def run(self): """ Spawn i3status using a self generated config file and poll its output. """ try: with NamedTemporaryFile(prefix='py3status_') as tmpfile: self.write_tmp_i3status_config(tmpfile) syslog( LOG_INFO, 'i3status spawned using config file {}'.format( tmpfile.name)) i3status_pipe = Popen( ['i3status', '-c', tmpfile.name], stdout=PIPE, stderr=PIPE, ) self.poller_inp = IOPoller(i3status_pipe.stdout) self.poller_err = IOPoller(i3status_pipe.stderr) self.tmpfile_path = tmpfile.name try: # loop on i3status output while self.lock.is_set(): line = self.poller_inp.readline() if line: if line.startswith('[{'): print_line(line) with jsonify(line) as (prefix, json_list): self.last_output = json_list self.last_prefix = ',' self.set_responses(json_list) self.ready = True elif not line.startswith(','): if 'version' in line: header = loads(line) header.update({'click_events': True}) line = dumps(header) print_line(line) else: with jsonify(line) as (prefix, json_list): self.last_output = json_list self.last_prefix = prefix self.set_responses(json_list) else: err = self.poller_err.readline() code = i3status_pipe.poll() if code is not None: msg = 'i3status died' if err: msg += ' and said: {}'.format(err) else: msg += ' with code {}'.format(code) raise IOError(msg) except IOError: err = sys.exc_info()[1] self.error = err except OSError: # we cleanup the tmpfile ourselves so when the delete will occur # it will usually raise an OSError: No such file or directory pass
def run(self): """ Spawn i3status using a self generated config file and poll its output. """ try: with NamedTemporaryFile(prefix='py3status_') as tmpfile: self.write_tmp_i3status_config(tmpfile) syslog(LOG_INFO, 'i3status spawned using config file {}'.format( tmpfile.name)) i3status_pipe = Popen( ['i3status', '-c', tmpfile.name], stdout=PIPE, stderr=PIPE, ) self.poller_inp = IOPoller(i3status_pipe.stdout) self.poller_err = IOPoller(i3status_pipe.stderr) self.tmpfile_path = tmpfile.name try: # loop on i3status output while self.lock.is_set(): line = self.poller_inp.readline() if line: if line.startswith('[{'): print_line(line) with jsonify(line) as (prefix, json_list): self.last_output = json_list self.last_prefix = ',' self.set_responses(json_list) self.ready = True elif not line.startswith(','): if 'version' in line: header = loads(line) header.update({'click_events': True}) line = dumps(header) print_line(line) else: with jsonify(line) as (prefix, json_list): self.last_output = json_list self.last_prefix = prefix self.set_responses(json_list) else: err = self.poller_err.readline() code = i3status_pipe.poll() if code is not None: msg = 'i3status died' if err: msg += ' and said: {}'.format(err) else: msg += ' with code {}'.format(code) raise IOError(msg) except IOError: err = sys.exc_info()[1] self.error = err except OSError: # we cleanup the tmpfile ourselves so when the delete will occur # it will usually raise an OSError: No such file or directory pass
def mock(self): """ Mock i3status behavior, used in standalone mode. """ # mock thread is_alive() method self.is_alive = lambda: True # mock i3status base output init_output = ['{"click_events": true, "version": 1}', '[', '[]'] for line in init_output: print_line(line) # mock i3status output parsing self.last_output = [] self.last_prefix = ',' self.update_json_list()
def run(self): """ Main py3status loop, continuously read from i3status and modules and output it to i3bar for displaying. """ # SIGUSR1 forces a refresh of the bar both for py3status and i3status, # this mimics the USR1 signal handling of i3status (see man i3status) signal(SIGUSR1, self.sig_handler) signal(SIGTERM, self.terminate) # initialize usage variables i3status_thread = self.i3status_thread py3_config = self.config['py3_config'] # prepare the color mappings self.create_mappings(py3_config) # self.output_modules needs to have been created before modules are # started. This is so that modules can do things like register their # content_function. self.create_output_modules() # Some modules need to be prepared before they can run # eg run their post_config_hook for module in self.modules.values(): module.prepare_module() # modules can now receive updates self.py3_modules_initialized = True # start modules for module in self.modules.values(): module.start_module() # this will be our output set to the correct length for the number of # items in the bar output = [None] * len(py3_config['order']) interval = self.config['interval'] last_sec = 0 # start our output header = { 'version': 1, 'click_events': True, 'stop_signal': SIGTSTP } print_line(dumps(header)) print_line('[[]') # main loop while True: # sleep a bit to avoid killing the CPU # by doing this at the begining rather than the end # of the loop we ensure a smoother first render of the i3bar time.sleep(0.1) while not self.i3bar_running: time.sleep(0.1) sec = int(time.time()) # only check everything is good each second if sec > last_sec: last_sec = sec # check i3status thread if not i3status_thread.is_alive(): err = i3status_thread.error if not err: err = 'I3status died horribly.' self.notify_user(err) # check events thread if not self.events_thread.is_alive(): # don't spam the user with i3-nagbar warnings if not hasattr(self.events_thread, 'nagged'): self.events_thread.nagged = True err = 'Events thread died, click events are disabled.' self.notify_user(err, level='warning') # update i3status time/tztime items if interval == 0 or sec % interval == 0: i3status_thread.update_times() # check if an update is needed if self.queue: while (len(self.queue)): module_name = self.queue.popleft() module = self.output_modules[module_name] for index in module['position']: # store the output as json out = module['module'].get_latest() output[index] = self.process_module_output(out) # build output string out = ','.join([x for x in output if x]) # dump the line to stdout print_line(',[{}]'.format(out))
def run(self): """ Main py3status loop, continuously read from i3status and modules and output it to i3bar for displaying. """ # SIGUSR1 forces a refresh of the bar both for py3status and i3status, # this mimics the USR1 signal handling of i3status (see man i3status) signal(SIGUSR1, self.sig_handler) signal(SIGTERM, self.terminate) # initialize usage variables i3status_thread = self.i3status_thread config = i3status_thread.config self.create_output_modules() # update queue populate with all py3modules self.queue.extend(self.modules) # this will be our output set to the correct length for the number of # items in the bar output = [None] * len(config['order']) interval = self.config['interval'] last_sec = 0 # start our output header = { 'version': 1, 'click_events': True, 'stop_signal': SIGTSTP } print_line(dumps(header)) print_line('[[]') # main loop while True: while not self.i3bar_running: time.sleep(0.1) sec = int(time.time()) # only check everything is good each second if sec > last_sec: last_sec = sec # check i3status thread if not i3status_thread.is_alive(): err = i3status_thread.error if not err: err = 'I3status died horribly.' self.notify_user(err) # check events thread if not self.events_thread.is_alive(): # don't spam the user with i3-nagbar warnings if not hasattr(self.events_thread, 'nagged'): self.events_thread.nagged = True err = 'Events thread died, click events are disabled.' self.notify_user(err, level='warning') # update i3status time/tztime items if interval == 0 or sec % interval == 0: i3status_thread.update_times() # check if an update is needed if self.queue: while (len(self.queue)): module_name = self.queue.popleft() module = self.output_modules[module_name] for index in module['position']: # store the output as json # modules can have more than one output out = module['module'].get_latest() output[index] = ', '.join([dumps(x) for x in out]) # build output string out = ','.join([x for x in output if x]) # dump the line to stdout print_line(',[{}]'.format(out)) # sleep a bit before doing this again to avoid killing the CPU time.sleep(0.1)
def run(self): """ Main py3status loop, continuously read from i3status and modules and output it to i3bar for displaying. """ # SIGUSR1 forces a refresh of the bar both for py3status and i3status, # this mimics the USR1 signal handling of i3status (see man i3status) signal(SIGUSR1, self.sig_handler) signal(SIGTERM, self.terminate) # initialize usage variables i3status_thread = self.i3status_thread py3_config = self.config['py3_config'] # prepare the color mappings self.create_mappings(py3_config) # self.output_modules needs to have been created before modules are # started. This is so that modules can do things like register their # content_function. self.create_output_modules() # Some modules need to be prepared before they can run # eg run their post_config_hook for module in self.modules.values(): module.prepare_module() # modules can now receive updates self.py3_modules_initialized = True # start modules for module in self.modules.values(): module.start_module() # this will be our output set to the correct length for the number of # items in the bar output = [None] * len(py3_config['order']) interval = self.config['interval'] last_sec = 0 # start our output header = {'version': 1, 'click_events': True, 'stop_signal': SIGTSTP} print_line(dumps(header)) print_line('[[]') # main loop while True: # sleep a bit to avoid killing the CPU # by doing this at the begining rather than the end # of the loop we ensure a smoother first render of the i3bar time.sleep(0.1) while not self.i3bar_running: time.sleep(0.1) sec = int(time.time()) # only check everything is good each second if sec > last_sec: last_sec = sec # check i3status thread if not i3status_thread.is_alive(): err = i3status_thread.error if not err: err = 'I3status died horribly.' self.notify_user(err) # check events thread if not self.events_thread.is_alive(): # don't spam the user with i3-nagbar warnings if not hasattr(self.events_thread, 'nagged'): self.events_thread.nagged = True err = 'Events thread died, click events are disabled.' self.notify_user(err, level='warning') # update i3status time/tztime items if interval == 0 or sec % interval == 0: i3status_thread.update_times() # check if an update is needed if self.queue: while (len(self.queue)): module_name = self.queue.popleft() module = self.output_modules[module_name] for index in module['position']: # store the output as json out = module['module'].get_latest() output[index] = self.process_module_output(out) # build output string out = ','.join([x for x in output if x]) # dump the line to stdout print_line(',[{}]'.format(out))
def run(self): """ Main py3status loop, continuously read from i3status and modules and output it to i3bar for displaying. """ # SIGUSR1 forces a refresh of the bar both for py3status and i3status, # this mimics the USR1 signal handling of i3status (see man i3status) signal(SIGUSR1, self.sig_handler) signal(SIGTERM, self.terminate) # initialize usage variables delta = 0 last_delta = -1 previous_json_list = [] # main loop while True: # check i3status thread if not self.i3status_thread.is_alive(): err = self.i3status_thread.error if not err: err = "i3status died horribly" self.i3_nagbar(err) break # check events thread if not self.events_thread.is_alive(): # don't spam the user with i3-nagbar warnings if not hasattr(self.events_thread, "i3_nagbar"): self.events_thread.i3_nagbar = True err = "events thread died, click events are disabled" self.i3_nagbar(err, level="warning") # get output from i3status prefix = self.i3status_thread.last_prefix json_list = deepcopy(self.i3status_thread.json_list) # transform time and tztime outputs from i3status # every configured interval seconds if ( self.config["interval"] <= 1 or int(delta) % self.config["interval"] == 0 and int(last_delta) != int(delta) ): delta = 0 last_delta = 0 json_list = self.i3status_thread.tick_time_modules(json_list, force=True) else: json_list = self.i3status_thread.tick_time_modules(json_list, force=False) # construct the global output if self.modules and self.py3_modules: # new style i3status configured ordering json_list = self.i3status_thread.get_modules_output(json_list, self.modules) # dump the line to stdout only on change if json_list != previous_json_list: print_line("{}{}".format(prefix, dumps(json_list))) # remember the last json list output previous_json_list = deepcopy(json_list) # reset i3status json_list and json_list_ts self.i3status_thread.update_json_list() # sleep a bit before doing this again to avoid killing the CPU delta += 0.1 sleep(0.1)