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