Multiple changes including random wallpaper, theme colors and switching to yay instead of yaourt
This commit is contained in:
		
							parent
							
								
									b78b817a33
								
							
						
					
					
						commit
						5b7475e50f
					
				
					 7 changed files with 609 additions and 46 deletions
				
			
		| 
						 | 
				
			
			@ -1,11 +1,18 @@
 | 
			
		|||
import os
 | 
			
		||||
import re
 | 
			
		||||
import subprocess
 | 
			
		||||
from asyncio import Queue
 | 
			
		||||
from threading import Thread
 | 
			
		||||
from time import sleep
 | 
			
		||||
 | 
			
		||||
import cairocffi
 | 
			
		||||
import notify2
 | 
			
		||||
import numpy
 | 
			
		||||
import pyaudio
 | 
			
		||||
import six
 | 
			
		||||
from libqtile import widget, bar
 | 
			
		||||
from libqtile.widget.currentlayout import CurrentLayoutIcon
 | 
			
		||||
from libqtile.widget.graph import _Graph
 | 
			
		||||
from libqtile.window import Internal
 | 
			
		||||
from libqtile.bar import Bar
 | 
			
		||||
from libqtile.utils import catch_exception_and_warn, UnixCommandNotFound
 | 
			
		||||
| 
						 | 
				
			
			@ -38,12 +45,34 @@ def is_running(process):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def execute(process):
 | 
			
		||||
    return subprocess.Popen(process.split())
 | 
			
		||||
    if isinstance(process, list):
 | 
			
		||||
        return subprocess.Popen(process)
 | 
			
		||||
    elif isinstance(process, str):
 | 
			
		||||
        return subprocess.Popen(process.split())
 | 
			
		||||
    else:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def execute_once(process):
 | 
			
		||||
    if not is_running(process):
 | 
			
		||||
        return subprocess.Popen(process.split())
 | 
			
		||||
        if isinstance(process, list):
 | 
			
		||||
            return subprocess.Popen(process)
 | 
			
		||||
        elif isinstance(process, str):
 | 
			
		||||
            return subprocess.Popen(process.split())
 | 
			
		||||
        else:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def call_process(command, **kwargs):
 | 
			
		||||
    """
 | 
			
		||||
        This method uses `subprocess.check_output` to run the given command
 | 
			
		||||
        and return the string from stdout, which is decoded when using
 | 
			
		||||
        Python 3.
 | 
			
		||||
    """
 | 
			
		||||
    output = subprocess.check_output(command, **kwargs)
 | 
			
		||||
    if six.PY3:
 | 
			
		||||
        output = output.decode()
 | 
			
		||||
    return output
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_screen_count():
 | 
			
		||||
| 
						 | 
				
			
			@ -217,18 +246,18 @@ class AppLauncherIcon(Image):
 | 
			
		|||
        spawn_popup(self.qtile, self.offsetx, self.offsety, "Hovered over AppLauncherIcon!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CheckUpdatesYaourt(CheckUpdates):
 | 
			
		||||
class CheckUpdatesYay(CheckUpdates):
 | 
			
		||||
    def __init__(self, **config):
 | 
			
		||||
        super(CheckUpdatesYaourt, self).__init__(**config)
 | 
			
		||||
        # Override command and output with yaourt command
 | 
			
		||||
        self.cmd = "yaourt -Qua".split()
 | 
			
		||||
        self.status_cmd = "yaourt -Qua".split()
 | 
			
		||||
        self.update_cmd = "sudo yaourt -Sya".split()
 | 
			
		||||
        super(CheckUpdatesYay, self).__init__(**config)
 | 
			
		||||
        # Override command and output with yay command
 | 
			
		||||
        self.cmd = "yay -Qua".split()
 | 
			
		||||
        self.status_cmd = "yay -Qua --color never".split()
 | 
			
		||||
        self.update_cmd = "sudo yay".split()
 | 
			
		||||
        self.subtr = 0
 | 
			
		||||
 | 
			
		||||
    def _check_updates(self):
 | 
			
		||||
        #subprocess.check_output(self.update_cmd)
 | 
			
		||||
        res = super(CheckUpdatesYaourt, self)._check_updates()
 | 
			
		||||
        res = super(CheckUpdatesYay, self)._check_updates()
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    def button_press(self, x, y, button):
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +282,7 @@ class CheckUpdatesYaourt(CheckUpdates):
 | 
			
		|||
        elif button == BUTTON_MIDDLE and self.execute is not None:
 | 
			
		||||
            subprocess.Popen(self.execute, shell=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KuroBatteryIcon(BatteryIcon):
 | 
			
		||||
    status_cmd = "acpi"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -265,6 +295,7 @@ class KuroBatteryIcon(BatteryIcon):
 | 
			
		|||
                output
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PulseVolumeWidget(Volume):
 | 
			
		||||
 | 
			
		||||
    defaults = [
 | 
			
		||||
| 
						 | 
				
			
			@ -535,3 +566,255 @@ class ThermalSensorWidget(ThermalSensor):
 | 
			
		|||
            command.append("-f")
 | 
			
		||||
        sensors_out = self.call_process(command)
 | 
			
		||||
        return self._format_sensors_output(sensors_out)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SeparatorWidget(base._TextBox):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super(SeparatorWidget, self).__init__(text="|", width=bar.CALCULATED, fontsize=14)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MediaWidget(base.InLoopPollText):
 | 
			
		||||
    """Media Status Widget"""
 | 
			
		||||
 | 
			
		||||
    class Status:
 | 
			
		||||
        OFFLINE = 0
 | 
			
		||||
        PLAYING = 1
 | 
			
		||||
        PAUSED = 2
 | 
			
		||||
        STOPPED = 3
 | 
			
		||||
 | 
			
		||||
    orientations = base.ORIENTATION_HORIZONTAL
 | 
			
		||||
    defaults = [
 | 
			
		||||
        ('off_text', '', 'The pattern for the text if no players are found.'),
 | 
			
		||||
        ('on_text_play', ' {}', 'The pattern for the text if music is playing.'),
 | 
			
		||||
        ('on_text_pause', ' {}', 'The pattern for the text if music is paused.'),
 | 
			
		||||
        ('on_text_stop', ' {}', 'The pattern for the text if music is stopped.'),
 | 
			
		||||
        ('update_interval', 1, 'The update interval.'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    player_icons = {
 | 
			
		||||
        'spotify': '',
 | 
			
		||||
        'vlc': '',
 | 
			
		||||
        'firefox': '',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    custom_player_data = {
 | 
			
		||||
        'firefox': {
 | 
			
		||||
            'showing': False,
 | 
			
		||||
            'title': '',
 | 
			
		||||
            'state': Status.STOPPED,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def __init__(self, **config):
 | 
			
		||||
        super(MediaWidget, self).__init__(**config)
 | 
			
		||||
        self.add_defaults(MediaWidget.defaults)
 | 
			
		||||
        self.surfaces = {}
 | 
			
		||||
 | 
			
		||||
    def cmd_update_custom_player(self, player_name, data):
 | 
			
		||||
        # Update firefox player
 | 
			
		||||
        if player_name == "firefox":
 | 
			
		||||
            if data['playing'] and data['muted']:
 | 
			
		||||
                self.custom_player_data['firefox']['showing'] = True
 | 
			
		||||
                self.custom_player_data['firefox']['state'] = MediaWidget.Status.PAUSED
 | 
			
		||||
                self.custom_player_data['firefox']['title'] = data['title']
 | 
			
		||||
            elif data['playing'] and not data['muted']:
 | 
			
		||||
                self.custom_player_data['firefox']['showing'] = True
 | 
			
		||||
                self.custom_player_data['firefox']['state'] = MediaWidget.Status.PLAYING
 | 
			
		||||
                self.custom_player_data['firefox']['title'] = data['title']
 | 
			
		||||
            elif not data['playing'] and data['muted']:
 | 
			
		||||
                self.custom_player_data['firefox']['showing'] = True
 | 
			
		||||
                self.custom_player_data['firefox']['state'] = MediaWidget.Status.STOPPED
 | 
			
		||||
                self.custom_player_data['firefox']['title'] = data['title']
 | 
			
		||||
            elif not data['playing'] and not data['muted']:
 | 
			
		||||
                self.custom_player_data['firefox']['showing'] = False
 | 
			
		||||
                self.custom_player_data['firefox']['state'] = MediaWidget.Status.OFFLINE
 | 
			
		||||
                self.custom_player_data['firefox']['title'] = data['title']
 | 
			
		||||
 | 
			
		||||
    def _get_players(self):
 | 
			
		||||
        players = []
 | 
			
		||||
 | 
			
		||||
        # Playerctl players
 | 
			
		||||
        command = ["playerctl", "-l"]
 | 
			
		||||
        result = self.call_process(command)
 | 
			
		||||
        if result:
 | 
			
		||||
            players.extend([x for x in result.split("\n") if x])
 | 
			
		||||
 | 
			
		||||
        # Custom players - Firefox
 | 
			
		||||
        if self.custom_player_data['firefox']['showing']:
 | 
			
		||||
            players.append('firefox')
 | 
			
		||||
 | 
			
		||||
        if players:
 | 
			
		||||
            return players
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def _get_info(self):
 | 
			
		||||
        players = self._get_players()
 | 
			
		||||
 | 
			
		||||
        if not players:
 | 
			
		||||
            return {}
 | 
			
		||||
        else:
 | 
			
		||||
            result = {}
 | 
			
		||||
 | 
			
		||||
            for player in players:
 | 
			
		||||
                if player in self.custom_player_data.keys():
 | 
			
		||||
                    # Custom player -- Firefox
 | 
			
		||||
                    if player == "firefox":
 | 
			
		||||
                        result[player] = [self.custom_player_data['firefox']['state'], self.custom_player_data['firefox']['title']]
 | 
			
		||||
 | 
			
		||||
                    # Other custom players -- generic attempt with error catching
 | 
			
		||||
                    else:
 | 
			
		||||
                        try:
 | 
			
		||||
                            result[player] = [self.custom_player_data[player]['state'],
 | 
			
		||||
                                              self.custom_player_data[player]['title']]
 | 
			
		||||
                        except KeyError:
 | 
			
		||||
                            pass
 | 
			
		||||
 | 
			
		||||
                else:
 | 
			
		||||
                    # PlayerCtl player
 | 
			
		||||
                    command = ["playerctl", "-p", player, "status"]
 | 
			
		||||
                    cmd_result = self.call_process(command).strip()
 | 
			
		||||
 | 
			
		||||
                    text = "Unknown"
 | 
			
		||||
                    if cmd_result in ["Playing", "Paused"]:
 | 
			
		||||
                        artist = self.call_process(['playerctl', '-p', player, 'metadata', 'artist']).strip()
 | 
			
		||||
                        title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip()
 | 
			
		||||
 | 
			
		||||
                        if artist and title:
 | 
			
		||||
                            text = "{} - {}".format(artist, title)
 | 
			
		||||
                        elif artist:
 | 
			
		||||
                            text = artist
 | 
			
		||||
                        elif title:
 | 
			
		||||
                            text = title
 | 
			
		||||
 | 
			
		||||
                    if cmd_result == "Playing":
 | 
			
		||||
                        result[player] = [MediaWidget.Status.PLAYING, text]
 | 
			
		||||
                    elif cmd_result == "Paused":
 | 
			
		||||
                        result[player] = [MediaWidget.Status.PAUSED, text]
 | 
			
		||||
                    elif cmd_result == "Stopped":
 | 
			
		||||
                        result[player] = [MediaWidget.Status.STOPPED, ""]
 | 
			
		||||
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
    def _get_formatted_text(self, status):
 | 
			
		||||
        if status[0] == MediaWidget.Status.PLAYING:
 | 
			
		||||
            return self.on_text_play.format(status[1])
 | 
			
		||||
        elif status[0] == MediaWidget.Status.PAUSED:
 | 
			
		||||
            return self.on_text_pause.format(status[1])
 | 
			
		||||
        elif status[0] == MediaWidget.Status.STOPPED:
 | 
			
		||||
            return self.on_text_stop.format(status[1])
 | 
			
		||||
        else:
 | 
			
		||||
            return "Unknown"
 | 
			
		||||
 | 
			
		||||
    def poll(self):
 | 
			
		||||
        text = []
 | 
			
		||||
        status = self._get_info()
 | 
			
		||||
        if not status:
 | 
			
		||||
            return self.off_text
 | 
			
		||||
        else:
 | 
			
		||||
            for player in status.keys():
 | 
			
		||||
                icon = self.player_icons.get(player, player)
 | 
			
		||||
                logger.warning([player, status[player]])
 | 
			
		||||
                text.append("{} {}".format(icon, self._get_formatted_text(status[player])))
 | 
			
		||||
 | 
			
		||||
        return " | ".join(text) if text else self.off_text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AudioVisualizerWidget(_Graph):
 | 
			
		||||
    """Display Audio Visualization graph"""
 | 
			
		||||
    orientations = base.ORIENTATION_HORIZONTAL
 | 
			
		||||
    defaults = [
 | 
			
		||||
        ("audio_channel", "default", "Which audio channel to show"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    stream = None
 | 
			
		||||
 | 
			
		||||
    fixed_upper_bound = True
 | 
			
		||||
 | 
			
		||||
    def __init__(self, **config):
 | 
			
		||||
        _Graph.__init__(self, **config)
 | 
			
		||||
        self.add_defaults(AudioVisualizerWidget.defaults)
 | 
			
		||||
        self.maxvalue = 100
 | 
			
		||||
        self.samples = 1024
 | 
			
		||||
        self.max_observed = 1
 | 
			
		||||
 | 
			
		||||
        # initialize communication queue
 | 
			
		||||
        self.q = Queue()
 | 
			
		||||
        self.t = None
 | 
			
		||||
        self.stream = None
 | 
			
		||||
        self.tries = 0
 | 
			
		||||
 | 
			
		||||
    def initialize_stream(self):
 | 
			
		||||
        # initialize portaudio
 | 
			
		||||
        p = pyaudio.PyAudio()
 | 
			
		||||
        try:
 | 
			
		||||
            self.stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=self.samples)
 | 
			
		||||
 | 
			
		||||
            # initialize thread
 | 
			
		||||
            self.t = Thread(target=self.process, args=[self, self.q])
 | 
			
		||||
            self.t.start()
 | 
			
		||||
        except OSError as e:
 | 
			
		||||
            logger.warning("Could not open audio stream: ".format(e))
 | 
			
		||||
 | 
			
		||||
        self.tries += 1
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def process(widget: 'AudioVisualizerWidget', queue: Queue):
 | 
			
		||||
 | 
			
		||||
        item = queue.get()
 | 
			
		||||
 | 
			
		||||
        if widget.max_observed > 100:
 | 
			
		||||
            widget.max_observed -= 100
 | 
			
		||||
        # Discard all available frames
 | 
			
		||||
        avail = widget.stream.get_read_available()
 | 
			
		||||
        while avail > 1000:
 | 
			
		||||
            _ = widget.stream.read(avail)
 | 
			
		||||
            logger.debug("Discarded {} frames".format(avail))
 | 
			
		||||
            avail = widget.stream.get_read_available()
 | 
			
		||||
 | 
			
		||||
        if avail > 100:
 | 
			
		||||
            data = widget.stream.read(widget.samples)
 | 
			
		||||
            numpydata = numpy.abs(numpy.fromstring(data, dtype=numpy.int16))
 | 
			
		||||
 | 
			
		||||
            if numpy.max(numpydata) > widget.max_observed:
 | 
			
		||||
                widget.max_observed = numpy.max(numpydata)
 | 
			
		||||
 | 
			
		||||
            numpydata = numpydata * (100 / widget.max_observed)
 | 
			
		||||
            numpydata = AudioVisualizerWidget.window_rms(numpydata, 25)
 | 
			
		||||
 | 
			
		||||
            widget.values = list(numpydata)
 | 
			
		||||
            print(widget.values)
 | 
			
		||||
        else:
 | 
			
		||||
            widget.values = [0]*1024
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def window_rms(a, window_size):
 | 
			
		||||
        a2 = numpy.power(a, 2)
 | 
			
		||||
        window = numpy.ones(window_size) / float(window_size)
 | 
			
		||||
        return numpy.sqrt(numpy.convolve(a2, window, 'valid'))
 | 
			
		||||
 | 
			
		||||
    def update_graph(self):
 | 
			
		||||
        if not self.stream and self.tries < 10:
 | 
			
		||||
            self.initialize_stream()
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            if self.q.empty():
 | 
			
		||||
                self.q.put(True)
 | 
			
		||||
                self.draw()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KuroCurrentLayoutIcon(CurrentLayoutIcon):
 | 
			
		||||
    def _get_layout_names(self):
 | 
			
		||||
        names = super(KuroCurrentLayoutIcon, self)._get_layout_names()
 | 
			
		||||
 | 
			
		||||
        from kuro.utils import layouts as kuro_layouts
 | 
			
		||||
        from libqtile.layout.base import Layout
 | 
			
		||||
        klayouts = [
 | 
			
		||||
            layout_class_name.lower()
 | 
			
		||||
            for layout_class, layout_class_name
 | 
			
		||||
            in map(lambda x: (getattr(kuro_layouts, x), x), dir(kuro_layouts))
 | 
			
		||||
            if isinstance(layout_class, six.class_types) and issubclass(layout_class, Layout)
 | 
			
		||||
        ]
 | 
			
		||||
        names.extend(klayouts)
 | 
			
		||||
 | 
			
		||||
        return list(set(names))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,13 +71,20 @@ def handle_focus_change(theme):
 | 
			
		|||
                    'middle': Color.RED,
 | 
			
		||||
                    'right': Color.WHITE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "chromium" in wm_class[0]:
 | 
			
		||||
            elif "Firefox" in wm_class[1]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.FULL,
 | 
			
		||||
                    'left': Color.WHITE,
 | 
			
		||||
                    'middle': Color.BLUE,
 | 
			
		||||
                    'right': Color.WHITE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "Thunderbird" in wm_class[1]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.FULL,
 | 
			
		||||
                    'left': Color.BLUE,
 | 
			
		||||
                    'middle': Color.WHITE,
 | 
			
		||||
                    'right': Color.BLUE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "pycharm" in wm_class[1]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.MEDIUM,
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +99,32 @@ def handle_focus_change(theme):
 | 
			
		|||
                    'middle': Color.WHITE,
 | 
			
		||||
                    'right': Color.BLUE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "quasselclient" in wm_class[0]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.MEDIUM,
 | 
			
		||||
                    'left': Color.BLUE,
 | 
			
		||||
                    'middle': Color.BLUE,
 | 
			
		||||
                    'right': Color.BLUE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "remmina" in wm_class[0]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.FULL,
 | 
			
		||||
                    'left': Color.RED,
 | 
			
		||||
                    'middle': Color.GREEN,
 | 
			
		||||
                    'right': Color.BLUE,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "spotify" in wm_class[0]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.FULL,
 | 
			
		||||
                    'left': Color.GREEN,
 | 
			
		||||
                    'middle': Color.GREEN,
 | 
			
		||||
                    'right': Color.GREEN,
 | 
			
		||||
                }))
 | 
			
		||||
            elif "pulseeffects" in wm_class[0]:
 | 
			
		||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
			
		||||
                    'brightness': Brightness.FULL,
 | 
			
		||||
                    'mode': Mode.RANDOM,
 | 
			
		||||
                }))
 | 
			
		||||
            else:
 | 
			
		||||
                BacklightController.reset_backlight()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue