1
0
mirror of https://github.com/alrayyes/dotfiles/ synced 2023-11-14 15:56:30 +00:00

Now use bspwm as window manager

This commit is contained in:
Ryan Kes 2019-12-10 13:40:20 +01:00
parent 4984da8d0b
commit dc3a426d41
24 changed files with 1415 additions and 74 deletions

View File

@ -12,6 +12,7 @@ A repository of my personal configuration files.
./clean-dead-symlinks ./clean-dead-symlinks
#+END_SRC #+END_SRC
** Configured Packages ** Configured Packages
- [[https://github.com/baskerville/bspwm][bspwm]]
- [[https://dunst-project.org/][dunst]] - [[https://dunst-project.org/][dunst]]
- [[https://firejail.wordpress.com/][firejail]] - [[https://firejail.wordpress.com/][firejail]]
- [[https://git-scm.com/][git]] - [[https://git-scm.com/][git]]
@ -33,8 +34,4 @@ A repository of my personal configuration files.
- [[https://github.com/denysdovhan/spaceship-prompt][spaceship zsh - [[https://github.com/denysdovhan/spaceship-prompt][spaceship zsh
theme]] theme]]
** Custom packages ** Custom packages
These are custom packages I use (mostly
[[https://suckless.org/][suckless]]).
- [[https://github.com/alrayyes/dwm][dwm]]
- [[https://github.com/alrayyes/slstatus][slstatus]]
- [[https://github.com/alrayyes/st][st]] - [[https://github.com/alrayyes/st][st]]

78
bspwm/.config/bspwm/bspwmrc Executable file
View File

@ -0,0 +1,78 @@
#! /bin/sh
sxhkd &
# Set screen orientation if second monitor is connected
SCREENCOUNT=$(xrandr | grep -c "\*")
# If multi screen add special mode for monitor so it supports 1440p over HDMI
if [ "$SCREENCOUNT" -eq 2 ]; then
if [ -f "$HOME/.local/bin/screen_desktop" ]; then
screen_desktop
# Make sure mouse is on main screen so windows are launched there
# xdotool mousemove 3360 1080
bspc monitor DP-1 -d 2 3 4 5 6 7 8 9 10
bspc monitor HDMI-2 -d 1
fi
if [ -f "$HOME/.local/bin/polybar-desktop" ]; then
polybar-desktop
fi
else
if [ -f "$HOME/.local/bin/screen" ]; then
screen
fi
if [ -f "$HOME/.local/bin/polybar-laptop" ]; then
bspc monitor -d 1 2 3 4 5 6 7 8 9 0
polybar-laptop
fi
fi
# lock screen after x minutes and on laptop close lid
xautolock -time 10 -locker ~/.local/bin/lock &
xss-lock -- ~/.local/bin/lock &
xcompmgr &
if [ -e ~/.cache/wall1.png ] && [ -e ~/.cache/wall2.png ]; then
xwallpaper --output HDMI-2 --zoom ~/.cache/wall2.png --output DP-1 --zoom ~/.cache/wall1.png &
elif [ -e ~/.cache/wall1.png ]; then
xwallpaper --output eDP1 --zoom ~/.cache/wall1.png &
fi
# switch off microphones
amixer -c 2 set Mic nocap
amixer -c 3 set Mic nocap
unclutter &
dunst &
slstatus &
redshift-gtk &
nm-applet &
syncthing-gtk &
gpodder &
spotify &
if [ -e /usr/bin/firefox ]; then
firefox &
elif [ -e /usr/bin/iceweasel ]; then
iceweasel &
fi
bspc config border_width 2
bspc config window_gap 12
bspc config split_ratio 0.52
bspc config borderless_monocle true
bspc config gapless_monocle true
bspc rule -a "Syncthing GTK" state=floating
bspc rule -a Gimp state=floating
bspc rule -a Gpodder desktop='^4'
bspc rule -a Spotify desktop='^4'
bspc rule -a Slack desktop='^4'
bspc rule -a Emacs state=tiled
bspc rule -a iceweasel desktop='^9'
bspc rule -a Firefox desktop='^9'
bspc rule -a scratchpad sticky=on state=floating
bspc rule -a scratchmacs sticky=on state=floating

2
bspwm/.local/bin/scratch Executable file
View File

@ -0,0 +1,2 @@
#!/usr/bin/sh
st -c scratchpad

View File

@ -11,4 +11,4 @@ export _JAVA_AWT_WM_NONREPARENTING=1
export AWT_TOOLKIT=MToolkit export AWT_TOOLKIT=MToolkit
wmname LG3D wmname LG3D
exec dwm exec bspwm

View File

@ -1,61 +0,0 @@
#!/bin/sh
# Set working directory to home
cd ~
# Set screen orientation if second monitor is connected
SCREENCOUNT=$(xrandr | grep -c "\*")
# If multi screen add special mode for monitor so it supports 1440p over HDMI
if [ "$SCREENCOUNT" -eq 2 ]
then
if [ -f "$HOME/.local/bin/screen_desktop" ]
then
screen_desktop
# Make sure mouse is on main screen so windows are launched there
xdotool mousemove 3360 1080
fi
else
if [ -f "$HOME/.local/bin/screen" ]
then
screen
fi
fi
# lock screen after x minutes and on laptop close lid
xautolock -time 10 -locker ~/.local/bin/lock &
xss-lock -- ~/.local/bin/lock &
xcompmgr &
sxhkd &
if [ -e ~/.cache/wall1.png ] && [ -e ~/.cache/wall2.png ]
then
xwallpaper --output HDMI-2 --zoom ~/.cache/wall2.png --output DP-1 --zoom ~/.cache/wall1.png &
elif [ -e ~/.cache/wall1.png ]
then
xwallpaper --output eDP1 --zoom ~/.cache/wall1.png &
fi
# switch off microphones
amixer -c 2 set Mic nocap
amixer -c 3 set Mic nocap
unclutter &
dunst &
slstatus &
redshift-gtk &
nm-applet &
syncthing-gtk &
gpodder &
exec st -c tmux -e tmux &
exec spotify &
if [ -e /usr/bin/firefox ]
then
exec firefox &
elif [ -e /usr/bin/iceweasel ]
then
exec iceweasel &
fi

View File

@ -0,0 +1,13 @@
# Script: isactive-bluetooth
A script that shows if bluetooth is on or off.
## Module
```ini
[module/isactive-bluetooth]
type = custom/script
exec = ~/polybar-scripts/isactive-bluetooth.sh
interval = 10
```

View File

@ -0,0 +1,7 @@
#!/bin/sh
if [ "$(systemctl is-active bluetooth.service)" = "active" ]; then
echo ""
else
echo ""
fi

View File

@ -0,0 +1,164 @@
# Script: player-mpris-tail
This script displays the current track and the play-pause status without polling. Information is obtained by listening to MPRIS events, so it is updated instantaneously on change.
![player-mpris-tail](screenshots/1.png) ![player-mpris-tail](screenshots/2.png)
## Dependencies
* `python-dbus`
* `python-gobject`
* `python-gi`
## Configuration
The format of the output can be defined by passing an `-f` or `--format` argument. This argument supports metadata replacement using `{tag}` (e.g. `{title}`) as well as more advanced formatting, described below.
Players can be blacklisted by passing a `-b` or `--blacklist` argument. As an example, VLC can be blacklisted by passing `-b vlc`. To get a list of the current running players (and their status), run the script as `player-mpris-tail.py list`.
### Commands
The current player can be controlled by passing one of the following commands:
Command | Description
---|---
play | Play the current track
pause | Pause the currently playing track
play-pause | Play the current track or unpause it if currently paused
stop | Stop playback
previous | Move to the previous track
next | Move to the next track
raise | Tell the current player to focus its window
General information about the current state can be printed using the following commands:
Command | Description
---|---
status | Print the normal output and exit immediately
current | Print the currently detected player and its status
list | List the detected players and their status
metadata | Print the metadata object for the current track
### Arguments
The following arguments are supported:
Argument | Description | Default
---|---|---
-b, --blacklist | Blacklist / Ignore the given player
-f, --format | Use the given `format` string | `{icon} {artist} - {title}`
--truncate-text | Use the given string as the end of truncated text | `…`
--icon-playing | Use the given text as the playing icon | `⏵`
--icon-paused | Use the given text as the paused icon | `⏸`
--icon-stopped | Use the given text as the stopped icon | `⏹`
--icon-none | Use the given text as the icon for when no player is active | ``
### Formatting
Tags can be printed by surrounding them with `{` and `}`. Polybar formatting can also be given and will be passed through, including substituted tags and formatters.
### Tags
The supported tags are:
Tag | Description
---|---
artist | The artist of the current track
album | The album of the current track
title | The title of the current track
track | The track number of the current track
length | The length of the current track
genre | The genre of the current track
disc | The disc number of the current track
date | The date of the current track
year | The year of the current track
cover | The URL of the cover of the current track
icon | The icon for the current status (playing / paused / stopped / none)
icon-reversed | The pause icon when playing, else the play icon
### String formatters
Parts of the `format` string can be manipulated by surrounding them with `{:` and `:}` and prepending a formatter followed by a `:` (e.g. `{:t20:by {artist}:}`)
The following formatters are supported:
Formatter | Argument | Description | Example | Output
---|---|---|---|---
`tag` | | Only print the string if `tag` exists | `{:album: on {album}:}` | ` on Album Name`
w | Number | Limit the width of the string to `number` | `{:w3:Hello:}` | `Hel`
t | Number | Truncate width of the string to `number`. If the string is shorter than or equal to `number` it is printed as given, else the string is truncated and appended a truncator text | `{:t3:Hello:}` | `He…`
## Module
### Basic output
```ini
[module/player-mpris-tail]
type = custom/script
exec = ~/polybar-scripts/player-mpris-tail.py -f '{icon} {artist} - {title}'
tail = true
```
Example: `⏵ Artist - Title`
### Basic output and mouse controls
```ini
[module/player-mpris-tail]
type = custom/script
exec = ~/polybar-scripts/player-mpris-tail.py -f '{icon} {artist} - {title}'
tail = true
click-left = ~/polybar-scripts/player-mpris-tail.py previous &
click-right = ~/polybar-scripts/player-mpris-tail.py next &
click-middle = ~/polybar-scripts/player-mpris-tail.py play-pause &
```
Example: `⏵ Artist - Title`
### Output using formatters
```ini
[module/player-mpris-tail]
type = custom/script
exec = ~/polybar-scripts/player-mpris-tail.py -f '{icon} {:artist:t5:{artist}:}{:artist: - :}{:t4:{title}:}'
tail = true
click-left = ~/polybar-scripts/player-mpris-tail.py previous &
click-right = ~/polybar-scripts/player-mpris-tail.py next &
click-middle = ~/polybar-scripts/player-mpris-tail.py play-pause &
```
Example: `⏵ Artis… - Titl…` or `⏵ Titl…`
### Output using formatters and Polybar action handlers
```ini
[module/player-mpris-tail]
type = custom/script
exec = ~/polybar-scripts/player-mpris-tail.py -f '{icon} {:artist:t18:{artist}:}{:artist: - :}{:t20:{title}:} %{A1:~/polybar-scripts/player-mpris-tail.py previous:} ⏮ %{A} %{A1:~/polybar-scripts/player-mpris-tail.py play-pause:} {icon-reversed} %{A} %{A1:~/polybar-scripts/player-mpris-tail.py next:} ⏭ %{A}'
tail = true
```
Example: `⏵ Artis… - Titl… ⏮ ⏸ ⏭ ` or `⏵ Titl… ⏮ ⏸ ⏭ ` or `⏸ Titl… ⏮ ⏵ ⏭ `
### Output using formatters, Polybar action handlers and blacklisting
```ini
[module/player-mpris-tail]
type = custom/script
exec = ~/polybar-scripts/player-mpris-tail.py -f '{icon} {:artist:t18:{artist}:}{:artist: - :}{:t20:{title}:} %{A1:~/polybar-scripts/player-mpris-tail.py previous -b vlc -b plasma-browser-integration:} ⏮ %{A} %{A1:~/polybar-scripts/player-mpris-tail.py play-pause -b vlc -b plasma-browser-integration:} {icon-reversed} %{A} %{A1:~/polybar-scripts/player-mpris-tail.py next -b vlc -b plasma-browser-integration:} ⏭ %{A}' -b vlc -b plasma-browser-integration
tail = true
```
Example: `⏵ Artis… - Titl… ⏮ ⏸ ⏭ ` or `⏵ Titl… ⏮ ⏸ ⏭ ` or `⏸ Titl… ⏮ ⏵ ⏭ `

View File

@ -0,0 +1,532 @@
#!/usr/bin/env python3
import sys
import dbus
import os
from operator import itemgetter
import argparse
import re
from urllib.parse import unquote
import time
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
DBusGMainLoop(set_as_default=True)
FORMAT_STRING = '{icon} {artist} - {title}'
FORMAT_REGEX = re.compile(r'(\{:(?P<tag>.*?)(:(?P<format>[wt])(?P<formatlen>\d+))?:(?P<text>.*?):\})', re.I)
FORMAT_TAG_REGEX = re.compile(r'(?P<format>[wt])(?P<formatlen>\d+)')
SAFE_TAG_REGEX = re.compile(r'[{}]')
class PlayerManager:
def __init__(self, blacklist = [], connect = True):
self.blacklist = blacklist
self._connect = connect
self._session_bus = dbus.SessionBus()
self.players = {}
self.print_queue = []
self.connected = False
self.player_states = {}
self.refreshPlayerList()
if self._connect:
self.connect()
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
print("interrupt received, stopping…")
def connect(self):
self._session_bus.add_signal_receiver(self.onOwnerChangedName, 'NameOwnerChanged')
self._session_bus.add_signal_receiver(self.onChangedProperties, 'PropertiesChanged',
path = '/org/mpris/MediaPlayer2',
sender_keyword='sender')
def onChangedProperties(self, interface, properties, signature, sender = None):
if sender in self.players:
player = self.players[sender]
# If we know this player, but haven't been able to set up a signal handler
if 'properties_changed' not in player._signals:
# Then trigger the signal handler manually
player.onPropertiesChanged(interface, properties, signature)
else:
# If we don't know this player, get its name and add it
bus_name = self.getBusNameFromOwner(sender)
self.addPlayer(bus_name, sender)
player = self.players[sender]
player.onPropertiesChanged(interface, properties, signature)
def onOwnerChangedName(self, bus_name, old_owner, new_owner):
if self.busNameIsAPlayer(bus_name):
if new_owner and not old_owner:
self.addPlayer(bus_name, new_owner)
elif old_owner and not new_owner:
self.removePlayer(old_owner)
else:
self.changePlayerOwner(bus_name, old_owner, new_owner)
def getBusNameFromOwner(self, owner):
player_bus_names = [ bus_name for bus_name in self._session_bus.list_names() if self.busNameIsAPlayer(bus_name) ]
for player_bus_name in player_bus_names:
player_bus_owner = self._session_bus.get_name_owner(player_bus_name)
if owner == player_bus_owner:
return player_bus_name
def busNameIsAPlayer(self, bus_name):
return bus_name.startswith('org.mpris.MediaPlayer2') and bus_name.split('.')[3] not in self.blacklist
def refreshPlayerList(self):
player_bus_names = [ bus_name for bus_name in self._session_bus.list_names() if self.busNameIsAPlayer(bus_name) ]
for player_bus_name in player_bus_names:
self.addPlayer(player_bus_name)
if self.connected != True:
self.connected = True
self.printQueue()
def addPlayer(self, bus_name, owner = None):
player = Player(self._session_bus, bus_name, owner = owner, connect = self._connect, _print = self.print)
self.players[player.owner] = player
def removePlayer(self, owner):
if owner in self.players:
self.players[owner].disconnect()
del self.players[owner]
# If there are no more players, clear the output
if len(self.players) == 0:
_printFlush(ICON_NONE)
# Else, print the output of the next active player
else:
players = self.getSortedPlayerOwnerList()
if len(players) > 0:
self.players[players[0]].printStatus()
def changePlayerOwner(self, bus_name, old_owner, new_owner):
player = Player(self._session_bus, bus_name, owner = new_owner, connect = self._connect, _print = self.print)
self.players[new_owner] = player
del self.players[old_owner]
# Get a list of player owners sorted by current status and age
def getSortedPlayerOwnerList(self):
players = [
{
'number': int(owner.split('.')[-1]),
'status': 2 if player.status == 'playing' else 1 if player.status == 'paused' else 0,
'owner': owner
}
for owner, player in self.players.items()
]
return [ info['owner'] for info in reversed(sorted(players, key=itemgetter('status', 'number'))) ]
# Get latest player that's currently playing
def getCurrentPlayer(self):
playing_players = [
player_owner for player_owner in self.getSortedPlayerOwnerList()
if
self.players[player_owner].status == 'playing' or
self.players[player_owner].status == 'paused'
]
return self.players[playing_players[0]] if playing_players else None
def print(self, status, player):
self.player_states[player.bus_name] = status
if self.connected:
current_player = self.getCurrentPlayer()
if current_player != None:
_printFlush(self.player_states[current_player.bus_name])
else:
_printFlush(ICON_STOPPED)
else:
self.print_queue.append([status, player])
def printQueue(self):
for args in self.print_queue:
self.print(args[0], args[1])
self.print_queue.clear()
class Player:
def __init__(self, session_bus, bus_name, owner = None, connect = True, _print = None):
self._session_bus = session_bus
self.bus_name = bus_name
self._disconnecting = False
self.__print = _print
self.metadata = {
'artist' : '',
'album' : '',
'title' : '',
'track' : 0
}
self._rate = 1.
self._positionAtLastUpdate = 0.
self._timeAtLastUpdate = time.time()
self._positionTimerRunning = False
self._metadata = None
self.status = 'stopped'
self.icon = ICON_NONE
self.icon_reversed = ICON_PLAYING
if owner is not None:
self.owner = owner
else:
self.owner = self._session_bus.get_name_owner(bus_name)
self._obj = self._session_bus.get_object(self.bus_name, '/org/mpris/MediaPlayer2')
self._properties_interface = dbus.Interface(self._obj, dbus_interface='org.freedesktop.DBus.Properties')
self._introspect_interface = dbus.Interface(self._obj, dbus_interface='org.freedesktop.DBus.Introspectable')
self._media_interface = dbus.Interface(self._obj, dbus_interface='org.mpris.MediaPlayer2')
self._player_interface = dbus.Interface(self._obj, dbus_interface='org.mpris.MediaPlayer2.Player')
self._introspect = self._introspect_interface.get_dbus_method('Introspect', dbus_interface=None)
self._getProperty = self._properties_interface.get_dbus_method('Get', dbus_interface=None)
self._playerPlay = self._player_interface.get_dbus_method('Play', dbus_interface=None)
self._playerPause = self._player_interface.get_dbus_method('Pause', dbus_interface=None)
self._playerPlayPause = self._player_interface.get_dbus_method('PlayPause', dbus_interface=None)
self._playerStop = self._player_interface.get_dbus_method('Stop', dbus_interface=None)
self._playerPrevious = self._player_interface.get_dbus_method('Previous', dbus_interface=None)
self._playerNext = self._player_interface.get_dbus_method('Next', dbus_interface=None)
self._playerRaise = self._media_interface.get_dbus_method('Raise', dbus_interface=None)
self._signals = {}
self.refreshPosition()
self.refreshStatus()
self.refreshMetadata()
if connect:
self.printStatus()
self.connect()
def play(self):
self._playerPlay()
def pause(self):
self._playerPause()
def playpause(self):
self._playerPlayPause()
def stop(self):
self._playerStop()
def previous(self):
self._playerPrevious()
def next(self):
self._playerNext()
def raisePlayer(self):
self._playerRaise()
def connect(self):
if self._disconnecting is not True:
introspect_xml = self._introspect(self.bus_name, '/')
if 'TrackMetadataChanged' in introspect_xml:
self._signals['track_metadata_changed'] = self._session_bus.add_signal_receiver(self.onMetadataChanged, 'TrackMetadataChanged', self.bus_name)
self._signals['seeked'] = self._player_interface.connect_to_signal('Seeked', self.onSeeked)
self._signals['properties_changed'] = self._properties_interface.connect_to_signal('PropertiesChanged', self.onPropertiesChanged)
def disconnect(self):
self._disconnecting = True
for signal_name, signal_handler in list(self._signals.items()):
signal_handler.remove()
del self._signals[signal_name]
def refreshStatus(self):
# Some clients (VLC) will momentarily create a new player before removing it again
# so we can't be sure the interface still exists
try:
self.status = str(self._getProperty('org.mpris.MediaPlayer2.Player', 'PlaybackStatus')).lower()
self.updateIcon()
self.checkPositionTimer()
except dbus.exceptions.DBusException:
self.disconnect()
def refreshMetadata(self):
# Some clients (VLC) will momentarily create a new player before removing it again
# so we can't be sure the interface still exists
try:
self._metadata = self._getProperty('org.mpris.MediaPlayer2.Player', 'Metadata')
self._parseMetadata()
except dbus.exceptions.DBusException:
self.disconnect()
def updateIcon(self):
self.icon = (
ICON_PLAYING if self.status == 'playing' else
ICON_PAUSED if self.status == 'paused' else
ICON_STOPPED if self.status == 'stopped' else
ICON_NONE
)
self.icon_reversed = (
ICON_PAUSED if self.status == 'playing' else
ICON_PLAYING
)
def _print(self, status):
self.__print(status, self)
def _parseMetadata(self):
if self._metadata != None:
artist = _getProperty(self._metadata, 'xesam:artist', [''])
if artist != None and len(artist):
self.metadata['artist'] = re.sub(SAFE_TAG_REGEX, """\1\1""", artist[0])
else:
artists = _getProperty(self._metadata, 'xesam:artists', [''])
if artists != None and len(artists):
# Note: This only grabs the first artist
self.metadata['artist'] = re.sub(SAFE_TAG_REGEX, """\1\1""", artists[0])
else:
self.metadata['artist'] = '';
self.metadata['album'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _getProperty(self._metadata, 'xesam:album', ''))
self.metadata['title'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _getProperty(self._metadata, 'xesam:title', ''))
self.metadata['track'] = _getProperty(self._metadata, 'xesam:trackNumber', '')
length = str(_getProperty(self._metadata, 'xesam:length', ''))
if not len(length):
length = str(_getProperty(self._metadata, 'mpris:length', ''))
if len(length):
self.metadata['length'] = int(length)
else:
self.metadata['length'] = 0
self.metadata['genre'] = _getProperty(self._metadata, 'xesam:genre', '')
self.metadata['disc'] = _getProperty(self._metadata, 'xesam:discNumber', '')
self.metadata['date'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _getProperty(self._metadata, 'xesam:contentCreated', ''))
self.metadata['year'] = re.sub(SAFE_TAG_REGEX, """\1\1""", self.metadata['date'][0:4])
self.metadata['url'] = _getProperty(self._metadata, 'xesam:url', '')
self.metadata['filename'] = os.path.basename(self.metadata['url'])
cover = _getProperty(self._metadata, 'xesam:artUrl', '')
if not len(cover):
cover = _getProperty(self._metadata, 'mpris:artUrl', '')
if len(cover):
self.metadata['cover'] = re.sub(SAFE_TAG_REGEX, """\1\1""", cover)
else:
self.metadata['cover'] = ''
self.metadata['duration'] = _getDuration(self.metadata['length'])
def onMetadataChanged(self, track_id, metadata):
self.refreshMetadata()
self.printStatus()
def onPropertiesChanged(self, interface, properties, signature):
updated = False
if dbus.String('Metadata') in properties:
_metadata = properties[dbus.String('Metadata')]
if _metadata != self._metadata:
self._metadata = _metadata
self._parseMetadata()
updated = True
if dbus.String('PlaybackStatus') in properties:
status = str(properties[dbus.String('PlaybackStatus')]).lower()
if status != self.status:
self.status = status
self.checkPositionTimer()
self.updateIcon()
updated = True
if dbus.String('Rate') in properties and dbus.String('PlaybackStatus') not in properties:
self.refreshStatus()
if NEEDS_POSITION and dbus.String('Rate') in properties:
rate = properties[dbus.String('Rate')]
if rate != self._rate:
self._rate = rate
self.refreshPosition()
if updated:
self.refreshPosition()
self.printStatus()
def checkPositionTimer(self):
if NEEDS_POSITION and self.status == 'playing' and not self._positionTimerRunning:
self._positionTimerRunning = True
GLib.timeout_add_seconds(1, self._positionTimer)
def onSeeked(self, position):
self.refreshPosition()
self.printStatus()
def _positionTimer(self):
self.printStatus()
self._positionTimerRunning = self.status == 'playing'
return self._positionTimerRunning
def refreshPosition(self):
try:
time_us = self._getProperty('org.mpris.MediaPlayer2.Player', 'Position')
except dbus.exceptions.DBusException:
time_us = 0
self._timeAtLastUpdate = time.time()
self._positionAtLastUpdate = time_us / 1000000
def _getPosition(self):
if self.status == 'playing':
return self._positionAtLastUpdate + self._rate * (time.time() - self._timeAtLastUpdate)
else:
return self._positionAtLastUpdate
def _statusReplace(self, match, metadata):
tag = match.group('tag')
format = match.group('format')
formatlen = match.group('formatlen')
text = match.group('text')
tag_found = False
reversed_tag = False
if tag.startswith('-'):
tag = tag[1:]
reversed_tag = True
if format is None:
tag_is_format_match = re.match(FORMAT_TAG_REGEX, tag)
if tag_is_format_match:
format = tag_is_format_match.group('format')
formatlen = tag_is_format_match.group('formatlen')
tag_found = True
if format is not None:
text = text.format_map(CleanSafeDict(**metadata))
if format == 'w':
formatlen = int(formatlen)
text = text[:formatlen]
elif format == 't':
formatlen = int(formatlen)
if len(text) > formatlen:
text = text[:max(formatlen - len(TRUNCATE_STRING), 0)] + TRUNCATE_STRING
if tag_found is False and tag in metadata and len(metadata[tag]):
tag_found = True
if reversed_tag:
tag_found = not tag_found
if tag_found:
return text
else:
return ''
def printStatus(self):
if self.status in [ 'playing', 'paused' ]:
metadata = { **self.metadata, 'icon': self.icon, 'icon-reversed': self.icon_reversed }
if NEEDS_POSITION:
metadata['position'] = time.strftime("%M:%S", time.gmtime(self._getPosition()))
# replace metadata tags in text
text = re.sub(FORMAT_REGEX, lambda match: self._statusReplace(match, metadata), FORMAT_STRING)
# restore polybar tag formatting and replace any remaining metadata tags after that
try:
text = re.sub(r'􏿿p􏿿(.*?)􏿿p􏿿(.*?)􏿿p􏿿(.*?)􏿿p􏿿', r'%{\1}\2%{\3}', text.format_map(CleanSafeDict(**metadata)))
except:
print("Invalid format string")
self._print(text)
else:
self._print(ICON_STOPPED)
def _dbusValueToPython(value):
if isinstance(value, dbus.Dictionary):
return {_dbusValueToPython(key): _dbusValueToPython(value) for key, value in value.items()}
elif isinstance(value, dbus.Array):
return [ _dbusValueToPython(item) for item in value ]
elif isinstance(value, dbus.Boolean):
return int(value) == 1
elif (
isinstance(value, dbus.Byte) or
isinstance(value, dbus.Int16) or
isinstance(value, dbus.UInt16) or
isinstance(value, dbus.Int32) or
isinstance(value, dbus.UInt32) or
isinstance(value, dbus.Int64) or
isinstance(value, dbus.UInt64)
):
return int(value)
elif isinstance(value, dbus.Double):
return float(value)
elif (
isinstance(value, dbus.ObjectPath) or
isinstance(value, dbus.Signature) or
isinstance(value, dbus.String)
):
return unquote(str(value))
def _getProperty(properties, property, default = None):
value = default
if not isinstance(property, dbus.String):
property = dbus.String(property)
if property in properties:
value = properties[property]
return _dbusValueToPython(value)
else:
return value
def _getDuration(t: int):
seconds = t / 1000000
return time.strftime("%M:%S", time.gmtime(seconds))
class CleanSafeDict(dict):
def __missing__(self, key):
return '{{{}}}'.format(key)
"""
Seems to assure print() actually prints when no terminal is connected
"""
_last_status = ''
def _printFlush(status, **kwargs):
global _last_status
if status != _last_status:
print(status, **kwargs)
sys.stdout.flush()
_last_status = status
parser = argparse.ArgumentParser()
parser.add_argument('command', help="send the given command to the active player",
choices=[ 'play', 'pause', 'play-pause', 'stop', 'previous', 'next', 'status', 'list', 'current', 'metadata', 'raise' ],
default=None,
nargs='?')
parser.add_argument('-b', '--blacklist', help="ignore a player by it's bus name. Can be be given multiple times (e.g. -b vlc -b audacious)",
action='append',
metavar="BUS_NAME",
default=[])
parser.add_argument('-f', '--format', default='{icon} {:artist:{artist} - :}{:title:{title}:}{:-title:{filename}:}')
parser.add_argument('--truncate-text', default='')
parser.add_argument('--icon-playing', default='')
parser.add_argument('--icon-paused', default='')
parser.add_argument('--icon-stopped', default='')
parser.add_argument('--icon-none', default='')
args = parser.parse_args()
FORMAT_STRING = re.sub(r'%\{(.*?)\}(.*?)%\{(.*?)\}', r'􏿿p􏿿\1􏿿p􏿿\2􏿿p􏿿\3􏿿p􏿿', args.format)
NEEDS_POSITION = "{position}" in FORMAT_STRING
TRUNCATE_STRING = args.truncate_text
ICON_PLAYING = args.icon_playing
ICON_PAUSED = args.icon_paused
ICON_STOPPED = args.icon_stopped
ICON_NONE = args.icon_none
if args.command is None:
PlayerManager(blacklist = args.blacklist)
else:
player_manager = PlayerManager(blacklist = args.blacklist, connect = False)
current_player = player_manager.getCurrentPlayer()
if args.command == 'play' and current_player:
current_player.play()
elif args.command == 'pause' and current_player:
current_player.pause()
elif args.command == 'play-pause' and current_player:
current_player.playpause()
elif args.command == 'stop' and current_player:
current_player.stop()
elif args.command == 'previous' and current_player:
current_player.previous()
elif args.command == 'next' and current_player:
current_player.next()
elif args.command == 'status' and current_player:
current_player.printStatus()
elif args.command == 'list':
print("\n".join(sorted([
"{} : {}".format(player.bus_name.split('.')[3], player.status)
for player in player_manager.players.values() ])))
elif args.command == 'current' and current_player:
print("{} : {}".format(current_player.bus_name.split('.')[3], current_player.status))
elif args.command == 'metadata' and current_player:
print(_dbusValueToPython(current_player._metadata))
elif args.command == 'raise' and current_player:
current_player.raisePlayer()

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,24 @@
# Script: updates-arch-combined
A script that shows if there are updates for Arch Linux and AUR updates.
See also [updates-arch](../updates-arch) and [updates-arch-aur](../updates-arch-aur).
![updates-arch-combined](screenshots/1.png)
## Dependencies
The possibilities depend on your AUR helper. Not all helpers can report the pending updates.
At the moment `trizen` and `cower` are documented. Take a look at the script to see how it works.
## Module
```ini
[module/updates-arch-combined]
type = custom/script
exec = ~/polybar-scripts/updates-arch-combined.sh
interval = 600
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,16 @@
#!/bin/sh
updates_arch=$(checkupdates | wc -l)
# if ! updates_aur=$(cower -u 2> /dev/null | wc -l); then
if ! updates_aur=$(trizen -Su --aur --quiet | wc -l); then
updates_aur=0
fi
updates=$(("$updates_arch" + "$updates_aur"))
if [ "$updates" -gt 0 ]; then
echo "$updates"
else
echo ""
fi

View File

@ -0,0 +1,422 @@
;=====================================================
;
; To learn more about how to configure Polybar
; go to https://github.com/jaagr/polybar
;
; The README contains alot of information
;
;=====================================================
[colors]
;background = ${xrdb:color0:#222}
background = #222
background-alt = #444
;foreground = ${xrdb:color7:#222}
foreground = #dfdfdf
foreground-alt = #555
primary = #ffb52a
secondary = #e60053
alert = #bd2c40
[bar/base]
width = 100%
height = 27
radius = 6.0
fixed-center = false
background = ${colors.background}
foreground = ${colors.foreground}
line-size = 3
line-color = #f00
border-size = 0
border-color = #00000000
padding-left = 0
padding-right = 2
module-margin-left = 1
module-margin-right = 2
scroll-up = bspwm-desknext
scroll-down = bspwm-deskprev
wm-restack = bspwm
[bar/base-laptop]
inherit = "bar/base"
font-0 = FuraCode Nerd Font:pixelsize=14
[bar/base-desktop]
inherit = "bar/base"
font-0 = FuraCode Nerd Font:pixelsize=10
[bar/laptop-bottom]
inherit = bar/base-laptop
bottom = true
monitor = ${env:MONITOR:e-DP1}
modules-center = mpd player-mpris-tail
[bar/laptop-top]
inherit = bar/base-laptop
monitor = ${env:MONITOR:e-DP1}
modules-left = bspwm
modules-center = tun0 tun1 wlan bluetooth
modules-right = github updates-arch-combined battery xbacklight filesystem volume memory cpu temperature date
tray-position = right
tray-padding = 0
[bar/monitor1]
inherit = bar/base-desktop
monitor = ${env:MONITOR:DP-1}
modules-left = bspwm
modules-center = mpd player-mpris-tail
modules-right = github updates-arch-combined bluetooth eth filesystem volume memory cpu temperature date
tray-position = right
tray-padding = 0
[bar/monitor2]
inherit = bar/base-desktop
monitor = ${env:MONITOR:HDMI-2}
modules-left = bspwm
[module/xwindow]
type = internal/xwindow
label = %title:0:30:...%
[module/xkeyboard]
type = internal/xkeyboard
blacklist-0 = num lock
format-prefix = " "
format-prefix-foreground = ${colors.foreground-alt}
format-prefix-underline = ${colors.secondary}
label-layout = %layout%
label-layout-underline = ${colors.secondary}
label-indicator-padding = 2
label-indicator-margin = 1
label-indicator-background = ${colors.secondary}
label-indicator-underline = ${colors.secondary}
[module/filesystem]
type = internal/fs
interval = 25
mount-0 = /
mount-1 = /home
label-mounted = %{F#0a81f5}%mountpoint%%{F-}: %percentage_used%%
label-unmounted = %mountpoint% not mounted
label-unmounted-foreground = ${colors.foreground-alt}
[module/bspwm]
type = internal/bspwm
label-focused-background = ${colors.background-alt}
label-focused-underline= ${colors.primary}
label-focused-padding = 2
label-occupied-padding = 2
label-urgent-background = ${colors.alert}
label-urgent-padding = 2
label-empty-foreground = ${colors.foreground-alt}
label-empty-padding = 2
pin-workspaces = true
[module/mpd]
type = internal/mpd
format-online = <label-song> <icon-prev> <icon-stop> <toggle> <icon-next>
icon-prev = 
icon-stop = 
icon-play = 
icon-pause = 
icon-next = 
label-song-maxlen = 25
label-song-ellipsis = true
[module/xbacklight]
type = internal/xbacklight
format = <label> <bar>
label = 
bar-width = 10
bar-indicator = |
bar-indicator-foreground = #ff
bar-indicator-font = 2
bar-fill = ─
bar-fill-font = 2
bar-fill-foreground = #9f78e1
bar-empty = ─
bar-empty-font = 2
bar-empty-foreground = ${colors.foreground-alt}
[module/backlight-acpi]
inherit = module/xbacklight
type = internal/backlight
card = intel_backlight
[module/cpu]
type = internal/cpu
interval = 2
format-prefix = " "
format-prefix-foreground = ${colors.foreground-alt}
format-underline = #f90000
label = %percentage:2%%
format = <label> <ramp-coreload>
ramp-coreload-0 = ▁
ramp-coreload-1 = ▂
ramp-coreload-2 = ▃
ramp-coreload-3 = ▄
ramp-coreload-4 = ▅
ramp-coreload-5 = ▆
ramp-coreload-6 = ▇
ramp-coreload-7 = █
[module/memory]
type = internal/memory
interval = 2
format-prefix = " "
format-prefix-foreground = ${colors.foreground-alt}
format-underline = #4bffdc
label = %percentage_used%%
ramp-used-0 = ▁
ramp-used-1 = ▂
ramp-used-2 = ▃
ramp-used-3 = ▄
ramp-used-4 = ▅
ramp-used-5 = ▆
ramp-used-6 = ▇
ramp-used-7 = █
[module/wlan]
type = internal/network
interface = wlp4s0
interval = 3.0
format-connected = <ramp-signal> <label-connected>
format-packetloss = <animation-packetloss> <label-connected>
format-disconnected =
format-connected-underline = #55aa55
format-connected-prefix = " "
label-connected = "%essid% %signal% %downspeed:8% %upspeed:8%"
ramp-signal-0 = ▁
ramp-signal-1 = ▂
ramp-signal-2 = ▃
ramp-signal-3 = ▄
ramp-signal-4 = ▅
ramp-signal-5 = ▆
ramp-signal-6 = ▇
ramp-signal-7 = █
animation-packetloss-0 = ⚠
animation-packetloss-1 = 📶
; Framerate in milliseconds
animation-packetloss-framerate = 500
[module/tun0]
type = internal/network
interface = tun0
interval = 3.0
format-connected-underline = #55aa55
format-connected-prefix = "嬨 "
label-connected = "%ifname%"
[module/tun1]
type = internal/network
interface = tun1
interval = 3.0
format-connected-underline = #55aa55
format-connected-prefix = "嬨 "
label-connected = "%ifname%"
[module/eth]
type = internal/network
interface = eno1
interval = 3.0
format-connected-underline = #55aa55
format-connected-prefix = " "
format-connected-prefix-foreground = ${colors.foreground-alt}
label-connected = "%local_ip% %downspeed% %upspeed%"
format-disconnected =
;format-disconnected = <label-disconnected>
;format-disconnected-underline = ${self.format-connected-underline}
;label-disconnected = %ifname% disconnected
;label-disconnected-foreground = ${colors.foreground-alt}
[module/date]
type = internal/date
interval = 5
date =
date-alt = " %d-%m-%Y"
time = %H:%M
time-alt = %H:%M:%S
format-prefix = 
format-prefix-foreground = ${colors.foreground-alt}
format-underline = #0a6cf5
label = %date% %time%
[module/volume]
type = internal/alsa
format-volume = <label-volume> <bar-volume>
label-volume = 蓼
label-volume-foreground = ${root.foreground}
format-muted-prefix = " "
format-muted-foreground = ${colors.foreground-alt}
label-muted = sound muted
bar-volume-width = 10
bar-volume-foreground-0 = #55aa55
bar-volume-foreground-1 = #55aa55
bar-volume-foreground-2 = #55aa55
bar-volume-foreground-3 = #55aa55
bar-volume-foreground-4 = #55aa55
bar-volume-foreground-5 = #f5a70a
bar-volume-foreground-6 = #ff5555
bar-volume-gradient = false
bar-volume-indicator = |
bar-volume-indicator-font = 2
bar-volume-fill = ─
bar-volume-fill-font = 2
bar-volume-empty = ─
bar-volume-empty-font = 2
bar-volume-empty-foreground = ${colors.foreground-alt}
[module/battery]
type = internal/battery
battery = BAT0
adapter = ADP1
full-at = 98
format-charging = <animation-charging> <label-charging>
format-charging-underline = #ffb52a
format-discharging = <ramp-capacity> <label-discharging>
format-discharging-underline = ${self.format-charging-underline}
format-full-prefix = " "
format-full-prefix-foreground = ${colors.foreground-alt}
format-full-underline = ${self.format-charging-underline}
ramp-capacity-0 = 
ramp-capacity-1 = 
ramp-capacity-2 = 
ramp-capacity-foreground = ${colors.foreground-alt}
animation-charging-0 = 
animation-charging-1 = 
animation-charging-2 = 
animation-charging-foreground = ${colors.foreground-alt}
animation-charging-framerate = 750
[module/temperature]
type = internal/temperature
thermal-zone = 0
warn-temperature = 60
format = <ramp> <label>
format-underline = #f50a4d
format-warn = <ramp> <label-warn>
format-warn-underline = ${self.format-underline}
label = %temperature-c%
label-warn = %temperature-c%
label-warn-foreground = ${colors.secondary}
ramp-0 = 
ramp-1 = 
ramp-2 = 
ramp-foreground = ${colors.foreground-alt}
[module/powermenu]
type = custom/menu
expand-right = true
format-spacing = 1
label-open = 
label-open-foreground = ${colors.secondary}
label-close =  cancel
label-close-foreground = ${colors.secondary}
label-separator = |
label-separator-foreground = ${colors.foreground-alt}
menu-0-0 = reboot
menu-0-0-exec = menu-open-1
menu-0-1 = power off
menu-0-1-exec = menu-open-2
menu-1-0 = cancel
menu-1-0-exec = menu-open-0
menu-1-1 = reboot
menu-1-1-exec = sudo reboot
menu-2-0 = power off
menu-2-0-exec = sudo poweroff
menu-2-1 = cancel
menu-2-1-exec = menu-open-0
[module/github]
type = internal/github
token = ${file:~/.github-access-token}
format = <label>
label = " %notifications%"
[module/updates-arch-combined]
type = custom/script
exec = /bin/sh ~/.config/polybar/bin/updates-arch-combined/updates-arch-combined.sh
interval = 600
[module/player-mpris-tail]
type = custom/script
exec = python ~/.config/polybar/bin/player-mpris-tail/player-mpris-tail.py
tail = true
click-left = /bin/sh ~/.config/polybar/bin/player-mpris-tail/player-ctrl.sh previous
click-right = /bin/sh ~/.config/polybar/bin/player-mpris-tail/player-ctrl.sh next
click-middle = /bin/sh ~/.config/polybar/bin/player-mpris-tail/player-ctrl.sh play-pause
[module/bluetooth]
type = custom/script
exec = /bin/sh ~/.config/polybar/bin/isactive-bluetooth/isactive-bluetooth.sh
[settings]
screenchange-reload = true
;compositing-background = xor
;compositing-background = screen
;compositing-foreground = source
;compositing-border = over
[global/wm]
margin-top = 5
margin-bottom = 5
; vim:ft=dosini

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Terminate already running bar instances
killall -q polybar
# Wait until the processes have been shut down
while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
# Launch bar1 and bar2
polybar monitor1 &
polybar monitor2 &
echo "Bars launched..."

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Terminate already running bar instances
killall -q polybar
# Wait until the processes have been shut down
while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
# Launch bar1 and bar2
polybar laptop-top &
polybar laptop-bottom &
echo "Bars launched..."

View File

@ -36,10 +36,6 @@ super + z
super + c super + c
yubikey-oath-dmenu --clipboard clipboard --notify yubikey-oath-dmenu --clipboard clipboard --notify
# dmenu application launcher
super + p
dmenu-frecency
# Wireguard # Wireguard
super + w super + w
vpn-switch vpn-switch
@ -54,6 +50,128 @@ XF86Eject
shift + XF86Eject shift + XF86Eject
prompt "Reboot computer?" "sudo -A shutdown -r now" prompt "Reboot computer?" "sudo -A shutdown -r now"
# Open frequent apps # scratchpad
super + o ; {e,w,m,v,h,s,i,n,q,c} alt + {s,e}
{emacs, $TERMINAL -e weather, $TERMINAL -e neomutt, $TERMINAL -e vifm, $TERMINAL -e htop, slack, $TERMINAL -e weechat, $TERMINAL -e newsboat, qtpass, $TERMINAL -e calendar} tdrop -ma -w -4 {-s dropdown st -c scratchpad,emacs}
#
# BSPWM
#
# terminal emulator
super + Return
$TERMINAL
# program launcher
super + @space
dmenu-frecency
# make sxhkd reload its configuration files:
super + Escape
pkill -USR1 -x sxhkd
#
# bspwm hotkeys
#
# quit/restart bspwm
super + alt + {q,r}
bspc {quit,wm -r}
# close and kill
super + {_,shift + }w
bspc node -{c,k}
# alternate between the tiled and monocle layout
super + m
bspc desktop -l next
# send the newest marked node to the newest preselected node
super + y
bspc node newest.marked.local -n newest.!automatic.local
# swap the current node and the biggest node
super + g
bspc node -s biggest
#
# state/flags
#
# set the window state
super + {t,shift + t,s,f}
bspc node -t {tiled,pseudo_tiled,floating,fullscreen}
# set the node flags
super + ctrl + {m,x,y,z}
bspc node -g {marked,locked,sticky,private}
#
# focus/swap
#
# focus the node in the given direction
super + {_,shift + }{h,j,k,l}
bspc node -{f,s} {west,south,north,east}
# focus the node for the given path jump
super + {p,b,comma,period}
bspc node -f @{parent,brother,first,second}
# focus the next/previous node in the current desktop
super + {_,shift + }c
bspc node -f {next,prev}.local
# focus the next/previous desktop in the current monitor
super + bracket{left,right}
bspc desktop -f {prev,next}.local
# focus the last node/desktop
super + {grave,Tab}
bspc {node,desktop} -f last
# focus the older or newer node in the focus history
super + {o,i}
bspc wm -h off; \
bspc node {older,newer} -f; \
bspc wm -h on
# focus or send to the given desktop
super + {_,shift + }{1-9,0}
bspc {desktop -f,node -d} '^{1-9,10}'
#
# preselect
#
# preselect the direction
super + ctrl + {h,j,k,l}
bspc node -p {west,south,north,east}
# preselect the ratio
super + ctrl + {1-9}
bspc node -o 0.{1-9}
# cancel the preselection for the focused node
super + ctrl + space
bspc node -p cancel
# cancel the preselection for the focused desktop
super + ctrl + shift + space
bspc query -N -d | xargs -I id -n 1 bspc node id -p cancel
#
# move/resize
#
# expand a window by moving one of its side outward
super + alt + {h,j,k,l}
bspc node -z {left -20 0,bottom 0 20,top 0 -20,right 20 0}
# contract a window by moving one of its side inward
super + alt + shift + {h,j,k,l}
bspc node -z {right -20 0,top 0 20,bottom 0 -20,left 20 0}
# move a floating window
super + {Left,Down,Up,Right}
bspc node -v {-20 0,0 20,0 -20,20 0}

View File

@ -75,10 +75,13 @@ export EDITOR="nvim"
# Enable password store extensions # Enable password store extensions
export PASSWORD_STORE_ENABLE_EXTENSIONS="true" export PASSWORD_STORE_ENABLE_EXTENSIONS="true"
# This needs to be set for bspwm to see config
export XDG_CONFIG_HOME="$HOME/.config"
# Save history file in proper place # Save history file in proper place
HISTFILE=~/.cache/zsh/history HISTFILE=~/.cache/zsh/history
-# Use alternative muhome # Us alternative muhome
export MU_HOME="/home/alrayyes/.cache/mu" export MU_HOME="/home/alrayyes/.cache/mu"
# Needed to get zsh to play nice with emacs vterm # Needed to get zsh to play nice with emacs vterm