Source code for i3pystatus.redshift

import os
import signal
import threading
from subprocess import Popen, PIPE

from i3pystatus import IntervalModule, formatp


class RedshiftController(threading.Thread):

    def __init__(self, args=[]):
        """Initialize controller and start child process

        The parameter args is a list of command line arguments to pass on to
        the child process. The "-v" argument is automatically added."""

        threading.Thread.__init__(self)

        # Initialize state variables
        self._inhibited = False
        self._temperature = 0
        self._period = 'Unknown'
        self._location = (0.0, 0.0)
        self._brightness = 0.0
        self._pid = None

        cmd = ["redshift"] + args
        if "-v" not in cmd:
            cmd += ["-v"]

        env = os.environ.copy()
        env['LANG'] = env['LANGUAGE'] = env['LC_ALL'] = env['LC_MESSAGES'] = 'C'

        self._params = {
            "args": cmd,
            "env": env,
            "bufsize": 1,
            "stdout": PIPE,
            "universal_newlines": True,
        }

    def parse_output(self, line):
        """Convert output to key value pairs"""

        try:
            key, value = line.split(":")
            self.update_value(key.strip(), value.strip())
        except ValueError:
            pass

    def update_value(self, key, value):
        """Parse key value pairs to update their values"""

        if key == "Status":
            self._inhibited = value != "Enabled"
        elif key == "Color temperature":
            self._temperature = int(value.rstrip("K"), 10)
        elif key == "Period":
            self._period = value
        elif key == "Brightness":
            self._brightness = value
        elif key == "Location":
            location = []
            for x in value.split(", "):
                v, d = x.split(" ")
                location.append(float(v) * (1 if d in "NE" else -1))
            self._location = (location)

    @property
    def inhibited(self):
        """Current inhibition state"""
        return self._inhibited

    @property
    def temperature(self):
        """Current screen temperature"""
        return self._temperature

    @property
    def period(self):
        """Current period of day"""
        return self._period

    @property
    def location(self):
        """Current location"""
        return self._location

    @property
    def brightness(self):
        """Current brightness"""
        return self._brightness

    def set_inhibit(self, inhibit):
        """Set inhibition state"""
        if self._pid and inhibit != self._inhibited:
            os.kill(self._pid, signal.SIGUSR1)
            self._inhibited = inhibit

    def run(self):
        with Popen(**self._params) as proc:
            self._pid = proc.pid
            for line in proc.stdout:
                self.parse_output(line)
            proc.wait(10)


[docs]class Redshift(IntervalModule): """ Show status and control redshift - http://jonls.dk/redshift/. This module runs an instance of redshift by itself, since it needs to parse its output, so you should remove redshift/redshift-gtk from your i3 config before using this module. Requires `redshift` installed. .. rubric:: Available formatters * `{inhibit}` — show if redshift is currently On or Off (using `toggle_inhibit` callback) * `{latitude}` — location latitude * `{longitude}` — location longitude * `{period}` — current period (Day or Night) * `{temperature}` — current screen temperature in Kelvin scale (K) """ settings = ( ("color", "Text color"), ("error_color", "Text color when an error occurs"), "format", ("format_inhibit", "List of 2 strings for `{inhibit}`, the first is shown when Redshift is On and the second is shown when Off"), ("redshift_parameters", "List of parameters to pass to redshift binary"), ) color = "#ffffff" error_color = "#ff0000" format = "{inhibit} {temperature}K" format_inhibit = ["On", "Off"] on_leftclick = "toggle_inhibit" redshift_parameters = [] def init(self): self._controller = RedshiftController(self.redshift_parameters) self._controller.daemon = True self._controller.start() self.update_values() def update_values(self): self.inhibit = self._controller.inhibited self.period = self._controller.period self.temperature = self._controller.temperature self.latitude, self.longitude = self._controller.location self.brightness = self._controller.brightness
[docs] def toggle_inhibit(self): """Enable/disable redshift""" if self.inhibit: self._controller.set_inhibit(False) self.inhibit = False else: self._controller.set_inhibit(True) self.inhibit = True
def run(self): if self._controller.is_alive(): self.update_values() fdict = { "inhibit": self.format_inhibit[int(self.inhibit)], "period": self.period, "temperature": self.temperature, "latitude": self.latitude, "longitude": self.longitude, "brightness": self.brightness, } output = formatp(self.format, **fdict) color = self.color else: output = "redshift exited unexpectedly" color = self.error_color self.output = { "full_text": output, "color": color, }