From 657bdb826ac7a1d017ee150dc2550f6e47f31d7d Mon Sep 17 00:00:00 2001 From: enkore Date: Sat, 9 Mar 2013 21:23:36 +0100 Subject: [PATCH] Add preliminary(!) support for bidirectional communication with i3bar Novelty use only. --- i3pystatus/__init__.py | 12 ++++++++++++ i3pystatus/core/io.py | 15 +++++++++++---- i3pystatus/core/modules.py | 4 ++++ i3pystatus/core/util.py | 7 +++++++ i3pystatus/modsde.py | 4 ++++ i3pystatus/parcel.py | 7 +++++++ setup.py | 2 +- 7 files changed, 46 insertions(+), 5 deletions(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index 8f740c9..052143d 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import sys +import threading from .core import util, io from .core.modules import * @@ -18,8 +19,12 @@ def main(): class Status: def __init__(self, standalone=False, interval=1, input_stream=sys.stdin): + self.standalone = standalone if standalone: self.io = io.StandaloneIO(interval) + self.ce_thread = threading.Thread(target=self.run_command_endpoint) + self.ce_thread.daemon = True + self.ce_thread.start() else: self.io = io.IOHandler(input_stream) @@ -31,6 +36,13 @@ class Status: if module: self.modules.append(module, *args, **kwargs) + def run_command_endpoint(self): + for j in io.JSONIO(io=io.IOHandler(sys.stdin, io.DevNull()), skiplines=1).read(): + if j["command"] == "block_clicked": + module = self.modules.get_by_id(j["instance"]) + if module: + module.on_click() + def run(self): for j in io.JSONIO(self.io).read(): for module in self.modules: diff --git a/i3pystatus/core/io.py b/i3pystatus/core/io.py index f45af2c..9e32c46 100644 --- a/i3pystatus/core/io.py +++ b/i3pystatus/core/io.py @@ -2,7 +2,13 @@ import time import json import sys +import threading from contextlib import contextmanager +import io + +class DevNull(io.TextIOBase): + def write(self, string): + pass class IOHandler: def __init__(self, inp=sys.stdin, out=sys.stdout): @@ -50,7 +56,7 @@ class StandaloneIO(IOHandler): """ n = -1 - proto = ('{"version":1}', "[", "[]", ",[]", ) + proto = ('{"version":1,"bidirectional":1}', "[", "[]", ",[]", ) def __init__(self, interval=1): super().__init__() @@ -62,6 +68,7 @@ class StandaloneIO(IOHandler): time.sleep(self.interval) except KeyboardInterrupt: return + yield self.read_line() def read_line(self): @@ -70,10 +77,10 @@ class StandaloneIO(IOHandler): return self.proto[min(self.n, len(self.proto)-1)] class JSONIO: - def __init__(self, io): + def __init__(self, io, skiplines=2): self.io = io - self.io.write_line(self.io.read_line()) - self.io.write_line(self.io.read_line()) + for i in range(skiplines): + self.io.write_line(self.io.read_line()) def read(self): """Iterate over all JSON input (Generator)""" diff --git a/i3pystatus/core/modules.py b/i3pystatus/core/modules.py index a74da20..41a9b8e 100644 --- a/i3pystatus/core/modules.py +++ b/i3pystatus/core/modules.py @@ -18,8 +18,12 @@ class Module(SettingsBase): if self.output: if "name" not in self.output: self.output["name"] = self.__name__ + self.output["instance"] = str(id(self)) json.insert(0, self.output) + def on_click(self): + pass + def __repr__(self): return self.__class__.__name__ diff --git a/i3pystatus/core/util.py b/i3pystatus/core/util.py index 965dde2..4195ee3 100644 --- a/i3pystatus/core/util.py +++ b/i3pystatus/core/util.py @@ -51,6 +51,13 @@ class ModuleList(collections.UserList): module.registered(self.status_handler) super().append(module) + def get_by_id(self, find_id): + find_id = int(find_id) + for module in self: + if int(id(module)) == find_id: + return module + return None + class PrefixedKeyDict(collections.UserDict): def __init__(self, prefix): super().__init__() diff --git a/i3pystatus/modsde.py b/i3pystatus/modsde.py index f5c31d4..04b6410 100644 --- a/i3pystatus/modsde.py +++ b/i3pystatus/modsde.py @@ -8,6 +8,7 @@ import urllib.request, urllib.parse, urllib.error import re import http.cookiejar import xml.etree.ElementTree as ET +import webbrowser from i3pystatus import IntervalModule @@ -85,3 +86,6 @@ class ModsDeChecker(IntervalModule): self.logged_in = True self.opener.addheaders.append(("Cookie", "{}={}".format(cookie.name, cookie.value))) return True + + def on_click(self): + webbrowser.open_new_tab("http://forum.mods.de/bb/") \ No newline at end of file diff --git a/i3pystatus/parcel.py b/i3pystatus/parcel.py index fa0779e..15509b9 100644 --- a/i3pystatus/parcel.py +++ b/i3pystatus/parcel.py @@ -1,5 +1,6 @@ from urllib.request import urlopen +import webbrowser import lxml.html from lxml.cssselect import CSSSelector @@ -37,6 +38,9 @@ class DHL(TrackerAPI): ret["status"] = self.intrarow_status_selector(last_row)[0].text.strip() return ret + def get_url(self): + return self.url + class ParcelTracker(IntervalModule): interval = 20 @@ -59,3 +63,6 @@ class ParcelTracker(IntervalModule): "full_text": self.format.format(**fdict).strip(), "instance": self.name, } + + def on_click(self): + webbrowser.open_new_tab(self.instance.get_url()) diff --git a/setup.py b/setup.py index 0cda9bb..862ad8b 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup setup(name="i3pystatus", - version="3.8.2", + version="3.9", description="Like i3status, this generates status line for i3bar / i3wm", url="http://github.com/enkore/i3pystatus", license="MIT",