diff options
| author | Ultrabug <ultrabug@gentoo.org> | 2013-12-13 18:23:23 +0100 |
|---|---|---|
| committer | Ultrabug <ultrabug@gentoo.org> | 2013-12-13 18:23:23 +0100 |
| commit | 9ca0ee00a7cd12ce4a0ca7ea2b6ca8fcb55b47fa (patch) | |
| tree | a45bc8c3a5727fb14860baa1a7e7e4925074127a | |
| parent | 45872ecb1db0336531ea27605a7fd978583a46da (diff) | |
new generic click event handler using the special module file named i3bar_click_events.py which will be forwarded any orphan click event for action. this allows you to take action on clicks made on your i3status modules.
| -rw-r--r-- | examples/i3bar_click_events.py | 127 | ||||
| -rwxr-xr-x | py3status/__init__.py | 30 |
2 files changed, 157 insertions, 0 deletions
diff --git a/examples/i3bar_click_events.py b/examples/i3bar_click_events.py new file mode 100644 index 0000000..792965c --- /dev/null +++ b/examples/i3bar_click_events.py @@ -0,0 +1,127 @@ +from subprocess import Popen +from time import time + + +class Py3status: + """ + This module allows you to take actions based on click events made on + the i3status modules. For example, thanks to this module you could + launch the wicd GUI when clicking on the ethernet or wireless module + of your i3status output ! + + IMPORTANT: + This module file name is reserved and should NOT be changed if you + want py3status to handle your i3status modules click events ! + + The behavior described above will only work if this file is named + 'i3bar_click_events.py' ! + """ + def __init__(self): + """ + This is where you setup your actions based on your i3status config. + + Configuration: + -------------- + self.actions = { + "<module name and instance>": { + <button number>: [<function to run>, <arg1>, <arg2>], + } + } + + Variables: + ---------- + <button number> is an integer from 1 to 3: + 1 : left click + 2 : middle click + 3 : right click + + <function to run> is a python function written in this module. + The 'external_command' function is provided for convenience if + you want to call an external program from this module. + You can of course write your own functions and have them executed + on a click event at will with possible arguments <arg1>, <arg2>... + + <module name and instance> is a string made from the module + attribute 'name' and 'instance' using a space as separator: + For i3status modules, it's simply the name of the module as it + appears in the 'order' instruction of your i3status.conf. + Example: + in i3status.conf -> order += "wireless wlan0" + self.actions key -> "wireless wlan0" + + Usage example: + -------------- + - Open the wicd-gtk GUI when we LEFT click on the ethernet + module of i3status. + - Open emelfm2 to /home when we LEFT click on + the /home instance of disk_info + - Open emelfm2 to / when we LEFT click on + the / instance of disk_info + + The related i3status.conf looks like: + order += "disk /home" + order += "disk /" + order += "ethernet eth0" + + The resulting self.actions should be: + self.actions = { + "ethernet eth0": { + 1: [external_command, 'wicd-gtk', '-n'], + }, + "disk_info /home": { + 1: [external_command, 'emelfm2', '-1', '~'], + }, + "disk_info /": { + 1: [external_command, 'emelfm2', '-1', '/'], + }, + } + """ + # CONFIGURE ME PLEASE, LOVE YOU BIG TIME ! + self.actions = { + } + + def on_click(self, i3status_output_json, i3status_config, event): + """ + If an action is configured for the given i3status module 'name' and + 'instance' (if present), then we'll execute the given function with + its arguments (if present). + + Usually you SHOULD NOT modify this part of the code. + """ + button = event['button'] + key_name = '{} {}'.format( + event['name'], + event.get('instance', '') + ).strip() + if key_name in self.actions and button in self.actions[key_name]: + # get the function to run + func = self.actions[key_name][button][0] + assert hasattr(func, '__call__'), \ + 'first element of the action list must be a function' + + # run the function with the possibly given arguments + func(*self.actions[key_name][button][1:]) + + def i3bar_click_events(self, i3status_output_json, i3status_config): + """ + Cached empty output, this module doesn't show anything. + """ + response = {'full_text': '', 'name': 'i3bar_click_events'} + response['cached_until'] = time() + 3600 + return (-1, response) + + +def external_command(*cmd): + """ + This convenience function lets you call an external program at will. + + NOTE: + The stdout and stderr MUST be suppressed as shown here to avoid any + output from being caught by the i3bar (this would freeze it). + See issue #20 for more info. + """ + Popen( + cmd, + stdout=open('/dev/null', 'w'), + stderr=open('/dev/null', 'w') + ) diff --git a/py3status/__init__.py b/py3status/__init__.py index 0a182dd..cb24d39 100755 --- a/py3status/__init__.py +++ b/py3status/__init__.py @@ -252,6 +252,22 @@ class Events(Thread): if self.config['debug']: syslog(LOG_INFO, 'dispatching default event {}'.format(event)) + def i3bar_click_events_module(self): + """ + Detect the presence of the special i3bar_click_events.py module. + + When py3status detects a module named 'i3bar_click_events.py', + it will dispatch i3status click events to this module so you can catch + them and trigger any function call based on the event. + """ + for module in self.modules: + if not module.click_events: + continue + if module.module_name == 'i3bar_click_events.py': + return module + else: + return False + def run(self): """ Wait for an i3bar JSON event, then find the right module to dispatch @@ -276,6 +292,7 @@ class Events(Thread): # setup default action on button 2 press default_event = False + dispatched = False if 'button' in event and event['button'] == 2: default_event = True @@ -291,10 +308,23 @@ class Events(Thread): if 'instance' in event: if event['instance'] == obj['instance']: self.dispatch(module, obj, event) + dispatched = True break else: self.dispatch(module, obj, event) + dispatched = True break + + # fall back to i3bar_click_events.py module if present + if not dispatched: + module = self.i3bar_click_events_module() + if module: + if self.config['debug']: + syslog( + LOG_INFO, + 'dispatching event to i3bar_click_events' + ) + self.dispatch(module, obj, event) except Exception: err = sys.exc_info()[1] syslog(LOG_WARNING, 'event failed ({})'.format(err)) |
