def main_window(self): user_config_path = None if not user_config_dir_exists(): user_config_path = make_user_config_dir() else: user_config_path = get_user_config_path() script_hooks_enabled = True if user_config_path is None: logging.warn('Failed to find or create scripts directory, proceeding without scripting support') script_hooks_enabled = False else: self.script_loader = ScriptHookLoader(user_config_path) # initiating the graphs self.graphs = OrderedDict() self.summaries = OrderedDict() # TODO: Update to find sensors automatically freq_source = FreqSource(is_admin) self.graphs[freq_source.get_source_name()] = StuiBarGraph(freq_source, 'freq light', 'freq dark', 'freq light smooth', 'freq dark smooth') self.summaries[freq_source.get_source_name()] = SummaryTextList(freq_source) util_source = UtilSource() self.graphs[util_source.get_source_name()] = StuiBarGraph(util_source, 'util light', 'util dark', 'util light smooth', 'util dark smooth') self.summaries[util_source.get_source_name()] = SummaryTextList(util_source) temp_source = TemperatureSource(self.custom_temp) if script_hooks_enabled: temp_source.add_edge_hook(self.script_loader.load_script(temp_source.__class__.__name__, 30000)) # Invoke threshold script every 30s while threshold is exceeded. alert_colors = ['high temp light', 'high temp dark', 'high temp light smooth', 'high temp dark smooth'] self.graphs[temp_source.get_source_name()] = StuiBarGraph(temp_source, 'temp light', 'temp dark', 'temp light smooth', 'temp dark smooth', alert_colors=alert_colors) self.summaries[temp_source.get_source_name()] = SummaryTextList(temp_source, 'high temp txt') rapl_power_source = RaplPowerSource() self.graphs[rapl_power_source.get_source_name()] = StuiBarGraph(rapl_power_source, 'power dark', 'power light', 'power dark smooth', 'power light smooth') self.summaries[rapl_power_source.get_source_name()] = SummaryTextList(rapl_power_source) fan_source = FanSource(self.custom_fan) self.summaries[fan_source.get_source_name()] = SummaryTextList(fan_source) # only interested in available graph self.available_graphs = OrderedDict((key, val) for key, val in self.graphs.items() if val.get_is_available()) self.available_summaries = OrderedDict((key, val) for key, val in self.summaries.items() if val.get_is_available()) self.visible_graphs = self.available_graphs.copy() self.show_graphs() cpu_stats = self.cpu_stats() graph_controls = self.graph_controls() graph_stats = self.graph_stats() text_col = ViListBox(urwid.SimpleListWalker(cpu_stats + graph_controls + [urwid.Divider()] + graph_stats)) vline = urwid.AttrWrap(urwid.SolidFill(u'\u2502'), 'line') w = urwid.Columns([ ('fixed', 20, text_col), ('fixed', 1, vline), ('weight', 2, self.graph_place_holder), ], dividechars=1, focus_column=0) w = urwid.Padding(w, ('fixed left', 1), ('fixed right', 0)) w = urwid.AttrWrap(w, 'body') w = urwid.LineBox(w) w = urwid.AttrWrap(w, 'line') self.main_window_w = w return self.main_window_w
def __init__(self, args): # Load and configure user config dir when controller starts if not user_config_dir_exists(): user_config_dir = make_user_config_dir() else: user_config_dir = get_user_config_dir() self.script_hooks_enabled = True if user_config_dir is None: logging.warning("Failed to find or create scripts directory,\ proceeding without scripting support") self.script_hooks_enabled = False else: self.script_loader = ScriptHookLoader(user_config_dir) # Use user config file if one was saved before self.conf = None if user_config_file_exists(): self.conf = configparser.ConfigParser() self.conf.read(get_user_config_file()) else: logging.debug("Config file not found") # Set refresh rate accorrding to user config self.refresh_rate = '2.0' try: self.refresh_rate = str(self.conf.getfloat( 'GraphControll', 'refresh')) logging.debug("User refresh rate: " + str(self.refresh_rate)) except (AttributeError, ValueError, configparser.NoOptionError, configparser.NoSectionError): logging.debug("No refresh rate configed") # Set initial smooth graph state according to user config self.smooth_graph_mode = False try: if self.conf.getboolean('GraphControll', 'UTF8'): self.smooth_graph_mode = True else: logging.debug("UTF8 selected as " + self.conf.get('GraphControll', 'UTF8')) except (AttributeError, ValueError, configparser.NoOptionError, configparser.NoSectionError): logging.debug("No user config for utf8") self.temp_thresh = args.t_thresh # Try to load high temperature threshold if configured if args.t_thresh is None: try: self.temp_thresh = self.conf.get('TempControll', 'threshold') logging.debug("Temperature threshold set to " + str(self.temp_thresh)) except (AttributeError, ValueError, configparser.NoOptionError, configparser.NoSectionError): logging.debug("No user config for temp threshold") # Needed for use in view self.args = args self.animate_alarm = None self.terminal = args.terminal self.json = args.json self.mode = GraphMode() self.handle_mouse = not args.no_mouse self.stress_start_time = 0 self.stress_time = 0 self.view = GraphView(self) # use the first mode (no stress) as the default mode = self.get_modes()[0] self.mode.set_mode(mode) # update the view self.view.on_mode_change(mode) self.view.update_displayed_information() # Update csv file to save self.csv_file = None self.save_csv = args.csv if args.csv_file is not None: self.csv_file = args.csv_file logging.info("Printing output to csv " + self.csv_file) elif args.csv_file is None and args.csv: self.csv_file = DEFAULT_CSV_FILE
class GraphView(urwid.WidgetPlaceholder): """ A class responsible for providing the application's interface and graph display. """ def __init__(self, controller, args): self.controller = controller self.custom_temp = args.custom_temp self.custom_fan = args.custom_fan self.args = args self.hline = urwid.AttrWrap(urwid.SolidFill(u'_'), 'line') self.mode_buttons = [] self.refresh_rate_ctrl = urwid.Edit(('bold text', u'Refresh[s]:'), self.controller.refresh_rate) self.visible_graphs = {} self.graph_place_holder = urwid.WidgetPlaceholder(urwid.Pile([])) self.main_window_w = [] self.stress_menu = StressMenu(self.on_menu_close) self.help_menu = HelpMenu(self.on_menu_close) self.about_menu = AboutMenu(self.on_menu_close) self.temp_sensors_menu = TempSensorsMenu(self.on_sensors_menu_close) self.global_data = GlobalData(is_admin) self.stress_menu.sqrt_workers = str(self.global_data.num_cpus) self.left_margin = 0 self.top_margin = 0 self.v_relative = 50 self.h_relative = 50 urwid.WidgetPlaceholder.__init__(self, self.main_window()) urwid.connect_signal(self.refresh_rate_ctrl, 'change', self.update_refresh_rate) def update_refresh_rate(self, edit, new_refresh_rate): try: if float(new_refresh_rate) <= 0.001: pass else: self.controller.refresh_rate = new_refresh_rate except: self.controller.refresh_rate = '1.0' def update_displayed_information(self): """ Update all the graphs that are being displayed """ for key,val in self.summaries.items(): val.source.update() for g in self.visible_graphs.values(): g.update_displayed_graph_data() for s in self.available_summaries.values(): s.update() def on_reset_button(self, w): """Reset graph data and display empty graph""" for g in self.visible_graphs.values(): g.reset() for g in self.graphs.values(): try: g.source.reset() except NotImplementedError: pass self.update_displayed_information() def on_menu_close(self): """Return to main screen""" self.original_widget = self.main_window_w def on_sensors_menu_close(self): """Return to main screen and update sensor""" if self.temp_sensors_menu.current_active_mode: logging.info("State is not None") self.args.custom_temp = self.temp_sensors_menu.current_active_mode self.__init__(self.controller, self.args) logging.info("Temp sensor updated to " + self.args.custom_temp) else: logging.info("Temp sensor is None") self.original_widget = self.main_window_w def on_stress_menu_open(self, w): """Open stress options""" self.original_widget = urwid.Overlay(self.stress_menu.main_window, self.original_widget, ('relative', self.left_margin), self.stress_menu.get_size()[1], ('relative', self.top_margin), self.stress_menu.get_size()[0]) def on_help_menu_open(self, w): """Open Help menu""" self.original_widget = urwid.Overlay(self.help_menu.main_window, self.original_widget, ('relative', self.left_margin), self.help_menu.get_size()[1], ('relative', self.top_margin), self.help_menu.get_size()[0]) def on_about_menu_open(self, w): """Open About menu""" self.original_widget = urwid.Overlay(self.about_menu.main_window, self.original_widget, ('relative', self.left_margin), self.about_menu.get_size()[1], ('relative', self.top_margin), self.about_menu.get_size()[0]) def on_temp_sensors_menu_open(self, w): """Open About menu""" self.original_widget = urwid.Overlay(self.temp_sensors_menu.main_window, self.original_widget, ('relative', self.left_margin), self.temp_sensors_menu.get_size()[1], ('relative', self.top_margin), self.temp_sensors_menu.get_size()[0]) def on_mode_button(self, button, state): """Notify the controller of a new mode setting.""" if state: # The new mode is the label of the button self.controller.set_mode(button.get_label()) self.controller.start_stress() def on_mode_change(self, m): """Handle external mode change by updating radio buttons.""" for rb in self.mode_buttons: if rb.get_label() == m: rb.set_state(True, do_callback=False) break def on_unicode_checkbox(self, w, state): """Enable smooth edges if utf-8 is supported""" logging.debug("unicode State is " + str(state)) if state: self.hline = urwid.AttrWrap(urwid.SolidFill(u'\N{LOWER ONE QUARTER BLOCK}'), 'line') else: self.hline = urwid.AttrWrap(urwid.SolidFill(u'_'), 'line') for g_name,g in self.graphs.items(): g.set_smooth_colors(state) self.show_graphs() def exit_program(self, w=None): """ Kill all stress operations upon exit""" try: kill_child_processes(self.controller.mode.get_stress_process()) except: logging.debug('Could not kill process') raise urwid.ExitMainLoop() def graph_controls(self): """ Dislplay sidebar controls. i.e. buttons, and controls""" modes = self.controller.get_modes() # setup mode radio buttons group = [] for m in modes: rb = radio_button(group, m, self.on_mode_button) self.mode_buttons.append(rb) # Create list of buttons control_options = [button("Reset", self.on_reset_button)] if stress_installed: control_options.append(button('Stress Options', self.on_stress_menu_open)) control_options.append(button('Temp Sensors', self.on_temp_sensors_menu_open)) control_options.append(button('Help', self.on_help_menu_open)) control_options.append(button('About', self.on_about_menu_open)) # Create the menu animate_controls = urwid.GridFlow(control_options, 18, 2, 0, 'center') if urwid.get_encoding_mode() == "utf8": unicode_checkbox = urwid.CheckBox( "Smooth Graph", state=False, on_state_change=self.on_unicode_checkbox) else: unicode_checkbox = urwid.Text( "UTF-8 encoding not detected") install_stress_message = urwid.Text("") if not stress_installed: install_stress_message = urwid.Text(('button normal', u"(N/A) install stress")) graph_checkboxes = [urwid.CheckBox(x.get_graph_name(), state=True, on_state_change=lambda w, state, x=x: self.change_checkbox_state(x, state)) for x in self.available_graphs.values()] unavalable_graphs = [urwid.Text(( "[N/A] " + x.get_graph_name()) ) for x in self.graphs.values() if x.source.get_is_available() == False] graph_checkboxes += unavalable_graphs buttons = [urwid.Text(('bold text', u"Modes"), align="center"), ] + self.mode_buttons + [ install_stress_message, urwid.Divider(), urwid.Text(('bold text', u"Control Options"), align="center"), animate_controls, urwid.Divider(), self.refresh_rate_ctrl, urwid.Divider(), urwid.LineBox(urwid.Pile(graph_checkboxes)), urwid.LineBox(unicode_checkbox), urwid.Divider(), button("Quit", self.exit_program), ] return buttons def change_checkbox_state(self, x, state): if state: self.visible_graphs[x.get_graph_name()] = x else: del self.visible_graphs[x.get_graph_name()] self.show_graphs() def show_graphs(self): """Show a pile of the graph selected for dislpay""" elements = itertools.chain.from_iterable(([graph, ('fixed', 1, self.hline)] for graph in self.visible_graphs.values())) self.graph_place_holder.original_widget = urwid.Pile(elements) def cpu_stats(self): """Read and display processor name """ cpu_name = urwid.Text("CPU Name N/A", align="center") try: cpu_name = urwid.Text(get_processor_name().strip(), align="center") except: logging.info("CPU name not available") cpu_stats = [cpu_name, urwid.Divider()] return cpu_stats def graph_stats(self): fixed_stats = [] for key, val in self.available_summaries.items(): fixed_stats += val.get_text_item_list() return fixed_stats def main_window(self): user_config_path = None if not user_config_dir_exists(): user_config_path = make_user_config_dir() else: user_config_path = get_user_config_path() script_hooks_enabled = True if user_config_path is None: logging.warn('Failed to find or create scripts directory, proceeding without scripting support') script_hooks_enabled = False else: self.script_loader = ScriptHookLoader(user_config_path) # initiating the graphs self.graphs = OrderedDict() self.summaries = OrderedDict() # TODO: Update to find sensors automatically freq_source = FreqSource(is_admin) self.graphs[freq_source.get_source_name()] = StuiBarGraph(freq_source, 'freq light', 'freq dark', 'freq light smooth', 'freq dark smooth') self.summaries[freq_source.get_source_name()] = SummaryTextList(freq_source) util_source = UtilSource() self.graphs[util_source.get_source_name()] = StuiBarGraph(util_source, 'util light', 'util dark', 'util light smooth', 'util dark smooth') self.summaries[util_source.get_source_name()] = SummaryTextList(util_source) temp_source = TemperatureSource(self.custom_temp) if script_hooks_enabled: temp_source.add_edge_hook(self.script_loader.load_script(temp_source.__class__.__name__, 30000)) # Invoke threshold script every 30s while threshold is exceeded. alert_colors = ['high temp light', 'high temp dark', 'high temp light smooth', 'high temp dark smooth'] self.graphs[temp_source.get_source_name()] = StuiBarGraph(temp_source, 'temp light', 'temp dark', 'temp light smooth', 'temp dark smooth', alert_colors=alert_colors) self.summaries[temp_source.get_source_name()] = SummaryTextList(temp_source, 'high temp txt') rapl_power_source = RaplPowerSource() self.graphs[rapl_power_source.get_source_name()] = StuiBarGraph(rapl_power_source, 'power dark', 'power light', 'power dark smooth', 'power light smooth') self.summaries[rapl_power_source.get_source_name()] = SummaryTextList(rapl_power_source) fan_source = FanSource(self.custom_fan) self.summaries[fan_source.get_source_name()] = SummaryTextList(fan_source) # only interested in available graph self.available_graphs = OrderedDict((key, val) for key, val in self.graphs.items() if val.get_is_available()) self.available_summaries = OrderedDict((key, val) for key, val in self.summaries.items() if val.get_is_available()) self.visible_graphs = self.available_graphs.copy() self.show_graphs() cpu_stats = self.cpu_stats() graph_controls = self.graph_controls() graph_stats = self.graph_stats() text_col = ViListBox(urwid.SimpleListWalker(cpu_stats + graph_controls + [urwid.Divider()] + graph_stats)) vline = urwid.AttrWrap(urwid.SolidFill(u'\u2502'), 'line') w = urwid.Columns([ ('fixed', 20, text_col), ('fixed', 1, vline), ('weight', 2, self.graph_place_holder), ], dividechars=1, focus_column=0) w = urwid.Padding(w, ('fixed left', 1), ('fixed right', 0)) w = urwid.AttrWrap(w, 'body') w = urwid.LineBox(w) w = urwid.AttrWrap(w, 'line') self.main_window_w = w return self.main_window_w