From 579381978e8192c0d0a2ae6b746d235c413714bb Mon Sep 17 00:00:00 2001 From: Tobias Witek Date: Tue, 1 Nov 2016 07:46:26 +0100 Subject: [PATCH] [output] Add support for click-events in i3 The i3 output now has a separate thread that continuously monitors stdin for incoming click events. The generic output class also has methods for registering callbacks (as commands). For now, by default, scroll events will be used to emulate the next/previous workspace. --- bumblebee/modules/disk.py | 3 +++ bumblebee/modules/nic.py | 3 +++ bumblebee/output.py | 28 ++++++++++++++++++++++++++++ bumblebee/outputs/i3.py | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/bumblebee/modules/disk.py b/bumblebee/modules/disk.py index 9f98f91..cbe0a36 100644 --- a/bumblebee/modules/disk.py +++ b/bumblebee/modules/disk.py @@ -25,6 +25,9 @@ class Module(bumblebee.module.Module): return "{} {}/{} ({:05.02f}%)".format(self._path, bumblebee.util.bytefmt(self._free), bumblebee.util.bytefmt(self._size), self._perc) + def instance(self): + return self._path + def warning(self): return self._perc < 20 diff --git a/bumblebee/modules/nic.py b/bumblebee/modules/nic.py index e93688f..fdca861 100644 --- a/bumblebee/modules/nic.py +++ b/bumblebee/modules/nic.py @@ -64,6 +64,9 @@ class Module(bumblebee.module.Module): def _istunnel(self, intf): return intf.startswith("tun") + def instance(self): + return self._intf + def state(self): t = "wireless" if self._iswlan(self._intf) else "wired" diff --git a/bumblebee/output.py b/bumblebee/output.py index e0d9348..c3b232b 100644 --- a/bumblebee/output.py +++ b/bumblebee/output.py @@ -2,6 +2,34 @@ class Output(object): def __init__(self, theme): self._theme = theme + self._callbacks = {} + + def add_callback(self, cmd, button, module=None, instance=None): + self._callbacks[( + button, + module, + instance + )] = cmd + + def callback(self, event): + cb = self._callbacks.get(( + event.get("button", -1), + event.get("name", None), + event.get("instance", None) + ), None) + if cb is not None: return cb + cb = self._callbacks.get(( + event.get("button", -1), + event.get("name", None), + None + ), None) + if cb is not None: return cb + cb = self._callbacks.get(( + event.get("button", -1), + None, + None + ), None) + return cb def theme(self): return self._theme diff --git a/bumblebee/outputs/i3.py b/bumblebee/outputs/i3.py index d2a37ee..5d77542 100644 --- a/bumblebee/outputs/i3.py +++ b/bumblebee/outputs/i3.py @@ -1,16 +1,44 @@ from __future__ import unicode_literals +import os +import sys import json +import shlex +import threading +import subprocess import bumblebee.output +def read_input(output): + while True: + line = sys.stdin.readline().strip(",").strip() + if line == "[": continue + if line == "]": break + + DEVNULL = open(os.devnull, 'wb') + + event = json.loads(line) + cb = output.callback(event) + if cb: + cb = cb.format( + name = event.get("name", ""), + instance = event.get("instance", ""), + button = event.get("button", -1) + ) + subprocess.call(shlex.split(cb), stdout=DEVNULL, stderr=DEVNULL) + class i3bar(bumblebee.output.Output): def __init__(self, theme): - super(i3bar, self).__init__(theme) self._data = [] + self.add_callback("i3-msg workspace prev", 4) + self.add_callback("i3-msg workspace next", 5) + + self._thread = threading.Thread(target=read_input, args=(self,)) + self._thread.start() + def start(self): - return json.dumps({ "version": 1 }) + "[" + return json.dumps({ "version": 1, "click_events": True }) + "[" def add(self, obj): theme = self.theme() @@ -21,6 +49,8 @@ class i3bar(bumblebee.output.Output): u"full_text": "{}{}{}".format(theme.prefix(obj), d, theme.suffix(obj)), "color": theme.color(obj), "background": theme.background(obj), + "name": obj.__module__.replace("bumblebee.modules.",""), + "instance": obj.instance() if hasattr(obj, "instance") else None, } if theme.urgent(obj) and obj.critical():