Add Reopen option to the menu.
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 29 Jul 2011 11:26:39 +0000 (12:26 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 29 Jul 2011 11:26:39 +0000 (12:26 +0100)
There's a small problem here which is that we lose the original guest
name.  We need to store it somewhere, although it's not clear which
component should be storing it (probably the Window).

main.ml
slave.ml
slave.mli
window.ml
window.mli

diff --git a/main.ml b/main.ml
index 439033d..92327c3 100644 (file)
--- a/main.ml
+++ b/main.ml
@@ -77,6 +77,7 @@ let () =
             ~callback:(w#connect_to (Some "xen:///")));
   ignore (w#connect_none_signal
             ~callback:(w#connect_to None));
+  ignore (w#reopen_signal ~callback:w#reopen);
   ignore (
     w#inspection_signal
       ~callback:(
index 034bbdf..975ab35 100644 (file)
--- a/slave.ml
+++ b/slave.ml
@@ -51,6 +51,7 @@ type command =
   | Open_domain of string * inspection_data callback
   | Open_images of (string * string option) list * inspection_data callback
   | Read_directory of source * string * direntry list callback
+  | Reopen of inspection_data callback
   | Run_command of string * unit callback
 
 let rec string_of_command = function
@@ -81,6 +82,8 @@ let rec string_of_command = function
       sprintf "Open_images %s" (string_of_images images)
   | Read_directory (src, dir, _) ->
       sprintf "Read_directory (%s, %s)" (string_of_source src) dir
+  | Reopen _ ->
+      "Reopen"
   | Run_command (cmd, _) ->
       sprintf "Run_command %s" cmd
 
@@ -174,6 +177,8 @@ let open_domain ?fail name cb = send_to_slave ?fail (Open_domain (name, cb))
 let open_images ?fail images cb = send_to_slave ?fail (Open_images (images, cb))
 let read_directory ?fail src path cb =
   send_to_slave ?fail (Read_directory (src, path, cb))
+let reopen ?fail cb =
+  send_to_slave ?fail (Reopen cb)
 let run_command ?fail cmd cb =
   send_to_slave ?fail (Run_command (cmd, cb))
 
@@ -188,6 +193,11 @@ let quit = ref false
 let conn = ref None
 let g = ref None
 
+(* Last Open_domain or Open_images command.  This is so we can implement
+ * the Reopen command.
+ *)
+let last_open = ref None
+
 (* Run the callback unless someone set the q_discard flag while
  * we were running the command.
  *)
@@ -356,19 +366,19 @@ and execute_command = function
       status "Finished listing applications";
       callback_if_not_discarded cb r
 
-  | Open_domain (name, cb) ->
+  | Open_domain (name, cb) as cmd ->
       status "Opening %s ..." name;
 
       let conn = get_conn () in
       let dom = D.lookup_by_name conn name in
       let xml = D.get_xml_desc dom in
       let images = get_disk_images_from_xml xml in
-      open_disk_images images cb
+      open_disk_images images cb cmd
 
-  | Open_images (images, cb) ->
+  | Open_images (images, cb) as cmd ->
       status "Opening disk images ...";
 
-      open_disk_images images cb
+      open_disk_images images cb cmd
 
   | Read_directory (src, dir, cb) ->
       status "Reading directory %s ..." dir;
@@ -395,6 +405,22 @@ and execute_command = function
       status "Finished reading directory %s" dir;
       callback_if_not_discarded cb entries
 
+  | Reopen cb ->
+      (* Execute the last_open command, if there was one.  But note
+       * that we have to replace the callback in the saved command with
+       * the new callback passed by the main thread to reopen.
+       *)
+      (match !last_open with
+       | Some (Open_domain (name, _)) ->
+           execute_command (Open_domain (name, cb))
+       | Some (Open_images (images, _)) ->
+           execute_command (Open_images (images, cb))
+       | None ->
+           () (* invalid_arg? *)
+       | _ ->
+           assert false (* should never happen *)
+      )
+
   | Run_command (cmd, cb) ->
       status "Running %s ..." cmd;
 
@@ -420,6 +446,7 @@ and get_g () =
 and close_all () =
   (match !conn with Some conn -> C.close conn | None -> ());
   conn := None;
+  last_open := None;
   close_g ()
 
 and close_g () =
@@ -487,7 +514,7 @@ and get_disk_images_from_xml xml =
 (* The common code for Open_domain and Open_images which opens the
  * libguestfs handle, adds the disks, and launches the appliance.
  *)
-and open_disk_images images cb =
+and open_disk_images images cb cmd =
   debug "opening disk image %s" (string_of_images images);
 
   close_g ();
@@ -628,6 +655,10 @@ and open_disk_images images cb =
   } in
 
   status "Finished opening disk";
+
+  (* Save the command, in case user does Reopen. *)
+  last_open := Some cmd;
+
   callback_if_not_discarded cb data
 
 (* Start up one slave thread. *)
index c1fdb04..5eaa9c9 100644 (file)
--- a/slave.mli
+++ b/slave.mli
@@ -154,6 +154,10 @@ val read_directory : ?fail:exn callback -> Slave_types.source -> string -> Slave
       If [fail] is passed, then failures cause this callback to
       be called.  If not, the global failure hook is called. *)
 
+val reopen : ?fail:exn callback -> Slave_types.inspection_data callback -> unit
+  (** [reopen cb] reruns the last {!open_domain} or {!open_images}
+      command, if there was one. *)
+
 val run_command : ?fail:exn callback -> string -> unit callback -> unit
   (** [run_command cmd] runs an external command [cmd].  This is
       useful for possibly long-running commands as it keeps the
index d9dd7a6..7f35b04 100644 (file)
--- a/window.ml
+++ b/window.ml
@@ -30,6 +30,7 @@ type connect_menu = {
   connect_none_item : GMenu.menu_item;
   connect_uri_item : GMenu.menu_item;
   open_disk_item : GMenu.menu_item;
+  reopen_item : GMenu.menu_item;
   quit_item : GMenu.menu_item;
 }
 
@@ -57,13 +58,15 @@ class window =
     let none = factory#add_item "_Connect to default hypervisor" in
     let uri = factory#add_item "Connect to a _libvirt URI ..." in
     ignore (factory#add_separator ());
-    let opend =
-      factory#add_item "_Open disk image ..." ~key:GdkKeysyms._O in
+    let opend = factory#add_item "_Open disk image ..." ~key:GdkKeysyms._O in
+    ignore (factory#add_separator ());
+    let reopen = factory#add_item "Reopen current guest" in
     ignore (factory#add_separator ());
     let quit = factory#add_item "E_xit" ~key:GdkKeysyms._Q in
     { connect_menu = menu; connect_kvm_item = kvm;
       connect_xen_item = xen; connect_none_item = none;
-      connect_uri_item = uri; open_disk_item = opend; quit_item = quit } in
+      connect_uri_item = uri;
+      open_disk_item = opend; reopen_item = reopen; quit_item = quit } in
 
   let guest_menu =
     let menu = factory#add_submenu "_Guest" in
@@ -115,6 +118,7 @@ class window =
   let connect_xen_signal = new GUtil.signal () in
   let connect_none_signal = new GUtil.signal () in
   let connect_uri_signal = new GUtil.signal () in
+  let reopen_signal = new GUtil.signal () in
   let inspection_signal = new GUtil.signal () in
 
 object (self)
@@ -122,12 +126,14 @@ object (self)
                             connect_xen_signal#disconnect;
                             connect_none_signal#disconnect;
                             connect_uri_signal#disconnect;
+                            reopen_signal#disconnect;
                             inspection_signal#disconnect]
 
   method connect_kvm_signal = connect_kvm_signal#connect ~after
   method connect_xen_signal = connect_xen_signal#connect ~after
   method connect_none_signal = connect_none_signal#connect ~after
   method connect_uri_signal = connect_uri_signal#connect ~after
+  method reopen_signal = reopen_signal#connect ~after
   method inspection_signal = inspection_signal#connect ~after
 
   initializer
@@ -153,6 +159,8 @@ object (self)
               ~callback:connect_none_signal#call);
     ignore (connect_menu.connect_uri_item#connect#activate
               ~callback:connect_uri_signal#call);
+    ignore (connect_menu.reopen_item#connect#activate
+              ~callback:reopen_signal#call);
     ignore (guest_menu.guest_inspection_item#connect#activate
               ~callback:inspection_signal#call);
 
@@ -235,6 +243,16 @@ object (self)
         debug "when_opened_disk_images callback";
         self#when_opened_common image data
 
+  (* Called to reopen the handle. *)
+  method reopen () =
+    tree#clear ();
+    Slave.discard_command_queue ();
+    Slave.reopen self#when_reopened
+
+  method private when_reopened data =
+    debug "when_reopened callback";
+    self#when_opened_common "Reopened"(*XXX we lost the original name*) data
+
   (* Common code for when_opened_domain/when_opened_disk_images. *)
   method private when_opened_common name data =
     (* Dump some of the inspection data in debug messages. *)
index d0c6c43..39994dc 100644 (file)
@@ -29,6 +29,7 @@ object ('a)
   method connect_xen_signal : callback:(unit -> unit) -> GtkSignal.id
   method connect_none_signal : callback:(unit -> unit) -> GtkSignal.id
   method connect_uri_signal : callback:(unit -> unit) -> GtkSignal.id
+  method reopen_signal : callback:(unit -> unit) -> GtkSignal.id
   method inspection_signal : callback:(unit -> unit) -> GtkSignal.id
 
   method failure : exn -> unit
@@ -56,6 +57,9 @@ object ('a)
   method connect_to : string option -> unit -> unit
     (** Connect to the given libvirt URI. *)
 
+  method reopen : unit -> unit
+    (** Reopen the libguestfs handle and current guest. *)
+
   method run_cli_request : Cmdline.cli_request -> unit
     (** This function performs the {!Cmdline.cli_request} operation.
         The actual operation happens asynchronously after this function