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
				
			
		| 
						 | 
					@ -65,7 +65,6 @@ hook.subscribe.changegroup(Theme.callback_changegroup)
 | 
				
			||||||
hook.subscribe.focus_change(Theme.callback_focus_change)
 | 
					hook.subscribe.focus_change(Theme.callback_focus_change)
 | 
				
			||||||
hook.subscribe.float_change(Theme.callback_float_change)
 | 
					hook.subscribe.float_change(Theme.callback_float_change)
 | 
				
			||||||
hook.subscribe.group_window_add(Theme.callback_group_window_add)
 | 
					hook.subscribe.group_window_add(Theme.callback_group_window_add)
 | 
				
			||||||
hook.subscribe.window_name_change(Theme.callback_window_name_change)
 | 
					 | 
				
			||||||
hook.subscribe.client_new(Theme.callback_client_new)
 | 
					hook.subscribe.client_new(Theme.callback_client_new)
 | 
				
			||||||
hook.subscribe.client_managed(Theme.callback_client_managed)
 | 
					hook.subscribe.client_managed(Theme.callback_client_managed)
 | 
				
			||||||
hook.subscribe.client_killed(Theme.callback_client_killed)
 | 
					hook.subscribe.client_killed(Theme.callback_client_killed)
 | 
				
			||||||
| 
						 | 
					@ -112,3 +111,6 @@ def main(qtile):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Save qtile instance in theme
 | 
					    # Save qtile instance in theme
 | 
				
			||||||
    Theme.qtile = qtile
 | 
					    Theme.qtile = qtile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Save theme instance in qtile
 | 
				
			||||||
 | 
					    qtile.theme_instance = Theme
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,9 +183,6 @@ class BaseTheme:
 | 
				
			||||||
    def callback_group_window_add(self, *args, **kwargs):
 | 
					    def callback_group_window_add(self, *args, **kwargs):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def callback_window_name_change(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def callback_client_new(self, *args, **kwargs):
 | 
					    def callback_client_new(self, *args, **kwargs):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,17 @@ class Config(BaseConfig):
 | 
				
			||||||
    debug = False
 | 
					    debug = False
 | 
				
			||||||
    verbose = False
 | 
					    verbose = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Colors
 | 
				
			||||||
 | 
					    foreground = "#ffffff"
 | 
				
			||||||
 | 
					    background = "#000000"
 | 
				
			||||||
 | 
					    highlight = "#1793d0"
 | 
				
			||||||
 | 
					    inactive_light = "#777777"
 | 
				
			||||||
 | 
					    inactive_dark = "#333333"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Default Applications
 | 
					    # Default Applications
 | 
				
			||||||
    app_terminal = "terminator"
 | 
					    app_terminal = "terminator"
 | 
				
			||||||
    app_launcher = "dmenu_run -i -p '»' -nb '#000000' -fn 'Noto Sans-11' -nf '#777777' -sb '#1793d0' -sf '#ffffff'"
 | 
					    app_launcher = "dmenu_run -i -p '»' -nb '" + background + "' -fn 'Noto Sans-11' -nf '" + inactive_light + \
 | 
				
			||||||
 | 
					                   "' -sb '" + highlight + "' -sf '" + foreground + "'"
 | 
				
			||||||
    web_browser = "firefox-developer-edition"
 | 
					    web_browser = "firefox-developer-edition"
 | 
				
			||||||
    file_manager = "thunar"
 | 
					    file_manager = "thunar"
 | 
				
			||||||
    cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10"
 | 
					    cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10"
 | 
				
			||||||
| 
						 | 
					@ -18,7 +26,9 @@ class Config(BaseConfig):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Images
 | 
					    # Images
 | 
				
			||||||
    desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png"
 | 
					    desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png"
 | 
				
			||||||
 | 
					    desktop_bg_folder = "/home/kevin/Pictures/wallpapers/desktop_rotation"
 | 
				
			||||||
    applauncher_image = "/home/kevin/.config/qtile/kuro/resources/arch.png"
 | 
					    applauncher_image = "/home/kevin/.config/qtile/kuro/resources/arch.png"
 | 
				
			||||||
 | 
					    custom_layout_icon_paths = ['/home/kevin/.config/qtile/kuro/resources/layout_icons/']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Fonts
 | 
					    # Fonts
 | 
				
			||||||
    font_default = "Noto Sans"
 | 
					    font_default = "Noto Sans"
 | 
				
			||||||
| 
						 | 
					@ -41,14 +51,14 @@ class Config(BaseConfig):
 | 
				
			||||||
    width_zoomy_column = 300
 | 
					    width_zoomy_column = 300
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Colours
 | 
					    # Colours
 | 
				
			||||||
    colour_border_normal = "#333333"
 | 
					    colour_border_normal = inactive_dark
 | 
				
			||||||
    colour_border_focus = "#ffffff"
 | 
					    colour_border_focus = foreground
 | 
				
			||||||
    colour_border_urgent = "#774400"
 | 
					    colour_border_urgent = highlight
 | 
				
			||||||
    colour_spacer_background = "#777777"
 | 
					    colour_spacer_background = inactive_light
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Bar variables
 | 
					    # Bar variables
 | 
				
			||||||
    bar_background = "#000000"
 | 
					    bar_background = background
 | 
				
			||||||
    bar_opacity = 0.65
 | 
					    bar_opacity = 0.8
 | 
				
			||||||
    bar_hover_opacity = 1
 | 
					    bar_hover_opacity = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Groupbox variables
 | 
					    # Groupbox variables
 | 
				
			||||||
| 
						 | 
					@ -59,14 +69,14 @@ class Config(BaseConfig):
 | 
				
			||||||
    margin_groupbox = 0
 | 
					    margin_groupbox = 0
 | 
				
			||||||
    bool_groupbox_disable_drag = True
 | 
					    bool_groupbox_disable_drag = True
 | 
				
			||||||
    bool_groupbox_rounded_borders = True
 | 
					    bool_groupbox_rounded_borders = True
 | 
				
			||||||
    colour_groupbox_border_normal = "#333333"
 | 
					    colour_groupbox_border_normal = inactive_dark
 | 
				
			||||||
    colour_groupbox_border_focus = "#aaaaaa"
 | 
					    colour_groupbox_border_focus = foreground
 | 
				
			||||||
    colour_groupbox_icon_active = "#ffffff"
 | 
					    colour_groupbox_icon_active = foreground
 | 
				
			||||||
    colour_groupbox_icon_inactive = "#777777"
 | 
					    colour_groupbox_icon_inactive = inactive_light
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Tasklist variables
 | 
					    # Tasklist variables
 | 
				
			||||||
    tasklist_border = "#ffffff"
 | 
					    tasklist_border = foreground
 | 
				
			||||||
    tasklist_urgent_border = "#774400"
 | 
					    tasklist_urgent_border = highlight
 | 
				
			||||||
    tasklist_font = "Noto Sans"
 | 
					    tasklist_font = "Noto Sans"
 | 
				
			||||||
    tasklist_fontsize = 11
 | 
					    tasklist_fontsize = 11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,10 +107,10 @@ class Config(BaseConfig):
 | 
				
			||||||
    volume_font = "Noto Sans"
 | 
					    volume_font = "Noto Sans"
 | 
				
			||||||
    volume_fontsize = 11
 | 
					    volume_fontsize = 11
 | 
				
			||||||
    volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume"
 | 
					    volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume"
 | 
				
			||||||
    volume_get_command = "pamixer --sink 0 --get-volume".split()
 | 
					    volume_get_command = "pamixer --sink 2 --get-volume".split()
 | 
				
			||||||
    volume_mute_command = "pamixer --sink 0 -t".split()
 | 
					    volume_mute_command = "pamixer --sink 2 -t".split()
 | 
				
			||||||
    volume_up_command = "pamixer --sink 0 -i 2".split()
 | 
					    volume_up_command = "pamixer --sink 2 -i 2".split()
 | 
				
			||||||
    volume_down_command = "pamixer --sink 0 -d 2".split()
 | 
					    volume_down_command = "pamixer --sink 2 -d 2".split()
 | 
				
			||||||
    volume_is_bluetooth_icon = False
 | 
					    volume_is_bluetooth_icon = False
 | 
				
			||||||
    volume_update_interval = 0.2
 | 
					    volume_update_interval = 0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +127,15 @@ class Config(BaseConfig):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # CheckUpdates variables
 | 
					    # CheckUpdates variables
 | 
				
			||||||
    updates_display_format = "{updates}"
 | 
					    updates_display_format = "{updates}"
 | 
				
			||||||
    updates_execute_command = "terminator -e 'echo Updating\ via\ yaourt\ -Sayu...; yaourt -Sayu'"
 | 
					    updates_execute_command = "terminator -e 'echo Updating\ via\ yay...; yay'"
 | 
				
			||||||
    updates_colour_available = '#f4d742'
 | 
					    updates_colour_available = '#f4d742'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Screen organization
 | 
				
			||||||
 | 
					    laptop_screen = "eDP-1-1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Keyboard colors
 | 
				
			||||||
 | 
					    do_keyboard_updates = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Show audio visualizer
 | 
				
			||||||
 | 
					    show_audio_visualizer = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								kuro/resources/layout_icons/layout-kurowmii.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								kuro/resources/layout_icons/layout-kurowmii.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 266 B  | 
							
								
								
									
										257
									
								
								kuro/theme.py
									
										
									
									
									
								
							
							
						
						
									
										257
									
								
								kuro/theme.py
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,7 @@
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from libqtile.config import Key, Screen, Group, Drag, Click
 | 
					from libqtile.config import Key, Screen, Group, Drag, Click
 | 
				
			||||||
from libqtile.command import lazy
 | 
					from libqtile.command import lazy
 | 
				
			||||||
from libqtile import layout, bar, widget
 | 
					from libqtile import layout, bar, widget
 | 
				
			||||||
| 
						 | 
					@ -39,6 +43,12 @@ class Kuro(BaseTheme):
 | 
				
			||||||
    # Top bars
 | 
					    # Top bars
 | 
				
			||||||
    topbars = []
 | 
					    topbars = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Current wallpaper path
 | 
				
			||||||
 | 
					    current_wallpaper = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Whether or not to perform keyboard backlight updates
 | 
				
			||||||
 | 
					    do_keyboard_updates = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Window manager name
 | 
					    # Window manager name
 | 
				
			||||||
    wmname = "QTile"
 | 
					    wmname = "QTile"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +70,12 @@ class Kuro(BaseTheme):
 | 
				
			||||||
    def initialize(self):
 | 
					    def initialize(self):
 | 
				
			||||||
        self.log_debug("Initializing Kuro Theme...")
 | 
					        self.log_debug("Initializing Kuro Theme...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update color scheme
 | 
				
			||||||
 | 
					        self.initialize_colorscheme()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Set settings
 | 
				
			||||||
 | 
					        self.do_keyboard_updates = Config.get("do_keyboard_updates", True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super(Kuro, self).initialize()
 | 
					        super(Kuro, self).initialize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.update()
 | 
					        self.update()
 | 
				
			||||||
| 
						 | 
					@ -108,7 +124,7 @@ class Kuro(BaseTheme):
 | 
				
			||||||
            Key([self.mod], "b", lazy.spawn(Config.get('web_browser', "xterm links"))),
 | 
					            Key([self.mod], "b", lazy.spawn(Config.get('web_browser', "xterm links"))),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Super-F to start file manager
 | 
					            # Super-F to start file manager
 | 
				
			||||||
#            Key([self.mod], "f", lazy.spawn(Config.get('file_manager', "thunar"))),
 | 
					#            Key([self.mod], "f", lazy.spawn(Config.get('file_m4anager', "thunar"))),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Super-Shift-R to start spawncmd
 | 
					            # Super-Shift-R to start spawncmd
 | 
				
			||||||
            Key([self.mod, "shift"], "r", lazy.spawncmd()),
 | 
					            Key([self.mod, "shift"], "r", lazy.spawncmd()),
 | 
				
			||||||
| 
						 | 
					@ -132,13 +148,20 @@ class Kuro(BaseTheme):
 | 
				
			||||||
            # Shutdown QTile
 | 
					            # Shutdown QTile
 | 
				
			||||||
            Key([self.mod, "control"], "q", lazy.shutdown()),
 | 
					            Key([self.mod, "control"], "q", lazy.shutdown()),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Update wallpaper
 | 
				
			||||||
 | 
					            Key([self.mod, "control"], "w", lazy.function(self.update_wallpaper)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Reload colorscheme
 | 
				
			||||||
 | 
					            Key([self.mod, "control"], "t", lazy.function(self.update_colorscheme)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Reorganize screens
 | 
				
			||||||
 | 
					            Key([self.mod, "control"], "s", lazy.function(self.update_screens)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ##
 | 
					            ##
 | 
				
			||||||
            # Debug keyboard shortcuts
 | 
					            # Debug keyboard shortcuts
 | 
				
			||||||
            ##
 | 
					            ##
 | 
				
			||||||
            Key([self.mod, "control"], "w", lazy.function(display_wm_class)),
 | 
					            Key([self.mod, "control"], "c", lazy.function(display_wm_class)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Redraw the top bar
 | 
					            # Redraw the top bar
 | 
				
			||||||
            Key([self.mod, "shift", "control"], "r", lazy.function(self.redraw_bar)),
 | 
					            Key([self.mod, "shift", "control"], "r", lazy.function(self.redraw_bar)),
 | 
				
			||||||
| 
						 | 
					@ -153,7 +176,7 @@ class Kuro(BaseTheme):
 | 
				
			||||||
        groups = []
 | 
					        groups = []
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # http://fontawesome.io/cheatsheet
 | 
					        # http://fontawesome.io/cheatsheet
 | 
				
			||||||
        groups.append(Group("", spawn=Config.get('web_browser', "xterm links")))
 | 
					        groups.append(Group("", spawn=Config.get('web_browser', "xterm links")))
 | 
				
			||||||
        groups.append(Group("", spawn=Config.get('app_terminal', "xterm")))
 | 
					        groups.append(Group("", spawn=Config.get('app_terminal', "xterm")))
 | 
				
			||||||
        groups.append(Group(""))
 | 
					        groups.append(Group(""))
 | 
				
			||||||
        groups.append(Group("", spawn="franz4-bin"))
 | 
					        groups.append(Group("", spawn="franz4-bin"))
 | 
				
			||||||
| 
						 | 
					@ -161,7 +184,7 @@ class Kuro(BaseTheme):
 | 
				
			||||||
        groups.append(Group("", spawn=Config.get('file_manager', "thunar")))
 | 
					        groups.append(Group("", spawn=Config.get('file_manager', "thunar")))
 | 
				
			||||||
        groups.append(Group("", spawn="thunderbird"))
 | 
					        groups.append(Group("", spawn="thunderbird"))
 | 
				
			||||||
        groups.append(Group(""))
 | 
					        groups.append(Group(""))
 | 
				
			||||||
        groups.append(Group("", spawn="qupzilla https://music.kurocon.nl/"))
 | 
					        groups.append(Group(""))
 | 
				
			||||||
        groups.append(Group(""))
 | 
					        groups.append(Group(""))
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return groups
 | 
					        return groups
 | 
				
			||||||
| 
						 | 
					@ -233,7 +256,23 @@ class Kuro(BaseTheme):
 | 
				
			||||||
                    urgent_alert_method=Config.get('tasklist_urgent_alert_method', 'border'),
 | 
					                    urgent_alert_method=Config.get('tasklist_urgent_alert_method', 'border'),
 | 
				
			||||||
                    urgent_border=Config.get('tasklist_urgent_border', '#ff0000'),
 | 
					                    urgent_border=Config.get('tasklist_urgent_border', '#ff0000'),
 | 
				
			||||||
                    margin=Config.get('margin_groupbox', 0)
 | 
					                    margin=Config.get('margin_groupbox', 0)
 | 
				
			||||||
                ),
 | 
					                )
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if Config.get('show_audio_visualizer', False):
 | 
				
			||||||
 | 
					                widgets.append(utils.AudioVisualizerWidget(
 | 
				
			||||||
 | 
					                   graph_color=Config.get('visualizer_graph_color', "#ffffff"),
 | 
				
			||||||
 | 
					                   fill_color=Config.get('visualizer_fill_color', "#ffffff.3"),
 | 
				
			||||||
 | 
					                   border_color=Config.get('visualizer_border_color', "#000000"),
 | 
				
			||||||
 | 
					                   border_width=Config.get('visualizer_graph_width', 0),
 | 
				
			||||||
 | 
					                   line_width=Config.get('visualizer_line_width', 1),
 | 
				
			||||||
 | 
					                   frequency=0.05
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            widgets.extend([
 | 
				
			||||||
 | 
					                utils.MediaWidget(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                utils.SeparatorWidget(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                utils.ThermalSensorWidget(
 | 
					                utils.ThermalSensorWidget(
 | 
				
			||||||
                    font=Config.get('font_topbar', 'Arial'),
 | 
					                    font=Config.get('font_topbar', 'Arial'),
 | 
				
			||||||
| 
						 | 
					@ -342,9 +381,9 @@ class Kuro(BaseTheme):
 | 
				
			||||||
                widgets.append(widget.Systray(**self.widget_defaults))
 | 
					                widgets.append(widget.Systray(**self.widget_defaults))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            widgets.extend([
 | 
					            widgets.extend([
 | 
				
			||||||
                widget.CurrentLayoutIcon(),
 | 
					                utils.KuroCurrentLayoutIcon(custom_icon_paths=Config.get('custom_layout_icon_paths', [])),
 | 
				
			||||||
                widget.Clock(format="%a %d %b, %H:%M", **self.widget_defaults),
 | 
					                widget.Clock(format="%a %d %b, %H:%M", **self.widget_defaults),
 | 
				
			||||||
                utils.CheckUpdatesYaourt(
 | 
					                utils.CheckUpdatesYay(
 | 
				
			||||||
                    colour_no_updates=Config.get('updates_colour_none', '#ffffff'),
 | 
					                    colour_no_updates=Config.get('updates_colour_none', '#ffffff'),
 | 
				
			||||||
                    colour_have_updates=Config.get('updates_colour_available', '#ff0000'),
 | 
					                    colour_have_updates=Config.get('updates_colour_available', '#ff0000'),
 | 
				
			||||||
                    display_format=Config.get('updates_display_format', 'Updates: {updates}'),
 | 
					                    display_format=Config.get('updates_display_format', 'Updates: {updates}'),
 | 
				
			||||||
| 
						 | 
					@ -442,16 +481,67 @@ class Kuro(BaseTheme):
 | 
				
			||||||
    # Util functions
 | 
					    # Util functions
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def redraw_bar(qtile):
 | 
					    def redraw_bar(qtile):
 | 
				
			||||||
        for b in qtile.topbars:
 | 
					        for s in qtile.screens:
 | 
				
			||||||
            b.draw()
 | 
					            s.top.draw()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def update_screens(qtile):
 | 
				
			||||||
 | 
					        out = utils.call_process(["xrandr", "--current"])
 | 
				
			||||||
 | 
					        laptop_screen = None
 | 
				
			||||||
 | 
					        screens = []
 | 
				
			||||||
 | 
					        for x in out.split("\n"):
 | 
				
			||||||
 | 
					            if " connected " in x:
 | 
				
			||||||
 | 
					                if Config.get("laptop_screen", None) is not None and Config.get("laptop_screen", None) in x:
 | 
				
			||||||
 | 
					                    laptop_screen = x
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    screens.append(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Only configure two screens. Open arandr if more screens are present.
 | 
				
			||||||
 | 
					        if laptop_screen is not None and len(screens) == 1:
 | 
				
			||||||
 | 
					            laptop = laptop_screen.split()[0]
 | 
				
			||||||
 | 
					            other = screens[0].split()[0]
 | 
				
			||||||
 | 
					            utils.call_process(["xrandr", "--output", laptop, "--below", other])
 | 
				
			||||||
 | 
					            qtile.cmd_restart()
 | 
				
			||||||
 | 
					        elif laptop_screen is not None and len(screens) > 1:
 | 
				
			||||||
 | 
					            utils.execute("arandr")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # QTile base callbacks
 | 
					    # QTile base callbacks
 | 
				
			||||||
 | 
					    def callback_startup_once(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					        #Kuro.update_screens(self.qtile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def callback_startup(self):
 | 
					    def callback_startup(self):
 | 
				
			||||||
        utils.execute("sleep 3")
 | 
					        utils.execute("sleep 3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log_info("Restoring wallpaper...")
 | 
					        # self.log_info("Restoring previous wallpaper...")
 | 
				
			||||||
        utils.execute_once("nitrogen --restore")
 | 
					        # utils.execute_once("nitrogen --restore")
 | 
				
			||||||
        #
 | 
					        self.update_wallpaper(self.qtile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.current_wallpaper:
 | 
				
			||||||
 | 
					            utils.execute_once(["wal", "-n", "-i", "{}".format(self.current_wallpaper)])
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            wallpaper = None
 | 
				
			||||||
 | 
					            if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
 | 
				
			||||||
 | 
					                with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
 | 
				
			||||||
 | 
					                    try:
 | 
				
			||||||
 | 
					                        wallpaper = json.load(f)['wallpaper']
 | 
				
			||||||
 | 
					                    except KeyError:
 | 
				
			||||||
 | 
					                        wallpaper = None
 | 
				
			||||||
 | 
					            if wallpaper:
 | 
				
			||||||
 | 
					                Kuro.set_wallpaper(self.qtile, wallpaper)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                utils.execute_once("nitrogen --restore")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.log_info("Starting compositor...")
 | 
				
			||||||
 | 
					        utils.execute_once("compton -b")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update color scheme
 | 
				
			||||||
 | 
					        self.initialize_colorscheme()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update color scheme
 | 
				
			||||||
 | 
					        Kuro.update_colorscheme(self.qtile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # display = os.environ['DISPLAY']
 | 
					        # display = os.environ['DISPLAY']
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
        # if not display:
 | 
					        # if not display:
 | 
				
			||||||
| 
						 | 
					@ -467,7 +557,8 @@ class Kuro(BaseTheme):
 | 
				
			||||||
    #     return True
 | 
					    #     return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def callback_focus_change(self, *args, **kwargs):
 | 
					    def callback_focus_change(self, *args, **kwargs):
 | 
				
			||||||
        kb_handle_focus_change(self)
 | 
					        if self.do_keyboard_updates:
 | 
				
			||||||
 | 
					            kb_handle_focus_change(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    initial_windows = []
 | 
					    initial_windows = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -487,6 +578,9 @@ class Kuro(BaseTheme):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.callback_client_new()
 | 
					            self.callback_client_new()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Update color scheme
 | 
				
			||||||
 | 
					        Kuro.update_colorscheme(self.qtile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def callback_client_new(self, *args, **kwargs):
 | 
					    def callback_client_new(self, *args, **kwargs):
 | 
				
			||||||
        if len(self.initial_windows) > 0:
 | 
					        if len(self.initial_windows) > 0:
 | 
				
			||||||
            init = self.initial_windows.copy()
 | 
					            init = self.initial_windows.copy()
 | 
				
			||||||
| 
						 | 
					@ -501,5 +595,140 @@ class Kuro(BaseTheme):
 | 
				
			||||||
                                    if r.matches(window):
 | 
					                                    if r.matches(window):
 | 
				
			||||||
                                        self.qtile.dgroups.remove_rule(rid)
 | 
					                                        self.qtile.dgroups.remove_rule(rid)
 | 
				
			||||||
                                        self.initial_windows.remove((pid, gname))
 | 
					                                        self.initial_windows.remove((pid, gname))
 | 
				
			||||||
                                        self.log_info("Removed group rule for PID {}, window {}".format(pid, window.name))
 | 
					                                        self.log_info("Removed group rule for PID {}, window {}".format(pid,
 | 
				
			||||||
 | 
					                                                                                                        window.name))
 | 
				
			||||||
                self.log_info(str(self.qtile.dgroups.rules_map))
 | 
					                self.log_info(str(self.qtile.dgroups.rules_map))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def update_wallpaper(qtile):
 | 
				
			||||||
 | 
					        wallpapers = []
 | 
				
			||||||
 | 
					        wallpaper_dir = Config.get("desktop_bg_folder", "")
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            wallpapers = os.listdir(wallpaper_dir)
 | 
				
			||||||
 | 
					        except os.error:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if wallpapers:
 | 
				
			||||||
 | 
					            qtile.theme_instance.current_wallpaper = os.path.join(wallpaper_dir, random.choice(wallpapers))
 | 
				
			||||||
 | 
					            Kuro.set_wallpaper(qtile, qtile.theme_instance.current_wallpaper)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            utils.execute_once("nitrogen --restore")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def set_wallpaper(qtile, filename):
 | 
				
			||||||
 | 
					        utils.execute_once("wal-nitrogen {}".format(filename))
 | 
				
			||||||
 | 
					        qtile.theme_instance.current_wallpaper = filename
 | 
				
			||||||
 | 
					        Kuro.update_colorscheme(qtile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def update_mediaclients(*args, **kwargs):
 | 
				
			||||||
 | 
					        return str(str(args) + " " + str(kwargs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def initialize_colorscheme():
 | 
				
			||||||
 | 
					        colors = None
 | 
				
			||||||
 | 
					        if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
 | 
				
			||||||
 | 
					            with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    colors = json.load(f)['colors']
 | 
				
			||||||
 | 
					                except KeyError:
 | 
				
			||||||
 | 
					                    colors = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if colors:
 | 
				
			||||||
 | 
					            # Update Config
 | 
				
			||||||
 | 
					            Config.foreground = colors['color15']
 | 
				
			||||||
 | 
					            Config.background = colors['color0']
 | 
				
			||||||
 | 
					            Config.highlight = colors['color3']
 | 
				
			||||||
 | 
					            Config.inactive_light = colors['color4']
 | 
				
			||||||
 | 
					            Config.inactive_dark = colors['color5']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def update_colorscheme(qtile):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        :type qtile: libqtile.manager.Qtile
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if qtile.theme_instance.current_wallpaper:
 | 
				
			||||||
 | 
					            utils.execute(["wal", "-n", "-i", "{}".format(qtile.theme_instance.current_wallpaper)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        colors = None
 | 
				
			||||||
 | 
					        if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
 | 
				
			||||||
 | 
					            with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    colors = json.load(f)['colors']
 | 
				
			||||||
 | 
					                except KeyError:
 | 
				
			||||||
 | 
					                    colors = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if colors:
 | 
				
			||||||
 | 
					            # Update Config
 | 
				
			||||||
 | 
					            Config.foreground = colors['color15']
 | 
				
			||||||
 | 
					            Config.background = colors['color0']
 | 
				
			||||||
 | 
					            Config.highlight = colors['color3']
 | 
				
			||||||
 | 
					            Config.inactive_light = colors['color4']
 | 
				
			||||||
 | 
					            Config.inactive_dark = colors['color5']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Update border colors in layouts
 | 
				
			||||||
 | 
					            for group in qtile.groups:
 | 
				
			||||||
 | 
					                for layout in group.layouts:
 | 
				
			||||||
 | 
					                    if isinstance(layout, kuro_layouts.KuroWmii):
 | 
				
			||||||
 | 
					                        layout.border_focus = colors['color15']
 | 
				
			||||||
 | 
					                        layout.border_focus_stack = colors['color1']
 | 
				
			||||||
 | 
					                        layout.border_normal = colors['color1']
 | 
				
			||||||
 | 
					                        layout.border_normal_stack = colors['color1']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for screen in qtile.screens:
 | 
				
			||||||
 | 
					                bar = screen.top
 | 
				
			||||||
 | 
					                bar.background = colors['color1']
 | 
				
			||||||
 | 
					                bar.drawer.clear(bar.background)
 | 
				
			||||||
 | 
					                for w in bar.widgets:
 | 
				
			||||||
 | 
					                    if hasattr(w, '_update_drawer'):
 | 
				
			||||||
 | 
					                        try:
 | 
				
			||||||
 | 
					                            w._update_drawer()
 | 
				
			||||||
 | 
					                        except Exception as e:
 | 
				
			||||||
 | 
					                            logger.error("Error while updating drawer: {}".format(e))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'foreground'):
 | 
				
			||||||
 | 
					                        w.foreground = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'foreground_normal'):
 | 
				
			||||||
 | 
					                        w.foreground_normal = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'foreground_alert'):
 | 
				
			||||||
 | 
					                        w.foreground_alert = colors['color3']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'border'):
 | 
				
			||||||
 | 
					                        w.border = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'active'):
 | 
				
			||||||
 | 
					                        w.active = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'highlight_color'):
 | 
				
			||||||
 | 
					                        w.highlight_color = colors['color3']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'inactive'):
 | 
				
			||||||
 | 
					                        w.inactive = colors['color8']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'this_current_screen_border'):
 | 
				
			||||||
 | 
					                        w.this_current_screen_border = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'this_screen_border'):
 | 
				
			||||||
 | 
					                        w.this_screen_border = colors['color15']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'other_current_screen_border'):
 | 
				
			||||||
 | 
					                        w.other_current_screen_border = colors['color8']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if hasattr(w, 'other_screen_border'):
 | 
				
			||||||
 | 
					                        w.other_screen_border = colors['color8']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if isinstance(w, utils.AudioVisualizerWidget):
 | 
				
			||||||
 | 
					                        w.graph_color = colors['color15']
 | 
				
			||||||
 | 
					                        w.fill_color = colors['color8']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                bar.draw()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            utils.notify(
 | 
				
			||||||
 | 
					                "Updated colorscheme!",
 | 
				
			||||||
 | 
					                "active: {}, inactive: {}".format(colors['color15'], colors['color1'])
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,18 @@
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from asyncio import Queue
 | 
				
			||||||
 | 
					from threading import Thread
 | 
				
			||||||
from time import sleep
 | 
					from time import sleep
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cairocffi
 | 
					import cairocffi
 | 
				
			||||||
import notify2
 | 
					import notify2
 | 
				
			||||||
 | 
					import numpy
 | 
				
			||||||
 | 
					import pyaudio
 | 
				
			||||||
 | 
					import six
 | 
				
			||||||
from libqtile import widget, bar
 | 
					from libqtile import widget, bar
 | 
				
			||||||
 | 
					from libqtile.widget.currentlayout import CurrentLayoutIcon
 | 
				
			||||||
 | 
					from libqtile.widget.graph import _Graph
 | 
				
			||||||
from libqtile.window import Internal
 | 
					from libqtile.window import Internal
 | 
				
			||||||
from libqtile.bar import Bar
 | 
					from libqtile.bar import Bar
 | 
				
			||||||
from libqtile.utils import catch_exception_and_warn, UnixCommandNotFound
 | 
					from libqtile.utils import catch_exception_and_warn, UnixCommandNotFound
 | 
				
			||||||
| 
						 | 
					@ -38,12 +45,34 @@ def is_running(process):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def execute(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):
 | 
					def execute_once(process):
 | 
				
			||||||
    if not is_running(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():
 | 
					def get_screen_count():
 | 
				
			||||||
| 
						 | 
					@ -217,18 +246,18 @@ class AppLauncherIcon(Image):
 | 
				
			||||||
        spawn_popup(self.qtile, self.offsetx, self.offsety, "Hovered over AppLauncherIcon!")
 | 
					        spawn_popup(self.qtile, self.offsetx, self.offsety, "Hovered over AppLauncherIcon!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CheckUpdatesYaourt(CheckUpdates):
 | 
					class CheckUpdatesYay(CheckUpdates):
 | 
				
			||||||
    def __init__(self, **config):
 | 
					    def __init__(self, **config):
 | 
				
			||||||
        super(CheckUpdatesYaourt, self).__init__(**config)
 | 
					        super(CheckUpdatesYay, self).__init__(**config)
 | 
				
			||||||
        # Override command and output with yaourt command
 | 
					        # Override command and output with yay command
 | 
				
			||||||
        self.cmd = "yaourt -Qua".split()
 | 
					        self.cmd = "yay -Qua".split()
 | 
				
			||||||
        self.status_cmd = "yaourt -Qua".split()
 | 
					        self.status_cmd = "yay -Qua --color never".split()
 | 
				
			||||||
        self.update_cmd = "sudo yaourt -Sya".split()
 | 
					        self.update_cmd = "sudo yay".split()
 | 
				
			||||||
        self.subtr = 0
 | 
					        self.subtr = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _check_updates(self):
 | 
					    def _check_updates(self):
 | 
				
			||||||
        #subprocess.check_output(self.update_cmd)
 | 
					        #subprocess.check_output(self.update_cmd)
 | 
				
			||||||
        res = super(CheckUpdatesYaourt, self)._check_updates()
 | 
					        res = super(CheckUpdatesYay, self)._check_updates()
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def button_press(self, x, y, button):
 | 
					    def button_press(self, x, y, button):
 | 
				
			||||||
| 
						 | 
					@ -253,6 +282,7 @@ class CheckUpdatesYaourt(CheckUpdates):
 | 
				
			||||||
        elif button == BUTTON_MIDDLE and self.execute is not None:
 | 
					        elif button == BUTTON_MIDDLE and self.execute is not None:
 | 
				
			||||||
            subprocess.Popen(self.execute, shell=True)
 | 
					            subprocess.Popen(self.execute, shell=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KuroBatteryIcon(BatteryIcon):
 | 
					class KuroBatteryIcon(BatteryIcon):
 | 
				
			||||||
    status_cmd = "acpi"
 | 
					    status_cmd = "acpi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,6 +295,7 @@ class KuroBatteryIcon(BatteryIcon):
 | 
				
			||||||
                output
 | 
					                output
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PulseVolumeWidget(Volume):
 | 
					class PulseVolumeWidget(Volume):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    defaults = [
 | 
					    defaults = [
 | 
				
			||||||
| 
						 | 
					@ -535,3 +566,255 @@ class ThermalSensorWidget(ThermalSensor):
 | 
				
			||||||
            command.append("-f")
 | 
					            command.append("-f")
 | 
				
			||||||
        sensors_out = self.call_process(command)
 | 
					        sensors_out = self.call_process(command)
 | 
				
			||||||
        return self._format_sensors_output(sensors_out)
 | 
					        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,
 | 
					                    'middle': Color.RED,
 | 
				
			||||||
                    'right': Color.WHITE,
 | 
					                    'right': Color.WHITE,
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
            elif "chromium" in wm_class[0]:
 | 
					            elif "Firefox" in wm_class[1]:
 | 
				
			||||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
					                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
				
			||||||
                    'brightness': Brightness.FULL,
 | 
					                    'brightness': Brightness.FULL,
 | 
				
			||||||
                    'left': Color.WHITE,
 | 
					                    'left': Color.WHITE,
 | 
				
			||||||
                    'middle': Color.BLUE,
 | 
					                    'middle': Color.BLUE,
 | 
				
			||||||
                    'right': Color.WHITE,
 | 
					                    '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]:
 | 
					            elif "pycharm" in wm_class[1]:
 | 
				
			||||||
                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
					                BacklightController.reset_backlight(state=KeyboardState(values={
 | 
				
			||||||
                    'brightness': Brightness.MEDIUM,
 | 
					                    'brightness': Brightness.MEDIUM,
 | 
				
			||||||
| 
						 | 
					@ -92,6 +99,32 @@ def handle_focus_change(theme):
 | 
				
			||||||
                    'middle': Color.WHITE,
 | 
					                    'middle': Color.WHITE,
 | 
				
			||||||
                    'right': Color.BLUE,
 | 
					                    '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:
 | 
					            else:
 | 
				
			||||||
                BacklightController.reset_backlight()
 | 
					                BacklightController.reset_backlight()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue