diff --git a/icons/on-icon/off.png b/icons/on-icon/off.png
new file mode 100644
index 0000000..73c5d11
Binary files /dev/null and b/icons/on-icon/off.png differ
diff --git a/icons/on-icon/on.png b/icons/on-icon/on.png
new file mode 100644
index 0000000..815d68b
Binary files /dev/null and b/icons/on-icon/on.png differ
diff --git a/mainwindow.ui b/mainwindow.ui
index 0ce6d49..29b0e96 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -6,12 +6,12 @@
0
0
- 713
- 600
+ 769
+ 385
-
+
0
0
@@ -34,7 +34,7 @@
true
-
+
0
0
@@ -49,6 +49,9 @@
+
+ QLayout::SetDefaultConstraint
+
0
@@ -57,12 +60,6 @@
-
-
-
- 0
- 0
-
-
0
@@ -91,7 +88,10 @@
0
- Qt::ScrollBarAlwaysOn
+ Qt::ScrollBarAsNeeded
+
+
+ Qt::ScrollBarAsNeeded
true
@@ -115,7 +115,7 @@
false
- 4
+ 10
false
@@ -140,6 +140,12 @@
+
+
+
+
+
+
@@ -212,7 +218,7 @@
0
0
- 713
+ 769
23
diff --git a/qubesmanager/main.py b/qubesmanager/main.py
index 8cd02a5..9b46970 100755
--- a/qubesmanager/main.py
+++ b/qubesmanager/main.py
@@ -55,6 +55,10 @@ qubes_guid_path = '/usr/bin/qubes_guid'
update_suggestion_interval = 14 # 14 days
+power_order = Qt.DescendingOrder
+update_order = Qt.AscendingOrder
+
+
class QubesConfigFileWatcher(ProcessEvent):
def __init__ (self, update_func):
self.update_func = update_func
@@ -159,14 +163,19 @@ class VmInfoWidget (QWidget):
def __lt__(self, other):
self_val = self.upd_info_item.value
other_val = other.upd_info_item.value
- if self.tableWidget().sort_state_by_upd:
+ if self.tableWidget().horizontalHeader().sortIndicatorOrder() == update_order:
+ # the result will be sorted by upd, sorting order: Ascending
self_val += 1 if self.vm.is_running() else 0
other_val += 1 if other.vm.is_running() else 0
- return (self_val) > (other_val) #sort with Ascending Order
+ return (self_val) > (other_val)
+ elif self.tableWidget().horizontalHeader().sortIndicatorOrder() == power_order:
+ #the result will be sorted by power state, sorting order: Descending
+ self_val = -(self_val/10 + 10*(1 if self.vm.is_running() else 0))
+ other_val = -(other_val/10 + 10*(1 if other.vm.is_running() else 0))
+ return (self_val) > (other_val)
else:
- self_val = self_val/10 + 10*(1 if self.vm.is_running() else 0)
- other_val = other_val/10 + 10*(1 if other.vm.is_running() else 0)
- return (self_val) < (other_val) #sort with Descending order
+ #it would be strange if this happened
+ return
def __init__(self, vm, parent = None):
super (VmInfoWidget, self).__init__(parent)
@@ -528,7 +537,7 @@ class VmShutdownMonitor(QObject):
class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
row_height = 30
column_width = 200
- max_visible_rows = 7
+ min_visible_rows = 10
update_interval = 1000 # in msec
show_inactive_vms = True
columns_indices = { "Label": 0,
@@ -553,14 +562,24 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.table_selection_changed)
- cur_pos = self.pos()
self.table.setColumnWidth(0, self.column_width)
self.setSizeIncrement(QtCore.QSize(200, 30))
self.centralwidget.setSizeIncrement(QtCore.QSize(200, 30))
self.table.setSizeIncrement(QtCore.QSize(200, 30))
+
+ self.sort_by_mem = None
+ self.sort_by_cpu = None
+ self.sort_by_state = None
+
+ self.screen_number = -1
+ self.screen_changed = False
+
+ self.frame_width = 0
+ self.frame_height = 0
+
self.fill_table()
- self.move(cur_pos)
-
+ self.move(self.x(), 0)
+
self.table.setColumnHidden( self.columns_indices["NetVM"], True)
self.actionNetVM.setChecked(False)
self.table.setColumnHidden( self.columns_indices["CPU Graph"], True)
@@ -573,12 +592,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.table.horizontalHeader().setResizeMode(QHeaderView.Fixed)
-
self.table.sortItems(self.columns_indices["Label"], Qt.AscendingOrder)
- self.sort_by_mem = None
- self.sort_by_cpu = None
- self.sort_by_state = None
- self.table.sort_state_by_upd = True
self.context_menu = QMenu(self)
self.context_menu.addAction(self.action_settings)
@@ -623,42 +637,71 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
def show(self):
super(VmManagerWindow, self).show()
- self.set_table_geom_height()
- self.update_table_columns()
+ self.screen_number = app.desktop().screenNumber(self)
- def set_table_geom_height(self):
- minH = self.table.horizontalHeader().height() +\
- 2*self.table.frameWidth()
+ def set_table_geom_size(self):
- #All this sizing is kind of magic, so change it only if you have to
- #or if you know what you're doing :)
-
- n = self.table.rowCount();
+ desktop_width = app.desktop().availableGeometry(self).width() - self.frame_width # might be wrong...
+ desktop_height = app.desktop().availableGeometry(self).height() - self.frame_height # might be wrong...
+ desktop_height -= self.row_height #UGLY! to somehow ommit taskbar...
+
+ W = self.table.horizontalHeader().length() +\
+ self.table.verticalScrollBar().width() +\
+ 2*self.table.frameWidth() +1
- maxH = minH
- if n >= self.max_visible_rows:
- minH += self.max_visible_rows*self.row_height
- maxH += n*self.row_height
- else:
- minH += n*self.row_height
- maxH = minH
-
- self.centralwidget.setMinimumHeight(minH)
- self.centralwidget.setMaximumHeight(maxH)
+ H = self.table.horizontalHeader().height() +\
+ 2*self.table.frameWidth()
mainwindow_to_add = 0
+
+ available_space = desktop_height
if self.menubar.isVisible():
- mainwindow_to_add += self.menubar.height() + self.menubar.contentsMargins().top() + self.menubar.contentsMargins().bottom()
+ menubar_height = self.menubar.height() + self.menubar.contentsMargins().top() + self.menubar.contentsMargins().bottom()
+ available_space -= menubar_height
+ mainwindow_to_add += menubar_height
if self.toolbar.isVisible():
- mainwindow_to_add += self.toolbar.height() + self.toolbar.contentsMargins().top() + self.toolbar.contentsMargins().bottom()
-
- maxH += mainwindow_to_add
- minH += mainwindow_to_add
-
- self.setMaximumHeight(maxH)
- self.setMinimumHeight(minH)
+ toolbar_height = self.toolbar.height() + self.toolbar.contentsMargins().top() + self.toolbar.contentsMargins().bottom()
+ available_space -= toolbar_height
+ mainwindow_to_add += toolbar_height
+ if W >= desktop_width:
+ available_space -= self.table.horizontalScrollBar().height()
+ H += self.table.horizontalScrollBar().height()
+ default_rows = int(available_space/self.row_height)
+ n = self.table.rowCount();
+ if n > default_rows:
+ H += default_rows*self.row_height
+ self.table.verticalScrollBar().show()
+ else:
+ H += n*self.row_height
+ self.table.verticalScrollBar().hide()
+ W -= self.table.verticalScrollBar().width()
+
+ W = min(desktop_width, W)
+
+ self.centralwidget.setFixedHeight(H)
+
+ H += mainwindow_to_add
+
+ self.setMaximumHeight(H)
+ self.setMinimumHeight(H)
+
+ self.table.setFixedWidth(W)
+ self.centralwidget.setFixedWidth(W)
+ # don't change the following two lines to setFixedWidth!
+ self.setMaximumWidth(W)
+ self.setMinimumWidth(W)
+
+
+ def moveEvent(self, event):
+ super(VmManagerWindow, self).moveEvent(event)
+ screen_number = app.desktop().screenNumber(self)
+ if self.screen_number != screen_number:
+ self.screen_changed = True
+ self.screen_number = screen_number
+
+
def get_vms_list(self):
self.qvm_collection.lock_db_for_reading()
self.qvm_collection.load()
@@ -715,13 +758,13 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.vms_in_table = vms_in_table
self.reload_table = False
self.table.setSortingEnabled(True)
-
-
+
def mark_table_for_update(self):
self.reload_table = True
# When calling update_table() directly, always use out_of_schedule=True!
def update_table(self, out_of_schedule=False):
+
update_devs = self.update_block_devices() or out_of_schedule
if manager_window.isVisible():
some_vms_have_changed_power_state = False
@@ -731,14 +774,21 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
vm.last_power_state = state
some_vms_have_changed_power_state = True
- if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state):
+ reload_table = self.reload_table
+
+ if self.screen_changed == True:
+ reload_table = True
+ self.screen_changed = False
+
+
+ if reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state):
self.fill_table()
+ self.set_table_geom_size()
update_devs=True
- if self.sort_by_state != None and self.table.sort_state_by_upd and some_vms_have_changed_power_state:
- self.table.sort_state_by_upd = not self.table.sort_state_by_upd # sorter indicator changed will switch it...and we want it to remain unswtched.
+
+ if self.sort_by_state != None and some_vms_have_changed_power_state:
self.table.sortItems(self.columns_indices["State"], self.sort_by_state)
-
blk_visible = None
rows_with_blk = None
@@ -781,24 +831,17 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.table.sortItems(self.columns_indices["CPU"], self.sort_by_cpu)
elif self.sort_by_mem != None:
self.table.sortItems(self.columns_indices["MEM"], self.sort_by_mem)
+ elif self.sort_by_state != None and reload_table:
+ #needed to sort after reload (fill_table sorts items with setSortingEnabled, but by that time the widgets values are not correct yet).
+ self.table.sortItems(self.columns_indices["State"], self.sort_by_state)
-
self.table_selection_changed()
if not out_of_schedule:
self.counter += 1
QTimer.singleShot (self.update_interval, self.update_table)
- def update_table_columns(self):
-
- table_width = self.table.horizontalHeader().length() +\
- self.table.verticalScrollBar().width() + \
- 2*self.table.frameWidth() + 1
-
- self.table.setFixedWidth( table_width )
- self.centralwidget.setFixedWidth(table_width)
- self.setFixedWidth(table_width)
-
+
def update_block_devices(self):
res, msg = self.blk_manager.update()
if msg != None and len(msg) > 0:
@@ -806,6 +849,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
trayIcon.showMessage ("Qubes Manager", str, msecs=5000)
return res
+
def sortIndicatorChanged(self, column, order):
if column == self.columns_indices["CPU"] or column == self.columns_indices["CPU Graph"]:
self.sort_by_mem = None
@@ -818,13 +862,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.sort_by_mem = order
return
elif column == self.columns_indices["State"]:
- self.table.sort_state_by_upd = not self.table.sort_state_by_upd
+
self.sort_by_cpu = None
self.sort_by_mem = None
- if self.table.sort_state_by_upd:
- self.sort_by_state = Qt.DescendingOrder
- else:
- self.sort_by_state = Qt.AscendingOrder
+ self.sort_by_state = order
return
else:
self.sort_by_cpu = None
@@ -1173,7 +1214,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.show_inactive_vms = self.action_showallvms.isChecked()
self.mark_table_for_update()
self.update_table(out_of_schedule = True)
- self.set_table_geom_height()
+ self.set_table_geom_size()
@pyqtSlot(name='on_action_editfwrules_triggered')
def action_editfwrules_triggered(self):
@@ -1200,7 +1241,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
def showhide_menubar(self, checked):
self.menuWidget().setVisible(checked)
- self.set_table_geom_height()
+ self.set_table_geom_size()
if not checked:
self.context_menu.addAction(self.action_menubar)
else:
@@ -1209,37 +1250,37 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
def showhide_toolbar(self, checked):
self.toolbar.setVisible(checked)
- self.set_table_geom_height()
+ self.set_table_geom_size()
if not checked:
self.context_menu.addAction(self.action_toolbar)
else:
self.context_menu.removeAction(self.action_toolbar)
- def showhide_collumn(self, col_num, show):
+ def showhide_column(self, col_num, show):
self.table.setColumnHidden( col_num, not show)
- self.update_table_columns()
+ self.set_table_geom_size()
def on_actionState_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['State'], checked)
+ self.showhide_column( self.columns_indices['State'], checked)
def on_actionTemplate_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['Template'], checked)
+ self.showhide_column( self.columns_indices['Template'], checked)
def on_actionNetVM_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['NetVM'], checked)
+ self.showhide_column( self.columns_indices['NetVM'], checked)
def on_actionCPU_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['CPU'], checked)
+ self.showhide_column( self.columns_indices['CPU'], checked)
def on_actionCPU_Graph_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['CPU Graph'], checked)
+ self.showhide_column( self.columns_indices['CPU Graph'], checked)
def on_actionMEM_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['MEM'], checked)
+ self.showhide_column( self.columns_indices['MEM'], checked)
def on_actionMEM_Graph_toggled(self, checked):
- self.showhide_collumn( self.columns_indices['MEM Graph'], checked)
+ self.showhide_column( self.columns_indices['MEM Graph'], checked)
def createPopupMenu(self):
@@ -1427,6 +1468,29 @@ class QubesTrayIcon(QSystemTrayIcon):
action.setCheckable(True)
return action
+def get_frame_size():
+ w = 0
+ h = 0
+ cmd = ['xprop', '-name', 'Qubes VM Manager', '|', 'grep', '_NET_FRAME_EXTENTS']
+ xprop = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ for l in xprop.stdout:
+ line = l.split('=')
+ if len(line) == 2:
+ line = line[1].strip().split(',')
+ if len(line) == 4:
+ w = int(line[0].strip())+ int(line[1].strip())
+ h = int(line[2].strip())+ int(line[3].strip())
+ break;
+ #in case of some weird window managers we have to assume sth...
+ if w<= 0:
+ w = 10
+ if h <= 0:
+ h = 30
+
+ manager_window.frame_width = w
+ manager_window.frame_height = h
+ return
+
def show_manager():
manager_window.show()
@@ -1436,8 +1500,14 @@ def toggle_manager():
manager_window.hide()
else:
manager_window.show()
+ manager_window.set_table_geom_size()
manager_window.update_table(True)
+ get_frame_size()
+ print manager_window.frame_width, " x ", manager_window.frame_height
+ manager_window.set_table_geom_size()
+
+
def exit_app():
notifier.stop()
app.exit()