diff --git a/icons/restartvm.png b/icons/restartvm.png
new file mode 100644
index 0000000..2a84e90
Binary files /dev/null and b/icons/restartvm.png differ
diff --git a/mainwindow.ui b/mainwindow.ui
index 4c53adc..4cbc93c 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -320,6 +320,7 @@
+
@@ -369,6 +370,7 @@
+
@@ -455,6 +457,21 @@
Shutdown selected VM
+
+
+ false
+
+
+
+ :/restartvm.png:/restartvm.png
+
+
+ Restart VM
+
+
+ Restart selected VM
+
+
false
diff --git a/qubesmanager/main.py b/qubesmanager/main.py
index 3159e98..fb4e0ad 100755
--- a/qubesmanager/main.py
+++ b/qubesmanager/main.py
@@ -240,36 +240,48 @@ class VmRowInTable(object):
vm_shutdown_timeout = 20000 # in msec
+vm_restart_check_timeout= 1000 # in msec
class VmShutdownMonitor(QObject):
- def __init__(self, vm, shutdown_time=vm_shutdown_timeout):
+ def __init__(self, vm, shutdown_time=vm_shutdown_timeout, check_time=vm_restart_check_timeout, and_restart=False, caller=None):
QObject.__init__(self)
self.vm = vm
self.shutdown_time = shutdown_time
+ self.check_time = check_time
+ self.and_restart = and_restart
+ self.shutdown_started = datetime.now()
+ self.caller = caller
def check_if_vm_has_shutdown(self):
vm = self.vm
vm_start_time = vm.get_start_time()
- if not vm.is_running() or (
- vm_start_time and vm_start_time >= datetime.now() -
- timedelta(0, self.shutdown_time / 1000)):
- return
-
- reply = QMessageBox.question(
- None, "VM Shutdown",
- "The VM '{0}' hasn't shutdown within the last {1} seconds, "
- "do you want to kill it?
".format(
- vm.name, self.shutdown_time / 1000),
- "Kill it!",
- "Wait another {0} seconds...".format(
- self.shutdown_time / 1000))
- if reply == 0:
- vm.force_shutdown()
+ if vm.is_running() and vm_start_time and vm_start_time < self.shutdown_started:
+ if (datetime.now()-self.shutdown_started) > timedelta(milliseconds=self.shutdown_time):
+ reply = QMessageBox.question(
+ None, "VM Shutdown",
+ "The VM '{0}' hasn't shutdown within the last {1} seconds, "
+ "do you want to kill it?
".format(
+ vm.name, self.shutdown_time / 1000),
+ "Kill it!",
+ "Wait another {0} seconds...".format(
+ self.shutdown_time / 1000))
+ if reply == 0:
+ vm.force_shutdown()
+ if self.and_restart:
+ if self.caller:
+ self.caller.start_vm(vm)
+ else:
+ # noinspection PyTypeChecker,PyCallByClass
+ self.shutdown_started=datetime.now()
+ QTimer.singleShot(self.check_time, self.check_if_vm_has_shutdown)
+ else:
+ QTimer.singleShot(self.check_time, self.check_if_vm_has_shutdown)
else:
- # noinspection PyTypeChecker,PyCallByClass
- QTimer.singleShot(self.shutdown_time, self.check_if_vm_has_shutdown)
+ if self.and_restart:
+ if self.caller:
+ self.caller.start_vm(vm)
class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
row_height = 30
@@ -408,6 +420,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.context_menu.addAction(self.action_startvm_tools_install)
self.context_menu.addAction(self.action_pausevm)
self.context_menu.addAction(self.action_shutdownvm)
+ self.context_menu.addAction(self.action_restartvm)
self.context_menu.addAction(self.action_killvm)
self.context_menu.addSeparator()
@@ -879,6 +892,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
vm.last_running and
vm.last_power_state != "Paused" and
vm.qid != 0)
+ self.action_restartvm.setEnabled(
+ vm.last_running and
+ vm.last_power_state != "Paused" and
+ vm.qid != 0)
self.action_killvm.setEnabled((vm.last_running or
vm.last_power_state == "Paused") and
vm.qid != 0)
@@ -905,6 +922,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.action_resumevm.setEnabled(False)
self.action_pausevm.setEnabled(False)
self.action_shutdownvm.setEnabled(False)
+ self.action_restartvm.setEnabled(False)
self.action_killvm.setEnabled(False)
self.action_appmenus.setEnabled(False)
self.action_editfwrules.setEnabled(False)
@@ -1129,6 +1147,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
"ERROR: {0}".format(ex))
return
+
+ self.start_vm(vm)
+
+ def start_vm(self, vm):
assert not vm.is_running()
thread_monitor = ThreadMonitor()
thread = threading.Thread(target=self.do_start_vm,
@@ -1238,7 +1260,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
if reply == QMessageBox.Yes:
self.shutdown_vm(vm)
- def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout):
+ def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout, check_time=vm_restart_check_timeout, and_restart=False):
try:
vm.shutdown()
except Exception as ex:
@@ -1249,11 +1271,31 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
trayIcon.showMessage("VM '{0}' is shutting down...".format(vm.name),
msecs=3000)
- self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time)
+ self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time, check_time, and_restart, self)
# noinspection PyCallByClass,PyTypeChecker
- QTimer.singleShot(shutdown_time, self.shutdown_monitor[
+ QTimer.singleShot(check_time, self.shutdown_monitor[
vm.qid].check_if_vm_has_shutdown)
+
+ @pyqtSlot(name='on_action_restartvm_triggered')
+ def action_restartvm_triggered(self):
+ vm = self.get_selected_vm()
+ assert vm.is_running()
+
+ self.blk_manager.check_if_serves_as_backend(vm)
+
+ reply = QMessageBox.question(
+ None, "VM Restart Confirmation",
+ "Are you sure you want to restart the VM '{0}'?
"
+ "This will shutdown all the running applications "
+ "within this VM.".format(vm.name),
+ QMessageBox.Yes | QMessageBox.Cancel)
+
+ app.processEvents()
+
+ if reply == QMessageBox.Yes:
+ self.shutdown_vm(vm, and_restart=True)
+
@pyqtSlot(name='on_action_killvm_triggered')
def action_killvm_triggered(self):
vm = self.get_selected_vm()
diff --git a/resources.qrc b/resources.qrc
index c9f9172..c499d27 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -48,5 +48,6 @@
icons/pausevm.png
icons/showcpuload.png
icons/mic.png
+ icons/restartvm.png