Add KuroWMII layout that manages new windows in a way I like, add some more shortcuts, improve battery icon, automatically open programs on workspaces and remove the GroupRules for them after they spawn so that new instances of that app don't open on that workspace any more.

This commit is contained in:
Kevin Alberts 2017-12-02 09:29:26 +01:00
parent b9224b667d
commit 9a3fdf1b65
5 changed files with 176 additions and 14 deletions

View file

@ -10,8 +10,11 @@ class Config(BaseConfig):
# 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 '#000000' -fn 'Noto Sans-11' -nf '#777777' -sb '#1793d0' -sf '#ffffff'"
web_browser = "firefox"
file_manager = "thunar"
cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10"
cmd_brightness_down = "sudo /usr/bin/xbacklight -dec 10" cmd_brightness_down = "sudo /usr/bin/xbacklight -dec 10"
lock_command = "/home/kevin/bin/lock.sh"
# Images # Images
desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png" desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png"

View file

@ -7,8 +7,9 @@ from kuro.utils import general as utils
# Import variables # Import variables
from kuro.base import BaseTheme from kuro.base import BaseTheme
from kuro.utils.general import display_wm_class from kuro.utils.general import display_wm_class, test_popups
from kuro.utils.kb_backlight import handle_focus_change as kb_handle_focus_change from kuro.utils.kb_backlight import handle_focus_change as kb_handle_focus_change
from kuro.utils import layouts as kuro_layouts
try: try:
from kuro.config import Config from kuro.config import Config
@ -103,9 +104,17 @@ class Kuro(BaseTheme):
# Super-R to start dmenu_run # Super-R to start dmenu_run
Key([self.mod], "r", lazy.spawn(Config.get('app_launcher', "dmenu_run"))), Key([self.mod], "r", lazy.spawn(Config.get('app_launcher', "dmenu_run"))),
# Super-B to start webbrowser
Key([self.mod], "b", lazy.spawn(Config.get('web_browser', "xterm links"))),
# Super-F to start file manager
# Key([self.mod], "f", lazy.spawn(Config.get('file_manager', "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()),
# Lock shortcut
Key([self.mod], "l", lazy.spawn(Config.get('lock_command', "i3lock"))),
# Backlight keys # Backlight keys
Key([], "XF86MonBrightnessUp", lazy.spawn(Config.get('cmd_brightness_up', 'xbacklight -inc 10'))), Key([], "XF86MonBrightnessUp", lazy.spawn(Config.get('cmd_brightness_up', 'xbacklight -inc 10'))),
@ -120,9 +129,6 @@ class Kuro(BaseTheme):
# Restart QTile # Restart QTile
Key([self.mod, "control"], "r", lazy.restart()), Key([self.mod, "control"], "r", lazy.restart()),
# Redraw the top bar
Key([self.mod, "shift", "control"], "r", lazy.function(self.redraw_bar)),
# Shutdown QTile # Shutdown QTile
Key([self.mod, "control"], "q", lazy.shutdown()), Key([self.mod, "control"], "q", lazy.shutdown()),
@ -132,20 +138,39 @@ class Kuro(BaseTheme):
## ##
# Debug keyboard shortcuts # Debug keyboard shortcuts
## ##
Key([self.mod, "control"], "w", lazy.function(display_wm_class)) Key([self.mod, "control"], "w", lazy.function(display_wm_class)),
# Redraw the top bar
Key([self.mod, "shift", "control"], "r", lazy.function(self.redraw_bar)),
# Spawn a popup, and despawn it after 3 seconds
Key([self.mod, "control"], "p", lazy.function(test_popups)),
] ]
def init_groups(self): def init_groups(self):
self.log_debug("Initializing groups") self.log_debug("Initializing groups")
groups = []
# http://fontawesome.io/cheatsheet # http://fontawesome.io/cheatsheet
return [Group(i) for i in ""] groups.append(Group("", spawn=Config.get('web_browser', "xterm links")))
groups.append(Group("", spawn=Config.get('app_terminal', "xterm")))
groups.append(Group(""))
groups.append(Group("", spawn="franz4-bin"))
groups.append(Group("", spawn="quasselclient"))
groups.append(Group("", spawn=Config.get('file_manager', "thunar")))
groups.append(Group("", spawn="thunderbird"))
groups.append(Group(""))
groups.append(Group("", spawn="qupzilla https://music.kurocon.nl/"))
groups.append(Group(""))
return groups
def init_layouts(self): def init_layouts(self):
self.log_debug("Initializing layouts") self.log_debug("Initializing layouts")
return [ return [
layout.Wmii( kuro_layouts.KuroWmii(
border_focus=Config.get('colour_border_focus', "#ffffff"), border_focus=Config.get('colour_border_focus', "#ffffff"),
border_focus_stack=Config.get('colour_border_normal', "#777777"), border_focus_stack=Config.get('colour_border_normal', "#777777"),
border_normal=Config.get('colour_border_normal', "#777777"), border_normal=Config.get('colour_border_normal', "#777777"),
@ -261,7 +286,7 @@ class Kuro(BaseTheme):
frequency=2, frequency=2,
), ),
widget.BatteryIcon( utils.KuroBatteryIcon(
battery_name=Config.get('battery_name', 'BAT0'), battery_name=Config.get('battery_name', 'BAT0'),
energy_full_file=Config.get('battery_energy_full_file', 'charge_full'), energy_full_file=Config.get('battery_energy_full_file', 'charge_full'),
energy_now_file=Config.get('battery_energy_now_file', 'charge_now'), energy_now_file=Config.get('battery_energy_now_file', 'charge_now'),
@ -378,6 +403,8 @@ class Kuro(BaseTheme):
self.log_debug("Updating keys") self.log_debug("Updating keys")
for i, g in enumerate(self.groups): for i, g in enumerate(self.groups):
if i == 9:
i = -1
# mod1 + number = switch to group # mod1 + number = switch to group
self.keys.append( self.keys.append(
Key([self.mod], str(i + 1), lazy.group[g.name].toscreen()) Key([self.mod], str(i + 1), lazy.group[g.name].toscreen())
@ -441,3 +468,38 @@ class Kuro(BaseTheme):
def callback_focus_change(self, *args, **kwargs): def callback_focus_change(self, *args, **kwargs):
kb_handle_focus_change(self) kb_handle_focus_change(self)
initial_windows = []
def callback_startup_complete(self, *args, **kwargs):
# Only run on first startup
if not self.qtile.no_spawn:
dg = self.qtile.dgroups
for r in dg.rules:
pid = -1
# noinspection PyProtectedMember
for r2 in r.match._rules:
if r2[0] == "net_wm_pid":
pid = r2[1]
break
if pid != -1:
self.initial_windows.append((pid, r.group))
self.callback_client_new()
def callback_client_new(self, *args, **kwargs):
if len(self.initial_windows) > 0:
init = self.initial_windows.copy()
for pid, gname in init:
for group in self.qtile.groups:
if len(group.windows) > 0:
for window in group.windows:
w_pid = window.window.get_net_wm_pid()
if pid == w_pid:
c = self.qtile.dgroups.rules_map.copy()
for rid, r in c.items():
if r.matches(window):
self.qtile.dgroups.remove_rule(rid)
self.initial_windows.remove((pid, gname))
self.log_info("Removed group rule for PID {}, window {}".format(pid, window.name))
self.log_info(str(self.qtile.dgroups.rules_map))

View file

@ -1,10 +1,12 @@
import os import os
import re import re
import subprocess import subprocess
from time import sleep
import cairocffi import cairocffi
import notify2 import notify2
from libqtile import widget, bar from libqtile import widget, bar
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
from libqtile.widget import base from libqtile.widget import base
@ -13,6 +15,7 @@ from libqtile.widget.check_updates import CheckUpdates
from libqtile.widget.image import Image from libqtile.widget.image import Image
from libqtile.widget.sensors import ThermalSensor from libqtile.widget.sensors import ThermalSensor
from libqtile.widget.volume import Volume from libqtile.widget.volume import Volume
from libqtile.widget.battery import BatteryIcon
from libqtile.widget.wlan import get_status from libqtile.widget.wlan import get_status
from libqtile.log_utils import logger from libqtile.log_utils import logger
from notify2 import Notification, URGENCY_NORMAL from notify2 import Notification, URGENCY_NORMAL
@ -80,13 +83,45 @@ def notify(title, content, urgency=URGENCY_NORMAL, timeout=5000, image=None):
def spawn_popup(qtile, x, y, text): def spawn_popup(qtile, x, y, text):
"""
:param qtile: The main qtile instance
:type qtile: Qtile
:param x: x-coordinate
:type x: int
:param y: y-coordinate
:type y: int
:param text: String to display
:type text: str
:return: The popup instance
:rtype: Internal
"""
popup = Internal.create(
qtile, x, y, 100, 100, opacity=1
)
# Create textwidget for in window # Create textwidget for in window
pass popup.bordercolor = "#000000"
popup.borderwidth = 1
popup.focus(False)
#popup.
return popup
# window.Internal.create( def despawn_popup(popup):
# qtile, x, y, width, height, opacity=1 """
# ) :type popup: Internal
:param popup: The popup to despawn
"""
popup.kill()
def test_popups(qtile):
popup = spawn_popup(qtile, 10, 10, "Hello World!")
sleep(3)
despawn_popup(popup)
def display_wm_class(qtile): def display_wm_class(qtile):
@ -218,6 +253,17 @@ 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):
status_cmd = "acpi"
def button_press(self, x, y, button):
if button == BUTTON_LEFT:
output = subprocess.check_output(self.status_cmd).decode('utf-8')
notify(
"Battery Status",
output
)
class PulseVolumeWidget(Volume): class PulseVolumeWidget(Volume):

View file

@ -59,7 +59,7 @@ def handle_focus_change(theme):
name = window.name name = window.name
if wm_class: if wm_class:
theme.log_info(str(wm_class)) theme.log_info("{}, {}".format(wm_class, name))
# Check which window we entered and do some special effects if it is a special window. # Check which window we entered and do some special effects if it is a special window.

51
kuro/utils/layouts.py Normal file
View file

@ -0,0 +1,51 @@
from libqtile.layout.wmii import Wmii
class KuroWmii(Wmii):
def cmd_previous(self):
super(KuroWmii, self).cmd_previous()
def cmd_next(self):
super(KuroWmii, self).cmd_next()
def add(self, client):
"""
Add a new client window to the layout and focus it. It will be added to either the current column if there
are less rows in the current column than columns on the screen, or to a new row to the right of the current
column if there are less columns than rows in the current column.
:param client: The client window to add.
"""
self.clients.append(client)
c = self.current_column()
if c is None:
if len(self.columns) == 0:
self.columns = [{'active': 0, 'width': 100, 'mode': 'split', 'rows': []}]
c = self.columns[0]
c['rows'].append(client)
else:
num_cols = len(self.columns)
num_rows_curr_col = len(c['rows'])
if num_rows_curr_col < num_cols:
c['rows'].append(client)
else:
self.add_column_to_right(c, client)
self.focus(client)
def add_column_to_right(self, column, win):
"""
Adds a new column to the right of the given column with the given window in it
:param column: The column that's going to be to the left of the new column
:param win: The window to add to the new column
"""
newwidth = int(100 / (len(self.columns) + 1))
# we are only called if there already is a column, simplifies things
for c in self.columns:
c['width'] = newwidth
c = {'width': newwidth, 'mode': 'split', 'rows': [win]}
try:
index = self.columns.index(column) + 1
except ValueError:
index = 0
self.columns.insert(index, c)