From 341d733e4d4cb46e509691461ef7ba344adebeaa Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Mon, 26 Mar 2012 11:48:49 +0200 Subject: [PATCH 1/6] Fixed resizing on add/remove columns. --- mainwindow.ui | 9 ++++++--- qubesmanager/main.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index 0ce6d49..f253073 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -11,7 +11,7 @@ - + 0 0 @@ -34,7 +34,7 @@ true - + 0 0 @@ -49,6 +49,9 @@ + + QLayout::SetDefaultConstraint + 0 @@ -58,7 +61,7 @@ - + 0 0 diff --git a/qubesmanager/main.py b/qubesmanager/main.py index 8cd02a5..b0a6957 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -528,7 +528,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, @@ -573,7 +573,6 @@ 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 @@ -624,7 +623,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): def show(self): super(VmManagerWindow, self).show() self.set_table_geom_height() - self.update_table_columns() + self.set_table_geom_width() def set_table_geom_height(self): minH = self.table.horizontalHeader().height() +\ @@ -634,10 +633,9 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): #or if you know what you're doing :) n = self.table.rowCount(); - maxH = minH - if n >= self.max_visible_rows: - minH += self.max_visible_rows*self.row_height + if n >= self.min_visible_rows: + minH += self.min_visible_rows*self.row_height maxH += n*self.row_height else: minH += n*self.row_height @@ -655,10 +653,12 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): maxH += mainwindow_to_add minH += mainwindow_to_add - self.setMaximumHeight(maxH) + desktop_height = app.desktop().availableGeometry().height() - 2*self.row_height + + self.setMaximumHeight(min(desktop_height, maxH)) self.setMinimumHeight(minH) - + def get_vms_list(self): self.qvm_collection.lock_db_for_reading() self.qvm_collection.load() @@ -733,8 +733,11 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state): self.fill_table() + self.set_table_geom_height() + self.set_table_geom_width() 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. self.table.sortItems(self.columns_indices["State"], self.sort_by_state) @@ -789,7 +792,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.counter += 1 QTimer.singleShot (self.update_interval, self.update_table) - def update_table_columns(self): + def set_table_geom_width(self): table_width = self.table.horizontalHeader().length() +\ self.table.verticalScrollBar().width() + \ @@ -797,7 +800,9 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.table.setFixedWidth( table_width ) self.centralwidget.setFixedWidth(table_width) - self.setFixedWidth(table_width) + # don't change the following two lines to setFixedWidth! + self.setMaximumWidth(table_width) + self.setMinimumWidth(table_width) def update_block_devices(self): res, msg = self.blk_manager.update() @@ -1216,30 +1221,30 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): 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_width() 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): From 2962e9bc81f3ff9f48da96b194325e999738c1b9 Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Tue, 27 Mar 2012 10:36:58 +0200 Subject: [PATCH 2/6] Fix to sorting by state after table reload. --- qubesmanager/main.py | 49 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/qubesmanager/main.py b/qubesmanager/main.py index b0a6957..8fa7b39 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) @@ -558,6 +567,11 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): 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.fill_table() self.move(cur_pos) @@ -574,10 +588,6 @@ 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) @@ -715,8 +725,7 @@ 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 @@ -731,17 +740,15 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): vm.last_power_state = state some_vms_have_changed_power_state = True + reload_table = self.reload_table if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state): self.fill_table() self.set_table_geom_height() self.set_table_geom_width() 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. + elif 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 @@ -784,8 +791,10 @@ 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: @@ -811,6 +820,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 @@ -823,13 +833,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 From 2e5be2b55dacf6df1d983ca87958ffed0a7bf433 Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Tue, 27 Mar 2012 10:59:44 +0200 Subject: [PATCH 3/6] Initial size equals default. --- mainwindow.ui | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index f253073..23a2fa7 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 713 - 600 + 769 + 385 @@ -60,12 +60,6 @@ - - - 0 - 0 - - 0 @@ -118,7 +112,7 @@ false - 4 + 10 false @@ -143,6 +137,12 @@ + + + + + + @@ -215,7 +215,7 @@ 0 0 - 713 + 769 23 From 3b87b9ba27f4c9a3561077775ea581689e1080c9 Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Tue, 27 Mar 2012 11:36:21 +0200 Subject: [PATCH 4/6] Added new on/off icons. --- icons/on-icon/off.png | Bin 0 -> 11201 bytes icons/on-icon/on.png | Bin 0 -> 13175 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 icons/on-icon/off.png create mode 100644 icons/on-icon/on.png diff --git a/icons/on-icon/off.png b/icons/on-icon/off.png new file mode 100644 index 0000000000000000000000000000000000000000..73c5d11fa852b78abd1245dfdfd1a2a86186a23d GIT binary patch literal 11201 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 literal 0 HcmV?d00001 diff --git a/icons/on-icon/on.png b/icons/on-icon/on.png new file mode 100644 index 0000000000000000000000000000000000000000..815d68ba6d476beae70752f827d5ad6dd7698d24 GIT binary patch literal 13175 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 literal 0 HcmV?d00001 From 0833f773a70da6b9b1487a199ed63c914cfca0fd Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Wed, 28 Mar 2012 12:45:31 +0200 Subject: [PATCH 5/6] Sizing. --- mainwindow.ui | 7 ++- qubesmanager/main.py | 140 +++++++++++++++++++++++++++---------------- 2 files changed, 95 insertions(+), 52 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index 23a2fa7..29b0e96 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -11,7 +11,7 @@ - + 0 0 @@ -88,7 +88,10 @@ 0 - Qt::ScrollBarAlwaysOn + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded true diff --git a/qubesmanager/main.py b/qubesmanager/main.py index 8fa7b39..e8fbf27 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -562,7 +562,6 @@ 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)) @@ -572,9 +571,15 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): 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) @@ -632,41 +637,69 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): def show(self): super(VmManagerWindow, self).show() - self.set_table_geom_height() - self.set_table_geom_width() + 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(); - maxH = minH - if n >= self.min_visible_rows: - minH += self.min_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) + 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 + + 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 + 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) - desktop_height = app.desktop().availableGeometry().height() - 2*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() - self.setMaximumHeight(min(desktop_height, maxH)) - self.setMinimumHeight(minH) + 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): @@ -731,6 +764,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): # 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 @@ -741,13 +775,19 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): some_vms_have_changed_power_state = True reload_table = self.reload_table - if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state): + + 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_height() - self.set_table_geom_width() + self.set_table_geom_size() update_devs=True - elif self.sort_by_state != None and some_vms_have_changed_power_state: + + 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 @@ -801,18 +841,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.counter += 1 QTimer.singleShot (self.update_interval, self.update_table) - def set_table_geom_width(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) - # don't change the following two lines to setFixedWidth! - self.setMaximumWidth(table_width) - self.setMinimumWidth(table_width) - + def update_block_devices(self): res, msg = self.blk_manager.update() if msg != None and len(msg) > 0: @@ -1185,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): @@ -1212,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: @@ -1221,7 +1250,7 @@ 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: @@ -1230,7 +1259,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): def showhide_column(self, col_num, show): self.table.setColumnHidden( col_num, not show) - self.set_table_geom_width() + self.set_table_geom_size() def on_actionState_toggled(self, checked): self.showhide_column( self.columns_indices['State'], checked) @@ -1448,6 +1477,17 @@ def toggle_manager(): manager_window.hide() else: manager_window.show() + while manager_window.frameSize().width() - manager_window.width() == 0: + app.processEvents() + time.sleep(0.05) + manager_window.frame_width = manager_window.frameSize().width() - manager_window.width() + manager_window.frame_height = manager_window.frameSize().height() - manager_window.height() + + print manager_window.frame_width, " x ", manager_window.frame_height + manager_window.frame_width += 50 # UGLY! a silly tweak that worksforme... + + manager_window.set_table_geom_size() + manager_window.update_table(True) def exit_app(): From b616a8f5360305ca578bdde4e14e84ef34369581 Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Wed, 28 Mar 2012 21:36:59 +0200 Subject: [PATCH 6/6] Sizing uses xprop to read frame size. --- qubesmanager/main.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/qubesmanager/main.py b/qubesmanager/main.py index e8fbf27..9b46970 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -1468,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() @@ -1477,18 +1500,13 @@ def toggle_manager(): manager_window.hide() else: manager_window.show() - while manager_window.frameSize().width() - manager_window.width() == 0: - app.processEvents() - time.sleep(0.05) - manager_window.frame_width = manager_window.frameSize().width() - manager_window.width() - manager_window.frame_height = manager_window.frameSize().height() - manager_window.height() + 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.frame_width += 50 # UGLY! a silly tweak that worksforme... - manager_window.set_table_geom_size() - manager_window.update_table(True) def exit_app(): notifier.stop()