Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2 

3""" 

4import json 

5import logging 

6import os 

7import sys 

8import time 

9import warnings 

10 

11 

12LOG_FORMAT = '[%(asctime)s] %(threadName)-10s [%(levelname)-7s] %(message)s' 

13 

14 

15class Pi3Bar(object): 

16 """ 

17 Main thread. Manages all plugin instances. 

18 Collects output of them every second and writes it as json to stdout. 

19 

20 Example: 

21 

22 .. code-block:: python 

23 

24 #! /usr/bin/env python 

25 from pi3bar.app import Pi3Bar 

26 from pi3bar.plugins import * 

27 

28 

29 Pi3Bar( 

30 # <- 4 spaces! 

31 

32 # ... plugins 

33 

34 log_path='~/.pi3bar.log', # change the log file path if you want 

35 

36 ).run() # run pi3bar when executing this file 

37 """ 

38 def __init__(self, *register_plugins, **kwargs): 

39 log_level = kwargs.pop('log_level', logging.WARNING) 

40 try: 

41 main_file = sys.modules['__main__'].__file__ 

42 except AttributeError: 

43 default = os.path.join(os.path.expanduser('~'), '.pi3bar.log') 

44 else: 

45 default = os.path.join(os.path.dirname(main_file), 'status.log') 

46 log_path = kwargs.pop('log_path', default) 

47 

48 handler = logging.FileHandler(log_path) 

49 formatter = logging.Formatter(LOG_FORMAT) 

50 handler.setFormatter(formatter) 

51 

52 warnings.simplefilter('always', DeprecationWarning) 

53 logging.captureWarnings(True) 

54 self.logger = logging.getLogger() 

55 self.logger.addHandler(handler) 

56 self.logger.setLevel(log_level) 

57 

58 self.plugins = [] 

59 

60 from pi3bar.io import I3BarEventThread 

61 self.event_thread = I3BarEventThread(self.on_plugin_click, self.logger) 

62 self._register_plugins(register_plugins) 

63 

64 def _register_plugins(self, plugins): 

65 for plugin in plugins: 

66 if plugin in self.plugins: 

67 self.logger.error('Plugin %s already registered!' % plugin) 

68 continue 

69 

70 if plugin.instance is None: 

71 instance_count = sum([1 for p in self.plugins if p.name == plugin.name]) 

72 plugin.instance = str(instance_count) 

73 

74 plugin.logger = self.logger 

75 self.plugins.append(plugin) 

76 plugin.info('Registered') 

77 

78 def collect_output(self): 

79 """ 

80 Collect output of each plugin. 

81 Return json array string. 

82 """ 

83 output_list = [] 

84 plugins = self.plugins[:] 

85 

86 if not plugins: 

87 from pi3bar.plugins.utils import NoPlugins, Version 

88 # show version 

89 plugins.append(Version()) 

90 # and info that plugins is empty 

91 plugins.append(NoPlugins()) 

92 

93 for plugin in plugins: 

94 output = plugin.get_output() 

95 try: 

96 s = json.dumps(output) 

97 except TypeError: 

98 self.logger.error('TypeError in plugin %s:' % plugin, exc_info=1) 

99 s = json.dumps({ 

100 'name': plugin.name, 

101 'full_text': 'ERROR', 

102 'short_text': 'E', 

103 'background': '#ff0000' 

104 }) 

105 output_list.append(s) 

106 self.logger.debug('collect_output() [%s] %s' % (plugin, output)) 

107 

108 return ',[%s]' % ','.join(output_list) 

109 

110 def collect_write(self): 

111 """ 

112 Write output of all plugins to stdout. 

113 """ 

114 from pi3bar.io import write_sys 

115 write_sys(self.collect_output()) 

116 

117 def on_plugin_click(self, name, instance, button, x, y): 

118 """ 

119 Find registered plugin with given ``name`` and ``instance`` and call 

120 its :meth:`pi3bar.plugins.base.Plugin.on_click` method with ``button``, 

121 ``x`` and ``y``. 

122 """ 

123 for plugin in self.plugins: 

124 if plugin.name == name and plugin.instance == instance: 

125 try: 

126 plugin.on_click(button, x, y) 

127 except: 

128 # log instead of raise errors during plugin.on_click 

129 self.logger.error('Exception in %s.on_click:' % plugin, exc_info=1) 

130 return 

131 self.logger.error('Click by unregistered plugin "%s" instance "%s"' % (name, instance)) 

132 

133 def run(self): 

134 """ 

135 Run the main loop. 

136 """ 

137 from pi3bar.io import write_sys 

138 

139 write_sys('{ "version": 1, "click_events": true }') # header 

140 write_sys('[') # start infinite json array 

141 

142 # show version 

143 from pi3bar.plugins.utils import Version 

144 write_sys('[%s]' % json.dumps(Version().get_output())) # first item does not start with a comma! 

145 time.sleep(1) 

146 

147 self.event_thread.start() 

148 

149 for plugin in self.plugins: 

150 plugin.run() 

151 

152 while self.event_thread.CONTINUE: 

153 # run while event_thread is running. 

154 # It only closes gracefully when i3bar is closed. 

155 self.collect_write() 

156 time.sleep(1)