Initial i3 configuration

This is derived from my Awesome configuration. Still a lot to do from
a WM perspective. The organization is a bit different and I am giving
it up on the per-display systemd units as it does not really work due
to the fact we only have one user DBus and one environment.
This commit is contained in:
Vincent Bernat 2021-07-03 14:13:56 +02:00
parent d3af9e4890
commit d85a504c53
95 changed files with 383 additions and 3116 deletions

View file

@ -1,78 +0,0 @@
# Vincent Bernat's awesome configuration
This is my [awesome](http://awesome.naquadah.org) configuration. It
does not exactly feature the same keybindings as the default
configuration. I don't recommend using it by you can pick anything you
need in it.
This configuration is for _awesome_ 3.4. I did not update to 3.5
yet. Have a look at
[@P-EB pull request](https://github.com/vincentbernat/awesome-configuration/pull/5)
for 3.5 support.
Here some of the things you may be interested in:
- It is modular. I am using `config` as a table to pass different
things between "modules".
- I use a light transparency effect to tell if a window has the focus
or not. It needs a composite manager.
- I use a Python script `bin/build-wallpaper` to build the wallpaper
to be displayed. There is a random selection and it works with
multihead setup. It seems that classic tools are now able to change
the wallpaper per screen and therefore, the script may seem a bit
useless but I keep it.
- I am using `xss-lock` with `i3lock` as a screensaver. It relies on
standard X screensaver handling (and therefore is easy for
application to disable) and also supports systemd
inhibitors. Nothing fancy but I reuse the wallpaper built above. A
notification is sent 10 seconds before starting.
- In `rc/apparance.lua`, you may be interested by the way I configure
GTK2 and GTK3 to have an unified look. It works and it does not
need `gnome-control-center`.
- I have rebuilt my own implementation of the Quake console in
`lib/quake.lua`. The common ones didn't like when awesome was
restarted.
- I am using notifications when changing volume or brightness. I am
also using notifications to change xrandr setup. This is pretty
cool.
- Keybindings are "autodocumented". See `lib/keydoc.lua` to see how
this works. The list of key bindings can be accessed with Mod4 +
F1.
- On the debug front, I am quite happy with `dbg()` in
`rc/debug.lua`.
- Many stuff is handled by systemd. The session is still expected to
be handled by Xsession but we invoke a custom display-specific
`xsession@.target` which binds to a display-specific
`graphical-session@.target`. This is different from the
`graphical-session.target` shipped by distributions because I
wanted it to be display-specific. Also, unit activation is bundled
directly into `graphical-session@.target` while dependencies are
mostly handled in `awesome@.service`.
Also, I am using my custom terminal (`vbeterm`). You need to change
that in `rc.lua`. You can also find the sources on
[GitHub](https://github.com/vincentbernat/vbeterm).
Things in `lib/` are meant to be reused. I am using my own `loadrc()`
function to load modules and therefore, I prefix my modules with
`vbe/`. Before reusing a module, you may want to change this. Another
way to load them is to use:
require("lib/quake")
local quake = package.loaded["vbe/quake"]
## Requirements
Required Debian packages to make everything work can be found in my
[Puppet configuration][].
[Puppet configuration]: https://github.com/vincentbernat/puppet-workstation/blob/master/local-modules/desktop/manifests/awesome.pp

View file

@ -9,8 +9,8 @@ name="$4"
# Load the given keymap
xkb() {
xkbcomp -i ${device} -w 0 -I$HOME/.config/awesome/xkb \
$HOME/.config/awesome/xkb/$1.xkb ${DISPLAY}
xkbcomp -i ${device} -w 0 -I$HOME/.config/i3/dotfiles/xkb \
$HOME/.config/i3/dotfiles/xkb/$1.xkb ${DISPLAY}
}
case $event in
@ -30,7 +30,7 @@ case "$event,$use,$(uname -n),$name" in
done
;;
*,XISlaveKeyboard,zoro,"AT Translated Set 2 keyboard")
xkb x1
xkb x1gen2
;;
*,XISlaveKeyboard,*,"ThinkPad Extra Buttons")
xkb thinkpad-extra

View file

@ -33,15 +33,12 @@ xrandr --dpi $dpi
# Build xsettingsd
{
cat ~/.config/awesome/xsettingsd
cat ~/.config/i3/xsettingsd
echo Xft/DPI $(( $dpi*1024 ))
echo Xft/RGBA \"$( [ $dpi -gt 144 ] && echo none || echo rgb )\"
echo Gdk/WindowScalingFactor $(( $dpi/96 ))
echo Gdk/UnscaledDPI $(( $dpi*1024/($dpi/96) ))
} > ~/.xsettingsd
# Signal xsettingsd
systemctl --user reload xsettingsd@$(systemd-escape -- "$DISPLAY").service
# Also use xrdb for very old stuff (you know, LibreOffice)
echo Xft.dpi: $dpi | xrdb -merge

View file

@ -40,7 +40,7 @@ case "$1" in
# First, pause any music player
playerctl -a pause
# Then, lock screen
i3lock -n -e -i $HOME/.cache/awesome/current-wallpaper-${display}.png -t -f
i3lock -n -e -i $HOME/.cache/i3/current-wallpaper.png -t -f
echo "lock: unlock screen"
;;
esac

119
config Normal file
View file

@ -0,0 +1,119 @@
# i3 config file (v4)
set $up k
set $down j
set $left h
set $right l
set $mod Mod4
set $term vbeterm
font pango:Terminus 9
# Style
default_border pixel 3
default_floating_border pixel 3
# Use pactl to adjust volume in PulseAudio.
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10%
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10%
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle
bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle
# use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
# start a terminal
bindsym $mod+Return exec $term
# kill focused window
bindsym $mod+x kill
# execute command
bindsym $mod+r exec --no-startup-id dmenu_run
# change focus
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
bindsym $mod+$right focus right
# move focused window
bindsym $mod+Shift+$left move left
bindsym $mod+Shift+$down move down
bindsym $mod+Shift+$up move up
bindsym $mod+Shift+$right move right
# resize focused window
bindsym $mod+Ctrl+$left resize shrink width 10 px or 10 ppt
bindsym $mod+Ctrl+$down resize grow height 10 px or 10 ppt
bindsym $mod+Ctrl+$up resize shrink height 10 px or 10 ppt
bindsym $mod+Ctrl+$right resize grow width 10 px or 10 ppt
# change split orientation
bindsym $mod+v split toggle
# enter fullscreen mode for the focused container
bindsym $mod+f fullscreen toggle
# change container layout (stacked, tabbed, toggle split)
bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# toggle tiling / floating
bindsym $mod+Shift+space floating toggle
# change focus between tiling / floating windows
bindsym $mod+space focus mode_toggle
# focus the parent container
bindsym $mod+a focus parent
# Define names for default workspaces for which we configure key bindings later on.
# We use variables to avoid repeating the names in multiple places.
set $ws1 "1"
set $ws2 "2"
set $ws3 "3"
set $ws4 "4"
set $ws5 "5"
set $ws6 "6"
set $ws7 "7"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10"
# switch to workspace
bindsym $mod+1 workspace number $ws1
bindsym $mod+2 workspace number $ws2
bindsym $mod+3 workspace number $ws3
bindsym $mod+4 workspace number $ws4
bindsym $mod+5 workspace number $ws5
bindsym $mod+6 workspace number $ws6
bindsym $mod+7 workspace number $ws7
bindsym $mod+8 workspace number $ws8
bindsym $mod+9 workspace number $ws9
bindsym $mod+0 workspace number $ws10
bindsym $mod+Tab workspace back_and_forth
# move focused container to workspace
bindsym $mod+Shift+1 move container to workspace number $ws1
bindsym $mod+Shift+2 move container to workspace number $ws2
bindsym $mod+Shift+3 move container to workspace number $ws3
bindsym $mod+Shift+4 move container to workspace number $ws4
bindsym $mod+Shift+5 move container to workspace number $ws5
bindsym $mod+Shift+6 move container to workspace number $ws6
bindsym $mod+Shift+7 move container to workspace number $ws7
bindsym $mod+Shift+8 move container to workspace number $ws8
bindsym $mod+Shift+9 move container to workspace number $ws9
bindsym $mod+Shift+0 move container to workspace number $ws10
# reload/restart
bindsym $mod+Shift+c reload
bindsym $mod+Shift+r restart
# Lock screen
bindsym XF86ScreenSaver exec --no-startup-id xset s activate
bindsym $mod+Delete exec --no-startup-id xset s activate
# start stuff
exec_always --no-startup-id systemctl --user start --no-block wallpaper.service

27
dotfiles/gtkrc-2.0 Normal file
View file

@ -0,0 +1,27 @@
gtk-theme-name="Adwaita-dark"
gtk-icon-theme-name="Adwaita"
gtk-cursor-theme-name="Adwaita"
gtk-cursor-theme-size=0
gtk-font-name="DejaVu Sans 10"
gtk-button-images=1
gtk-menu-images=1
gtk-fallback-icon-theme="gnome"
gtk-toolbar-style=GTK_TOOLBAR_BOTH
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
gtk-decoration-layout=":menu"
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle="hintslight"
gtk-xft-rgba="rgb"
gtk-key-theme-name="Emacs"
binding "vbe-text-entry-bindings" {
unbind "<ctrl>b"
unbind "<shift><ctrl>b"
unbind "<ctrl>f"
unbind "<shift><ctrl>f"
unbind "<ctrl>w"
bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
}
class "GtkEntry" binding "vbe-text-entry-bindings"
class "GtkTextView" binding "vbe-text-entry-bindings"

44
dotfiles/gtkrc-3.0 Normal file
View file

@ -0,0 +1,44 @@
/* Useless: we cannot override properly by unbinding some keys */
/* @import url("/usr/share/themes/Emacs/gtk-3.0/gtk-keys.css"); */
@binding-set custom-text-entry
{
bind "<alt>b" { "move-cursor" (words, -1, 0) };
bind "<shift><alt>b" { "move-cursor" (words, -1, 1) };
bind "<alt>f" { "move-cursor" (words, 1, 0) };
bind "<shift><alt>f" { "move-cursor" (words, 1, 1) };
bind "<ctrl>a" { "move-cursor" (paragraph-ends, -1, 0) };
bind "<shift><ctrl>a" { "move-cursor" (paragraph-ends, -1, 1) };
bind "<ctrl>e" { "move-cursor" (paragraph-ends, 1, 0) };
bind "<shift><ctrl>e" { "move-cursor" (paragraph-ends, 1, 1) };
bind "<ctrl>y" { "paste-clipboard" () };
bind "<ctrl>d" { "delete-from-cursor" (chars, 1) };
bind "<alt>d" { "delete-from-cursor" (word-ends, 1) };
bind "<ctrl>k" { "delete-from-cursor" (paragraph-ends, 1) };
bind "<alt>backslash" { "delete-from-cursor" (whitespace, 1) };
bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) };
bind "<alt>space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
bind "<alt>KP_Space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
}
entry, textview
{
-gtk-key-bindings: custom-text-entry;
}
.window-frame, .window-frame:backdrop {
box-shadow: 0 0 0 black;
border-style: none;
margin: 0;
border-radius: 0;
}
.titlebar {
border-radius: 0;
}

9
dotfiles/qt5ct.conf Normal file
View file

@ -0,0 +1,9 @@
[Appearance]
custom_palette=false
icon_theme=Adwaita
standard_dialogs=gtk3
style=Adwaita-dark
[Fonts]
fixed=@Variant(\0\0\0@\0\0\0 \0\x44\0\x65\0j\0\x61\0V\0u\0 \0S\0\x61\0n\0s\0 \0M\0o\0n\0o@$\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)
general=@Variant(\0\0\0@\0\0\0\x16\0\x44\0\x65\0j\0\x61\0V\0u\0 \0S\0\x61\0n\0s@$\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)

View file

@ -1,9 +1,8 @@
[Unit]
Description=Configure monitors on %I
PartOf=graphical-session@%i.target
Description=Configure monitors
PartOf=graphical-session.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/autorandr --change --default default
LimitCORE=infinity
Type=oneshot

View file

@ -0,0 +1,14 @@
[Unit]
Description=i3 window manager
PartOf=graphical-session.target
After=autorandr.service
After=picom.service
After=xsettingsd.service
After=tmux.service
After=ssh-agent.service
Before=wallpaper.service
[Service]
ExecStart=/usr/bin/i3
ExecStopPost=/bin/systemctl --user stop graphical-session.target
Restart=on-failure

View file

@ -0,0 +1,8 @@
[Unit]
Description=XInput event monitor
PartOf=graphical-session.target
[Service]
ExecStartPre=/usr/bin/setxkbmap us
ExecStart=%h/.local/bin/inputplug -d -0 -c %h/.config/i3/bin/input-event
Restart=on-failure

View file

@ -0,0 +1,11 @@
[Unit]
Description=Miscellaneous settings for X11
PartOf=graphical-session.target
After=ssh-agent.service
[Service]
ExecStart=/usr/bin/xset -b
ExecStart=/usr/bin/xsetroot -cursor_name left_ptr
ExecStart=%h/.config/i3/bin/ssh-add
Type=oneshot
RemainAfterExit=false

View file

@ -0,0 +1,12 @@
[Unit]
Description=Compositor for X11
PartOf=graphical-session.target
[Service]
ExecStart=/usr/bin/picom --backend glx \
--xrender-sync-fence \
--vsync \
--opacity-rule 100:fullscreen \
--opacity-rule 85:!fullscreen \
--opacity-rule 100:focused
Restart=on-failure

View file

@ -1,8 +1,7 @@
[Unit]
Description=PolicyKit authentication agent on %I
PartOf=graphical-session@%i.target
Description=PolicyKit authentication agent
PartOf=graphical-session.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1
Restart=on-failure

View file

@ -1,8 +1,7 @@
[Unit]
Description=Set color temperature on %I
PartOf=graphical-session@%i.target
Description=Set color temperature
PartOf=graphical-session.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/redshift -l manual:lon=2.35:lat=48.87 -t 6500:3900
Restart=on-failure

View file

@ -0,0 +1,12 @@
[Unit]
Description=SSH key agent
Wants=dbus.socket
After=dbus.socket
[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStartPre=/usr/bin/dbus-update-activation-environment --systemd SSH_AUTH_SOCK
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
ExecStopPost=/usr/bin/dbus-update-activation-environment --systemd SSH_AUTH_SOCK=
Restart=always

View file

@ -0,0 +1,14 @@
[Unit]
Description=Build and display wallpaper
PartOf=graphical-session.target
[Service]
Environment=WALLPAPER_DIRECTORY=%h/.config/i3/wallpapers
Environment=WALLPAPER_OUTPUT=%h/.cache/i3/current-wallpaper.png
ExecStart=/usr/bin/mkdir -p %h/.cache/i3
ExecStart=%h/.config/i3/bin/build-wallpaper --crop \
--directory $WALLPAPER_DIRECTORY \
--target $WALLPAPER_OUTPUT
ExecStart=/usr/bin/fvwm-root -r $WALLPAPER_OUTPUT
Type=oneshot
RemainAfterExit=false

View file

@ -0,0 +1,7 @@
[Unit]
Description=Wallpaper rotation
PartOf=graphical-session.target
[Timer]
OnUnitActiveSec=2h
RandomizedDelaySec=10m

View file

@ -0,0 +1,7 @@
[Unit]
Description=X color management
PartOf=graphical-session.target
[Service]
ExecStart=/usr/bin/xiccd --edid
Restart=on-failure

View file

@ -0,0 +1,17 @@
[Unit]
Description=X session
BindsTo=graphical-session.target
Wants=autorandr.service
Wants=i3.service
Wants=picom.service
Wants=inputplug.service
Wants=misc-x.service
Wants=policykit-agent.service
Wants=redshift.service
Wants=wallpaper.timer
Wants=xiccd.service
Wants=xsettingsd.service
Wants=xss-lock.service
Wants=tmux.service
Wants=ssh-agent.service
Wants=pulseaudio.service

View file

@ -0,0 +1,11 @@
[Unit]
Description=XSETTINGS daemon
PartOf=graphical-session.target
[Service]
Environment=SKIP_RELOAD=1
ExecStartPre=%h/.config/i3/bin/xsettingsd-setup
ExecStart=/usr/bin/xsettingsd -c %h/.xsettingsd
ExecReload=%h/.config/i3/bin/xsettingsd-setup
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=on-failure

View file

@ -0,0 +1,7 @@
[Unit]
Description=Manage X screen saver
PartOf=graphical-session.target
[Service]
ExecStart=%h/.config/i3/bin/xss-lock start
Restart=on-failure

View file

@ -16,6 +16,6 @@ xkb_keymap {
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+inet(evdev)"
include "compose(ralt)+ctrl(nocaps)"
include "vbe(x1)" };
include "vbe(x1gen2)" };
xkb_geometry { include "pc(pc105)" };
};

38
dotfiles/xsession Normal file
View file

@ -0,0 +1,38 @@
#!/bin/sh
# Ensure we use the appropriate gtkrc-2.0 file
export GTK2_RC_FILES=$HOME/.gtkrc-2.0
# We do not want to rely on crappy mailcap
export MAILCAPS=$HOME/.mailcap
# Make QT automatically scale according to screen DPI
export QT_AUTO_SCREEN_SCALE_FACTOR=1
export QT_QPA_PLATFORMTHEME=qt5ct
# GTK3 apps try to contact org.a11y.Bus. Disable that.
export NO_AT_BRIDGE=1
# Environment variables
unset LC_ALL
[ -e ~/.zshenv ] && . ~/.zshenv
# Copy some configuration files
while read source target; do
for t in $target; do
mkdir -p $(dirname $HOME/$t)
ln -nsf ~/.config/i3/dotfiles/$source $HOME/$t
done
done <<EOF
Xresources .Xresources
gtkrc-2.0 .gtkrc-2.0
gtkrc-3.0 .config/gtk-3.0/settings.ini
qt5ct.conf .config/qt5ct/qt5ct.conf
systemd .config/systemd/user
firefox.js .mozilla/firefox/*/user.js
EOF
# Services are started with systemd
systemctl --user import-environment
systemctl --user daemon-reload
exec systemctl --user start --wait xsession.target

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

View file

@ -1,41 +0,0 @@
-- Handle brightness (with brightnessctl)
local awful = require("awful")
local naughty = require("naughty")
local math = math
local tonumber = tonumber
local string = string
local os = os
local dbg = dbg
-- A bit odd, but...
require("lib/icons")
local icons = package.loaded["vbe/icons"]
module("vbe/brightness")
local nid = nil
local function change(value)
-- Set new value
os.execute("brightnessctl -m s " .. value)
-- Get and display current value
current = awful.util.pread("brightnessctl -m i")
current = tonumber(string.match(current, ",(%d+)%%,"))
local icon = icons.lookup({name = "display-brightness",
type = "status"})
nid = naughty.notify({ text = string.format("%3d %%", current),
icon = icon,
font = "Free Sans Bold 24",
replaces_id = nid }).id
end
function increase()
change("5%+")
end
function decrease()
change("5%-")
end

View file

@ -1,63 +0,0 @@
-- Lookup function for icons
local paths = {
"/usr/share/icons/Adwaita",
"/usr/share/icons/gnome",
"/usr/share/icons/hicolor",
"/usr/share/icons/HighContrast",
"/usr/share/fvwm-crystal/fvwm/icons/Default",
}
local sizes = {
'32x32',
'24x24',
'22x22',
'16x16',
}
local types = {
'apps',
'actions',
'devices',
'status',
}
local formats = {
".png",
".xpm"
}
local assert = assert
local type = type
local pairs = pairs
local awful = require("awful")
module("vbe/icons")
-- Lookup for an icon. Return full path.
function lookup(arg)
local inames = assert(arg.name)
local isizes = arg.size or sizes
local itypes = arg.type or types
local ipaths = paths
local iformats = formats
if type(isizes) ~= "table" then isizes = { isizes } end
if type(itypes) ~= "table" then itypes = { itypes } end
if type(inames) ~= "table" then inames = { inames } end
for _, path in pairs(ipaths) do
for _, size in pairs(isizes) do
for _, t in pairs(itypes) do
for _, name in pairs(inames) do
if name then
for _, name in pairs({name, name:lower()}) do
for _, ext in pairs(iformats) do
local icon = path .. "/" .. size .. "/" .. t .. "/" .. name .. ext
if awful.util.file_readable(icon) then
return icon
end
end
end
end
end
end
end
end
end

View file

@ -1,124 +0,0 @@
-- Document key bindings
local awful = require("awful")
local table = table
local ipairs = ipairs
local pairs = pairs
local math = math
local string = string
local type = type
local modkey = modkey
local beautiful = require("beautiful")
local naughty = require("naughty")
local theme = beautiful.get()
local capi = {
root = root,
client = client
}
module("vbe/keydoc")
local doc = { }
local currentgroup = "Misc"
local orig = awful.key.new
-- Replacement for awful.key.new
local function new(mod, key, press, release, docstring)
-- Usually, there is no use of release, let's just use it for doc
-- if it's a string.
if press and release and not docstring and type(release) == "string" then
docstring = release
release = nil
end
local k = orig(mod, key, press, release)
-- Remember documentation for this key (we take the first one)
if k and #k > 0 and docstring then
doc[k[1]] = { help = docstring,
group = currentgroup }
end
return k
end
awful.key.new = new -- monkey patch
-- Turn a key to a string
local function key2str(key)
local sym = key.key or key.keysym
local translate = {
["#14"] = "#",
[" "] = "Space",
}
sym = translate[sym] or sym
if not key.modifiers or #key.modifiers == 0 then return sym end
local result = ""
local translate = {
[modkey] = "",
Shift = "",
Control = "Ctrl",
}
for _, mod in pairs(key.modifiers) do
mod = translate[mod] or mod
result = result .. mod .. " + "
end
return result .. sym
end
-- Unicode "aware" length function (well, UTF8 aware)
-- See: http://lua-users.org/wiki/LuaUnicode
local function unilen(str)
local _, count = string.gsub(str, "[^\128-\193]", "")
return count
end
-- Start a new group
function group(name)
currentgroup = name
return {}
end
local function markup(keys)
local result = {}
-- Compute longest key combination
local longest = 0
for _, key in ipairs(keys) do
if doc[key] then
longest = math.max(longest, unilen(key2str(key)))
end
end
local curgroup = nil
for _, key in ipairs(keys) do
if doc[key] then
local help, group = doc[key].help, doc[key].group
local skey = key2str(key)
result[group] = (result[group] or "") ..
'<span font="DejaVu Sans Mono ' .. 10 * theme.scale .. '" color="' .. beautiful.fg_widget_clock .. '"> ' ..
string.format("%" .. (longest - unilen(skey)) .. "s ", "") .. skey ..
'</span> <span color="' .. beautiful.fg_widget_value .. '">' ..
help .. '</span>\n'
end
end
return result
end
-- Display help in a naughty notification
local nid = nil
function display()
local strings = awful.util.table.join(
markup(capi.root.keys()),
capi.client.focus and markup(capi.client.focus:keys()) or {})
local result = ""
for group, res in pairs(strings) do
if #result > 0 then result = result .. "\n" end
result = result ..
'<span weight="bold" color="' .. beautiful.fg_widget_value_important .. '">' ..
group .. "</span>\n" .. res
end
nid = naughty.notify({ text = result,
replaces_id = nid,
hover_timeout = 0.1,
timeout = 30 }).id
end

View file

@ -1,140 +0,0 @@
-- Quake like console on top
-- Similar to:
-- http://git.sysphere.org/awesome-configs/tree/scratch/drop.lua
-- But uses a different implementation. The main difference is that we
-- are able to detect the Quake console from its name
-- (QuakeConsoleNeedsUniqueName by default).
-- If you have a rule like "awful.client.setslave" for your terminals,
-- ensure you use an exception for
-- QuakeConsoleNeedsUniqueName. Otherwise, you may run into problems
-- with focus.
local setmetatable = setmetatable
local string = string
local awful = require("awful")
local capi = { mouse = mouse,
screen = screen,
client = client,
timer = timer }
-- I use a namespace for my modules...
module("vbe/quake")
local QuakeConsole = {}
-- Display
function QuakeConsole:display()
-- First, we locate the terminal
local client = nil
local i = 0
for c in awful.client.cycle(function (c)
-- c.name may be changed!
return (c.instance == self.name or c.role == self.name)
end) do
client = c
client:tags({})
break
end
if not client and not self.visible then
-- The terminal is not here yet but we don't want it yet. Just do nothing.
return
end
if not client then
-- The client does not exist, we spawn it
awful.util.spawn(self.terminal .. " " .. string.format(self.argname, self.name))
return
end
-- Comptute size
local geom = capi.screen[capi.mouse.screen].workarea
local width, height = self.width, self.height
if width <= 1 then width = geom.width * width end
if height <= 1 then height = geom.height * height end
local x, y
if self.horiz == "left" then x = geom.x
elseif self.horiz == "right" then x = geom.width + geom.x - width
else x = geom.x + (geom.width - width)/2 end
if self.vert == "top" then y = geom.y
elseif self.vert == "bottom" then y = geom.height + geom.y - height
else y = geom.y + (geom.height - height)/2 end
-- Resize
awful.client.floating.set(client, true)
client.border_width = 0
client.size_hints_honor = false
client:geometry({ x = x, y = y, width = width, height = height })
-- Sticky and on top
client.ontop = true
client.above = true
client.skip_taskbar = true
client.sticky = true
-- This is not a normal window, don't apply any specific keyboard stuff
client:buttons({})
client:keys({})
-- Toggle display
if self.visible then
client.hidden = false
client:raise()
capi.client.focus = client
else
client.hidden = true
end
end
-- Create a console
function QuakeConsole:new(config)
-- The "console" object is just its configuration.
-- The application to be invoked is:
-- config.terminal .. " " .. string.format(config.argname, config.name)
config.terminal = config.terminal or "xterm" -- application to spawn
config.name = config.name or "QuakeConsoleNeedsUniqueName" -- window name
config.argname = config.argname or "-name %s" -- how to specify window name
-- If width or height <= 1 this is a proportion of the workspace
config.height = config.height or 0.25 -- height
config.width = config.width or 1 -- width
config.vert = config.vert or "top" -- top, bottom or center
config.horiz = config.horiz or "center" -- left, right or center
config.visible = config.visible or false -- Initially, not visible
local console = setmetatable(config, { __index = QuakeConsole })
capi.client.add_signal("manage",
function(c)
if (c.instance == console.name or c.role == console.name) then
console:display()
end
end)
capi.client.add_signal("unmanage",
function(c)
if (c.instance == console.name or c.role == console.name) then
console.visible = false
end
end)
-- "Reattach" currently running QuakeConsole. This is in case awesome is restarted.
local reattach = capi.timer { timeout = 0 }
reattach:add_signal("timeout",
function()
reattach:stop()
console:display()
end)
reattach:start()
return console
end
-- Toggle the console
function QuakeConsole:toggle()
self.visible = not self.visible
self:display()
end
setmetatable(_M, { __call = function(_, ...) return QuakeConsole:new(...) end })

View file

@ -1,944 +0,0 @@
--- Shifty: Dynamic tagging library for awesome3-git
-- @author koniu &lt;gkusnierz@gmail.com&gt;
-- @author resixian (aka bioe007) &lt;resixian@gmail.com&gt;
--
-- http://awesome.naquadah.org/wiki/index.php?title=Shifty
--
-- Modified version for my own use (Vincent Bernat)
--
-- TODO:
-- - Maybe name a tag after first client.
-- environment
local type = type
local ipairs = ipairs
local table = table
local string = string
local beautiful = require("beautiful")
local awful = require("awful")
local pairs = pairs
local io = io
local tonumber = tonumber
local dbg= dbg
local capi = {
client = client,
tag = tag,
image = image,
screen = screen,
button = button,
mouse = mouse,
root = root,
timer = timer
}
module("vbe/shifty")
-- variables
config = {}
config.tags = {}
config.apps = {}
config.defaults = {}
config.guess_name = true
config.remember_index = true
config.default_name = ""
config.prompt_sources = {
"config_tags",
"config_apps",
"existing",
"history"
}
config.prompt_matchers = {
"^",
":",
""
}
local matchp = ""
local index_cache = {}
for i = 1, capi.screen.count() do index_cache[i] = {} end
--getname: return the "user" name of a tag
-- @param t : tag
-- @return username of the tag
local function getname(t)
local name = awful.tag.getproperty(t, "shortname")
if name then
return "" .. name
end
return t.name
end
--setname: set the "user" name of a tag and update its name
-- @param t : tag
-- @param name : new name
local function setname(t, name)
if name then
local dispname = "" .. name
local pos = awful.tag.getproperty(t, "position") or "?"
awful.tag.setproperty(t, "shortname", name)
if pos then
if "" .. pos ~= "" .. dispname then
dispname = pos .. '' .. dispname
end
end
t.name = dispname
end
end
--freeposition: get a free position
local function freeposition()
local positions = {1, 2, 3, 4, 5, 6, 7, 8, 9}
for k, a in pairs(config.tags) do
if a.startup then
a = awful.util.table.join(a, a.startup)
end
if a.position then
local idx = awful.util.table.hasitem(positions, a.position)
if idx then
table.remove(positions, idx)
end
end
end
for s = 1, capi.screen.count() do
for i, t in ipairs(capi.screen[s]:tags()) do
local pos = awful.tag.getproperty(t, "position")
if pos then
local idx = awful.util.table.hasitem(positions, pos)
if idx then
table.remove(positions, idx)
end
end
end
end
if #positions > 0 then
return positions[1]
end
return nil
end
--name2tags: matches string 'name' to tag objects
-- @param name : tag name to find
-- @param scr : screen to look for tags on
-- @return table of tag objects or nil
function name2tags(name, scr)
local ret = {}
local a, b = scr or 1, scr or capi.screen.count()
for s = a, b do
for i, t in ipairs(capi.screen[s]:tags()) do
if name == getname(t) then
table.insert(ret, t)
end
end
end
if #ret > 0 then return ret end
end
function name2tag(name, scr, idx)
local ts = name2tags(name, scr)
if ts then return ts[idx or 1] end
end
--tag2index: finds index of a tag object
-- @param scr : screen number to look for tag on
-- @param tag : the tag object to find
-- @return the index [or zero] or end of the list
function tag2index(scr, tag)
for i, t in ipairs(capi.screen[scr]:tags()) do
if t == tag then return i end
end
end
--rename
--@param tag: tag object to be renamed
function rename(tag, no_selectall)
local theme = beautiful.get()
local t = tag or awful.tag.selected(capi.mouse.screen)
local scr = t.screen
local bg = nil
local fg = nil
local text = getname(t)
local before = getname(t)
if t == awful.tag.selected(scr) then
bg = theme.bg_focus or '#535d6c'
fg = theme.fg_urgent or '#ffffff'
else
bg = theme.bg_normal or '#222222'
fg = theme.fg_urgent or '#ffffff'
end
awful.prompt.run({
fg_cursor = fg, bg_cursor = bg, ul_cursor = "single",
text = text, selectall = not no_selectall},
taglist[scr][tag2index(scr, t) * 2],
function (name) if name:len() > 0 then setname(t, name); end end,
completion,
awful.util.getdir("cache") .. "/history_tags",
nil,
function ()
if getname(t) == before then
if awful.tag.getproperty(t, "initial") then del(t) end
else
awful.tag.setproperty(t, "initial", true)
set(t)
end
t:emit_signal("property::name")
end
)
end
--send: moves client to tag[idx]
-- maybe this isn't needed here in shifty?
-- @param idx the tag number to send a client to
function send(idx)
local scr = capi.client.focus.screen or capi.mouse.screen
local sel = awful.tag.selected(scr)
local sel_idx = tag2index(scr, sel)
local tags = capi.screen[scr]:tags()
local target = awful.util.cycle(#tags, sel_idx + idx)
awful.client.movetotag(tags[target], capi.client.focus)
awful.tag.viewonly(tags[target])
end
function send_next() send(1) end
function send_prev() send(-1) end
--pos2idx: translate shifty position to tag index
--@param pos: position (an integer)
--@param scr: screen number
function pos2idx(pos, scr)
local v = 1
if pos and scr then
for i = #capi.screen[scr]:tags() , 1, -1 do
local t = capi.screen[scr]:tags()[i]
if awful.tag.getproperty(t, "position") and
awful.tag.getproperty(t, "position") <= pos then
v = i + 1
break
end
end
end
return v
end
--select : helper function chooses the first non-nil argument
--@param args - table of arguments
function select(args)
for i, a in pairs(args) do
if a ~= nil then
return a
end
end
end
--tagtoscr : move an entire tag to another screen
--
--@param scr : the screen to move tag to
--@param t : the tag to be moved [awful.tag.selected()]
--@return the tag
function tagtoscr(scr, t)
-- break if called with an invalid screen number
if not scr or scr < 1 or scr > capi.screen.count() then return end
-- tag to move
local otag = t or awful.tag.selected()
otag.screen = scr
-- set screen and then reset tag to order properly
if #otag:clients() > 0 then
for _ , c in ipairs(otag:clients()) do
if not c.sticky then
c.screen = scr
c:tags({otag})
else
awful.client.toggletag(otag, c)
end
end
end
return otag
end
--set : set a tags properties
--@param t: the tag
--@param args : a table of optional (?) tag properties
--@return t - the tag object
function set(t, args)
if not t then return end
if not args then args = {} end
-- set the name
setname(t, args.name or getname(t))
-- attempt to load preset on initial run
local preset = (awful.tag.getproperty(t, "initial") and
config.tags[getname(t)]) or {}
-- pick screen and get its tag table
local scr = args.screen or
(not t.screen and preset.screen) or
t.screen or
capi.mouse.screen
local clientstomove = nil
if scr > capi.screen.count() then scr = capi.screen.count() end
if t.screen and scr ~= t.screen then
tagtoscr(scr, t)
t.screen = nil
end
local tags = capi.screen[scr]:tags()
-- allow preset.layout to be a table to provide a different layout per
-- screen for a given tag
local preset_layout = preset.layout
if preset_layout and preset_layout[scr] then
preset_layout = preset.layout[scr]
end
-- select from args, preset, getproperty,
-- config.defaults.configs or defaults
local props = {
layout = select{args.layout, preset_layout,
awful.tag.getproperty(t, "layout"),
config.defaults.layout, awful.layout.suit.tile},
mwfact = select{args.mwfact, preset.mwfact,
awful.tag.getproperty(t, "mwfact"),
config.defaults.mwfact, 0.55},
nmaster = select{args.nmaster, preset.nmaster,
awful.tag.getproperty(t, "nmaster"),
config.defaults.nmaster, 1},
ncol = select{args.ncol, preset.ncol,
awful.tag.getproperty(t, "ncol"),
config.defaults.ncol, 1},
matched = select{args.matched, awful.tag.getproperty(t, "matched")},
exclusive = select{args.exclusive, preset.exclusive,
awful.tag.getproperty(t, "exclusive"),
config.defaults.exclusive},
persist = select{args.persist, preset.persist,
awful.tag.getproperty(t, "persist"),
config.defaults.persist},
nopopup = select{args.nopopup, preset.nopopup,
awful.tag.getproperty(t, "nopopup"),
config.defaults.nopopup},
leave_kills = select{args.leave_kills, preset.leave_kills,
awful.tag.getproperty(t, "leave_kills"),
config.defaults.leave_kills},
max_clients = select{args.max_clients, preset.max_clients,
awful.tag.getproperty(t, "max_clients"),
config.defaults.max_clients},
position = select{args.position, preset.position,
awful.tag.getproperty(t, "position"), freeposition()},
icon = select{args.icon and capi.image(args.icon),
preset.icon and capi.image(preset.icon),
awful.tag.getproperty(t, "icon"),
config.defaults.icon and capi.image(config.defaults.icon)},
icon_only = select{args.icon_only, preset.icon_only,
awful.tag.getproperty(t, "icon_only"),
config.defaults.icon_only},
sweep_delay = select{args.sweep_delay, preset.sweep_delay,
awful.tag.getproperty(t, "sweep_delay"),
config.defaults.sweep_delay},
}
-- calculate desired taglist index
local index = args.index or preset.index or config.defaults.index
local rel_index = args.rel_index or
preset.rel_index or
config.defaults.rel_index
local sel = awful.tag.selected(scr)
--TODO: what happens with rel_idx if no tags selected
local sel_idx = (sel and tag2index(scr, sel)) or 0
local t_idx = tag2index(scr, t)
local limit = (not t_idx and #tags + 1) or #tags
local idx = nil
if rel_index then
idx = awful.util.cycle(limit, (t_idx or sel_idx) + rel_index)
elseif index then
idx = awful.util.cycle(limit, index)
elseif props.position then
idx = pos2idx(props.position, scr)
if t_idx and t_idx < idx then idx = idx - 1 end
elseif config.remember_index and index_cache[scr][getname(t)] then
idx = index_cache[scr][getname(t)]
elseif not t_idx then
idx = #tags + 1
end
-- if we have a new index, remove from old index and insert
if idx then
if t_idx then table.remove(tags, t_idx) end
table.insert(tags, idx, t)
index_cache[scr][getname(t)] = idx
end
-- set tag properties and push the new tag table
capi.screen[scr]:tags(tags)
for prop, val in pairs(props) do awful.tag.setproperty(t, prop, val) end
-- execute run/spawn
if awful.tag.getproperty(t, "initial") then
if not args.nospawn then
local spawn = args.spawn or preset.spawn or config.defaults.spawn
local run = args.run or preset.run or config.defaults.run
if spawn and args.matched ~= true then
awful.util.spawn_with_shell(spawn, scr)
end
if run then run(t) end
end
awful.tag.setproperty(t, "initial", nil)
end
return t
end
function shift_next() set(awful.tag.selected(), {rel_index = 1}) end
function shift_prev() set(awful.tag.selected(), {rel_index = -1}) end
--add : adds a tag
--@param args: table of optional arguments
function add(args)
if not args then args = {} end
local name = args.name or " "
-- initialize a new tag object and its data structure
local t = capi.tag{name = name}
-- tell set() that this is the first time
awful.tag.setproperty(t, "initial", true)
-- apply tag settings
set(t, args)
-- unless forbidden or if first tag on the screen, show the tag
if not (awful.tag.getproperty(t, "nopopup") or args.noswitch) or
#capi.screen[t.screen]:tags() == 1 then
awful.tag.viewonly(t)
end
-- get the name or rename
if args.name then
setname(t, args.name)
else
-- FIXME: hack to delay rename for un-named tags for
-- tackling taglist refresh which disabled prompt
-- from being rendered until input
awful.tag.setproperty(t, "initial", true)
local tmr
local f = function() rename(t); tmr:stop() end
tmr = capi.timer({timeout = 0.01})
tmr:add_signal("timeout", f)
tmr:start()
end
return t
end
--del : delete a tag
--@param tag : the tag to be deleted [current tag]
function del(tag)
local scr = (tag and tag.screen) or capi.mouse.screen or 1
local tags = capi.screen[scr]:tags()
local sel = awful.tag.selected(scr)
local t = tag or sel
local idx = tag2index(scr, t)
-- return if tag not empty (except sticky)
local clients = t:clients()
local sticky = 0
for i, c in ipairs(clients) do
if c.sticky then sticky = sticky + 1 end
end
if #clients > sticky then return false end
-- store index for later
index_cache[scr][getname(t)] = idx
-- remove tag
t.screen = nil
return true
end
--is_client_tagged : replicate behavior in tag.c - returns true if the
--given client is tagged with the given tag
function is_client_tagged(tag, client)
for i, c in ipairs(tag:clients()) do
if c == client then
return true
end
end
return false
end
--match : handles app->tag matching, a replacement for the manage hook in
-- rc.lua
--@param c : client to be matched
function match(c, startup)
local nopopup, intrusive, nofocus, run, slave
local target_tag_names, target_tags = {}, {}
local typ = c.type
local cls = c.class
local inst = c.instance
local role = c.role
local name = c.name
local target_screen = capi.mouse.screen
-- try matching client to config.apps
for i, a in ipairs(config.apps) do
if a.match then
local matched = false
-- match function
if not matched and a.match.check then
matched = a.match.check(c)
end
-- match only class
if not matched and cls and a.match.class then
for k, w in ipairs(a.match.class) do
matched = cls:find(w)
if matched then
break
end
end
end
-- match only instance
if not matched and inst and a.match.instance then
for k, w in ipairs(a.match.instance) do
matched = inst:find(w)
if matched then
break
end
end
end
-- match only name
if not matched and name and a.match.name then
for k, w in ipairs(a.match.name) do
matched = name:find(w)
if matched then
break
end
end
end
-- match only role
if not matched and role and a.match.role then
for k, w in ipairs(a.match.role) do
matched = (role == w)
if matched then
break
end
end
end
-- match only type
if not matched and typ and a.match.type then
for k, w in ipairs(a.match.type) do
matched = typ:find(w)
if matched then
break
end
end
end
-- check everything else against all attributes
if not matched then
for k, w in ipairs(a.match) do
matched = (cls and cls:find(w)) or
(inst and inst:find(w)) or
(name and name:find(w)) or
(role and (role == w)) or
(typ and typ:find(w))
if matched then
break
end
end
end
-- set attributes
if matched then
if a.startup and startup then
a = awful.util.table.join(a, a.startup)
end
if a.screen then target_screen = a.screen end
if a.tag then
if type(a.tag) == "string" then
target_tag_names = {a.tag}
else
target_tag_names = a.tag
end
end
if a.slave ~=nil then slave = a.slave end
if a.nopopup ~=nil then nopopup = a.nopopup end
if a.intrusive ~=nil then
intrusive = a.intrusive
end
if a.nofocus ~= nil then nofocus = a.nofocus end
if a.run ~= nil then run = a.run end
if a.props then
for kk, vv in pairs(a.props) do
awful.client.property.set(c, kk, vv)
end
end
end
end
end
local sel = awful.tag.selectedlist(target_screen)
if not target_tag_names or #target_tag_names == 0 then
-- if not matched to some names try putting
-- client in c.transient_for or current tags
if c.transient_for then
target_tags = c.transient_for:tags()
elseif #sel > 0 then
for i, t in ipairs(sel) do
local mc = awful.tag.getproperty(t, "max_clients")
if intrusive or c.type == "dialog" or
not (awful.tag.getproperty(t, "exclusive") or
(mc and mc >= #t:clients())) then
table.insert(target_tags, t)
if config.guess_name and cls then
if getname(t) == config.default_name or
getname(t) == "" .. (awful.tag.getproperty(t, "position") or "?") then
setname(t, cls:lower())
end
end
end
end
end
end
if (not target_tag_names or #target_tag_names == 0) and
(not target_tags or #target_tags == 0) then
-- if we still don't know any target names/tags guess
-- name from class or use default
if config.guess_name and cls then
target_tag_names = {cls:lower()}
else
target_tag_names = {config.default_name}
end
end
if #target_tag_names > 0 and #target_tags == 0 then
-- translate target names to tag objects, creating
-- missing ones
for i, tn in ipairs(target_tag_names) do
local res = {}
for j, t in ipairs(name2tags(tn, target_screen) or
name2tags(tn) or {}) do
local mc = awful.tag.getproperty(t, "max_clients")
local tagged = is_client_tagged(t, c)
if intrusive or
not (mc and (((#t:clients() >= mc) and not
tagged) or
(#t:clients() > mc))) or
intrusive then
table.insert(res, t)
end
end
if #res == 0 then
table.insert(target_tags,
add({name = tn,
noswitch = true,
matched = true}))
else
target_tags = awful.util.table.join(target_tags, res)
end
end
end
-- set client's screen/tag if needed
target_screen = target_tags[1].screen or target_screen
if c.screen ~= target_screen then c.screen = target_screen end
if slave then awful.client.setslave(c) end
c:tags(target_tags)
local showtags = {}
local u = nil
if #target_tags > 0 and not startup then
-- switch or highlight
for i, t in ipairs(target_tags) do
if not (nopopup or awful.tag.getproperty(t, "nopopup")) then
table.insert(showtags, t)
elseif not startup then
c.urgent = true
end
end
if #showtags > 0 then
local ident = false
-- iterate selected tags and and see if any targets
-- currently selected
for kk, vv in pairs(showtags) do
for _, tag in pairs(sel) do
if tag == vv then
ident = true
end
end
end
if not ident then
awful.tag.viewmore(showtags, c.screen)
end
end
end
if nofocus then
--focus and raise accordingly or lower if supressed
if (target and target ~= sel) and
(awful.tag.getproperty(target, "nopopup") or nopopup) then
awful.client.focus.history.add(c)
else
capi.client.focus = c
end
c:raise()
else
c:lower()
end
-- execute run function if specified
if run then run(c, target) end
end
--sweep : hook function that marks tags as used, visited,
--deserted also handles deleting used and empty tags
function sweep()
for s = 1, capi.screen.count() do
for i, t in ipairs(capi.screen[s]:tags()) do
local clients = t:clients()
local sticky = 0
for i, c in ipairs(clients) do
if c.sticky then sticky = sticky + 1 end
end
if #clients == sticky then
if awful.tag.getproperty(t, "used") and
not awful.tag.getproperty(t, "persist") then
if awful.tag.getproperty(t, "deserted") or
not awful.tag.getproperty(t, "leave_kills") then
local delay = awful.tag.getproperty(t, "sweep_delay")
if delay then
local tmr
local f = function()
del(t)
tmr:stop()
end
tmr = capi.timer({timeout = delay})
tmr:add_signal("timeout", f)
tmr:start()
else
del(t)
end
else
if awful.tag.getproperty(t, "visited") and
not t.selected then
awful.tag.setproperty(t, "deserted", true)
end
end
end
else
awful.tag.setproperty(t, "used", true)
end
if t.selected then
awful.tag.setproperty(t, "visited", true)
end
end
end
end
--getpos : returns a tag to match position
-- @param pos : the index to find
-- @return v : the tag (found or created) at position == 'pos'
function getpos(pos, args)
local v = nil
local existing = {}
local selected = nil
local scr = capi.mouse.screen or 1
local args = args or {}
-- search for existing tag assigned to pos
for i = 1, capi.screen.count() do
for j, t in ipairs(capi.screen[i]:tags()) do
if awful.tag.getproperty(t, "position") == pos then
table.insert(existing, t)
if t.selected and i == scr then
selected = #existing
end
end
end
end
if #existing > 0 then
-- if making another of an existing tag, return the end of
-- the list the optional 2nd argument decides if we return
-- only
v = (selected and
existing[awful.util.cycle(#existing, selected + 1)]) or
existing[1]
end
if not v then
-- search for preconf with 'pos' and create it
for i, j in pairs(config.tags) do
if j.position == pos then
v = add({name = i,
position = pos,
noswitch = true,
nospawn = args.nospawn})
end
end
end
if not v then
-- not existing, not preconfigured
v = add({position = pos,
name = pos,
noswitch = true,
nospawn = args.nospawn})
end
return v
end
--init : search shifty.config.tags for initial set of
--tags to open
function init()
local numscr = capi.screen.count()
for i, j in pairs(config.tags) do
local scr = j.screen or {1}
if type(scr) ~= 'table' then
scr = {scr}
end
for _, s in pairs(scr) do
if j.init and (s <= numscr) then
add({name = i,
persist = true,
screen = s,
layout = j.layout,
mwfact = j.mwfact})
end
end
end
end
--count : utility function returns the index of a table element
--FIXME: this is currently used only in remove_dup, so is it really
--necessary?
function count(table, element)
local v = 0
for i, e in pairs(table) do
if element == e then v = v + 1 end
end
return v
end
--remove_dup : used by shifty.completion when more than one
--tag at a position exists
function remove_dup(table)
local v = {}
for i, entry in ipairs(table) do
if count(v, entry) == 0 then v[#v+ 1] = entry end
end
return v
end
--completion : prompt completion
--
function completion(cmd, cur_pos, ncomp, sources, matchers)
-- get sources and matches tables
sources = sources or config.prompt_sources
matchers = matchers or config.prompt_matchers
local get_source = {
-- gather names from config.tags
config_tags = function()
local ret = {}
for n, p in pairs(config.tags) do
table.insert(ret, n)
end
return ret
end,
-- gather names from config.apps
config_apps = function()
local ret = {}
for i, p in pairs(config.apps) do
if p.tag then
if type(p.tag) == "string" then
table.insert(ret, p.tag)
else
ret = awful.util.table.join(ret, p.tag)
end
end
end
return ret
end,
-- gather names from existing tags, starting with the
-- current screen
existing = function()
local ret = {}
for i = 1, capi.screen.count() do
local s = awful.util.cycle(capi.screen.count(),
capi.mouse.screen + i - 1)
local tags = capi.screen[s]:tags()
for j, t in pairs(tags) do
table.insert(ret, getname(t))
end
end
return ret
end,
-- gather names from history
history = function()
local ret = {}
local f = io.open(awful.util.getdir("cache") ..
"/history_tags")
for name in f:lines() do table.insert(ret, name) end
f:close()
return ret
end,
}
-- if empty, match all
if #cmd == 0 or cmd == " " then cmd = "" end
-- match all up to the cursor if moved or no matchphrase
if matchp == "" or
cmd:sub(cur_pos, cur_pos+#matchp) ~= matchp then
matchp = cmd:sub(1, cur_pos)
end
-- find matching commands
local matches = {}
for i, src in ipairs(sources) do
local source = get_source[src]()
for j, matcher in ipairs(matchers) do
for k, name in ipairs(source) do
if name:find(matcher .. matchp) then
table.insert(matches, name)
end
end
end
end
-- no matches
if #matches == 0 then return cmd, cur_pos end
-- remove duplicates
matches = remove_dup(matches)
-- cycle
while ncomp > #matches do ncomp = ncomp - #matches end
-- put cursor at the end of the matched phrase
if #matches == 1 then
cur_pos = #matches[ncomp] + 1
else
cur_pos = matches[ncomp]:find(matchp) + #matchp
end
-- return match and position
return matches[ncomp], cur_pos
end
-- signals
capi.client.add_signal("manage", match)
capi.client.add_signal("unmanage", sweep)
capi.client.remove_signal("manage", awful.tag.withcurrent)
for s = 1, capi.screen.count() do
awful.tag.attached_add_signal(s, "property::selected", sweep)
awful.tag.attached_add_signal(s, "tagged", sweep)
end

View file

@ -1,76 +0,0 @@
-- Drive spotify through playerctl.
-- Spotify uses the MPRIS D-BUS interface. See more information here:
-- http://specifications.freedesktop.org/mpris-spec/latest/
-- To get the complete interface:
-- busctl --user introspect org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2
local awful = require("awful")
local dbg = dbg
local pairs = pairs
local os = os
local capi = {
client = client
}
module("vbe/spotify")
-- Get spotify window
local function spotify()
local clients = capi.client.get()
for k, c in pairs(clients) do
if awful.rules.match(c, { instance = "spotify",
class = "Spotify" }) then
return c
end
end
return nil
end
-- Send a command to spotify
local function cmd(command)
awful.util.spawn("playerctl -p spotify " .. command, false)
end
-- Show spotify
function show()
local client = spotify()
if client then
if not client:isvisible() then
awful.tag.viewonly(client:tags()[1])
end
capi.client.focus = client
client:raise()
else
awful.util.spawn("spotify")
end
end
function playpause()
cmd("play-pause")
end
function play()
cmd("play")
end
function pause()
cmd("pause")
end
function stop()
cmd("stop")
end
function next()
cmd("next")
end
function previous()
cmd("previous")
end
function mixer()
awful.util.spawn("pavucontrol")
end

View file

@ -1,70 +0,0 @@
-- Handle volume (through pulseaudio)
local awful = require("awful")
local naughty = require("naughty")
local tonumber = tonumber
local string = string
local os = os
-- A bit odd, but...
require("lib/icons")
local icons = package.loaded["vbe/icons"]
module("vbe/volume")
local volid = nil
local running = true
local function current(what)
local out = awful.util.pread("amixer -D pulse sget " .. what)
local vol, mute = out:match("([%d]+)%%.*%[([%l]*)")
return vol, mute
end
local function change(what, how)
if how ~= 0 then
local vol, mute = current(what)
how = string.format("%d%%", vol+how)
else
how = "toggle"
end
os.execute("amixer -q -D pulse sset " .. what .. " " .. how, false)
local vol, mute = current(what)
vol = tonumber(vol)
local icon = "high"
if mute ~= "on" or vol == 0 then
icon = "muted"
elseif vol < 30 then
icon = "low"
elseif vol < 60 then
icon = "medium"
end
local prefix = "audio-volume"
if what == "Capture" then
prefix = "microphone-sensitivity"
end
icon = icons.lookup({name = prefix .. "-" .. icon,
type = "status"})
volid = naughty.notify({ text = string.format("%3d %%", vol),
icon = icon,
font = "Free Sans Bold 24",
replaces_id = volid }).id
end
function increase(what)
change(what, 2)
end
function decrease(what)
change(what, -2)
end
function toggle(what)
change(what, 0)
end
-- run pavucontrol
function mixer()
awful.util.spawn("pavucontrol", false)
end

75
rc.lua
View file

@ -1,75 +0,0 @@
require("awful")
require("awful.autofocus")
require("awful.rules")
require("beautiful")
require("naughty")
-- Simple function to load additional LUA files from rc/.
function loadrc(name, mod)
local success
local result
-- Which file? In rc/ or in lib/?
local path = awful.util.getdir("config") .. "/" ..
(mod and "lib" or "rc") ..
"/" .. name .. ".lua"
-- If the module is already loaded, don't load it again
if mod and package.loaded[mod] then return package.loaded[mod] end
-- Execute the RC/module file
success, result = pcall(function() return dofile(path) end)
if not success then
naughty.notify({ title = "Error while loading an RC file",
text = "When loading `" .. name ..
"`, got the following error:\n" .. result,
preset = naughty.config.presets.critical
})
return print("E: error loading RC file '" .. name .. "': " .. result)
end
-- Is it a module?
if mod then
return package.loaded[mod]
end
return result
end
loadrc("errors") -- errors and debug stuff
-- Create cache directory
os.execute("mkdir -p " .. awful.util.getdir("cache"))
-- Setup xsettings
os.execute("~/.config/awesome/bin/xsettingsd-setup")
os.execute("systemctl --user start --no-block wallpaper@$(systemd-escape -- ${DISPLAY%.0})")
-- Global configuration
modkey = "Mod4"
config = {}
config.terminal = "vbeterm"
config.termclass = "Vbeterm"
config.layouts = {
awful.layout.suit.tile,
awful.layout.suit.tile.left,
awful.layout.suit.tile.bottom,
awful.layout.suit.fair,
awful.layout.suit.floating,
}
config.hostname = awful.util.pread('uname -n'):gsub('\n', '')
-- Remaining modules
loadrc("appearance") -- theme and appearance settings
loadrc("debug") -- debugging primitive `dbg()`
loadrc("bindings") -- keybindings
loadrc("widgets") -- widgets configuration
loadrc("tags") -- tags handling
loadrc("xlock") -- lock screen
loadrc("signals") -- window manager behaviour
loadrc("rules") -- window rules
loadrc("quake") -- quake console
loadrc("xrandr") -- xrandr menu
root.keys(config.keys.global)

View file

@ -1,120 +0,0 @@
-- Theme
beautiful.init(awful.util.getdir("config") .. "/rc/theme.lua")
-- Also have a look at `xsettingsd` which is used for GTK 3. At some
-- point, when we don't need GTK 2, we can use only xsettingsd and
-- avoid duplication.
local gtk2 = io.open(os.getenv("HOME") .. "/.gtkrc-2.0", "w")
gtk2:write([[
gtk-theme-name="Adwaita-dark"
gtk-icon-theme-name="Adwaita"
gtk-cursor-theme-name="Adwaita"
gtk-cursor-theme-size=0
gtk-font-name="DejaVu Sans 10"
gtk-button-images=1
gtk-menu-images=1
gtk-fallback-icon-theme="gnome"
gtk-toolbar-style=GTK_TOOLBAR_BOTH
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
gtk-decoration-layout=":menu"
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle="hintslight"
gtk-xft-rgba="rgb"
gtk-key-theme-name="Emacs"
binding "vbe-text-entry-bindings" {
unbind "<ctrl>b"
unbind "<shift><ctrl>b"
unbind "<ctrl>f"
unbind "<shift><ctrl>f"
unbind "<ctrl>w"
bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
}
class "GtkEntry" binding "vbe-text-entry-bindings"
class "GtkTextView" binding "vbe-text-entry-bindings"
]])
gtk2:close()
os.execute("mkdir -p ~/.config/gtk-3.0")
os.execute("rm -f ~/.config/gtk-3.0/settings.ini")
local gtk3 = io.open(os.getenv("HOME") .. "/.config/gtk-3.0/gtk.css", "w")
gtk3:write([[
/* Useless: we cannot override properly by unbinding some keys */
/* @import url("/usr/share/themes/Emacs/gtk-3.0/gtk-keys.css"); */
@binding-set custom-text-entry
{
bind "<alt>b" { "move-cursor" (words, -1, 0) };
bind "<shift><alt>b" { "move-cursor" (words, -1, 1) };
bind "<alt>f" { "move-cursor" (words, 1, 0) };
bind "<shift><alt>f" { "move-cursor" (words, 1, 1) };
bind "<ctrl>a" { "move-cursor" (paragraph-ends, -1, 0) };
bind "<shift><ctrl>a" { "move-cursor" (paragraph-ends, -1, 1) };
bind "<ctrl>e" { "move-cursor" (paragraph-ends, 1, 0) };
bind "<shift><ctrl>e" { "move-cursor" (paragraph-ends, 1, 1) };
bind "<ctrl>y" { "paste-clipboard" () };
bind "<ctrl>d" { "delete-from-cursor" (chars, 1) };
bind "<alt>d" { "delete-from-cursor" (word-ends, 1) };
bind "<ctrl>k" { "delete-from-cursor" (paragraph-ends, 1) };
bind "<alt>backslash" { "delete-from-cursor" (whitespace, 1) };
bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) };
bind "<alt>space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
bind "<alt>KP_Space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
}
entry, textview
{
-gtk-key-bindings: custom-text-entry;
}
.window-frame, .window-frame:backdrop {
box-shadow: 0 0 0 black;
border-style: none;
margin: 0;
border-radius: 0;
}
.titlebar {
border-radius: 0;
}
]])
gtk3:close()
-- For QT, use qt5ct
os.execute("mkdir -p ~/.config/qt5ct")
local qt5ct = io.open(os.getenv("HOME") .. "/.config/qt5ct/qt5ct.conf", "w")
qt5ct:write([[
[Appearance]
custom_palette=false
icon_theme=Adwaita
standard_dialogs=gtk3
style=Adwaita-dark
[Fonts]
fixed=@Variant(\0\0\0@\0\0\0 \0\x44\0\x65\0j\0\x61\0V\0u\0 \0S\0\x61\0n\0s\0 \0M\0o\0n\0o@$\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)
general=@Variant(\0\0\0@\0\0\0\x16\0\x44\0\x65\0j\0\x61\0V\0u\0 \0S\0\x61\0n\0s@$\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)
]])
qt5ct:close()
-- The systray is a bit complex. We need to configure it to display
-- the right colors. Here is a link with more background about this:
-- http://thread.gmane.org/gmane.comp.window-managers.awesome/9028
xprop = assert(io.popen("xprop -root _NET_SUPPORTING_WM_CHECK"))
wid = xprop:read():match("^_NET_SUPPORTING_WM_CHECK.WINDOW.: window id # (0x[%S]+)$")
xprop:close()
if wid then
wid = tonumber(wid) + 1
os.execute("xprop -id " .. wid .. " -format _NET_SYSTEM_TRAY_COLORS 32c " ..
"-set _NET_SYSTEM_TRAY_COLORS " ..
"65535,65535,65535,65535,8670,8670,65535,32385,0,8670,65535,8670")
end
-- Set cursor theme
os.execute("xsetroot -cursor_name left_ptr")

View file

@ -1,317 +0,0 @@
config.keys = {}
config.mouse = {}
local volume = loadrc("volume", "vbe/volume")
local brightness = loadrc("brightness", "vbe/brightness")
local keydoc = loadrc("keydoc", "vbe/keydoc")
local function screenshot()
awful.util.spawn_with_shell("flameshot gui -r | xclip -selection clipboard -t image/png",
false)
end
-- Function to toggle a given window to the currently selected and
-- focused tag. We need a filter. This function can be used to focus a
-- particular window. When the filter is unable to select something,
-- we undo previous actions (hence "toggle"). This function returns a
-- function that will effectively toggle things.
local function toggle_window(filter)
local undo = {} -- undo stack
client.add_signal('unmanage',
function(c)
-- If the client is in the undo stack, remove it
while true do
idx = awful.util.table.hasitem(undo, c)
if not idx then break end
table.remove(undo, idx)
end
end)
local toggle = function()
-- "Current" screen
local s = client.focus and client.focus.screen or mouse.screen
local cl = filter() -- Client to toggle
if cl and client.focus ~= cl then
-- So, we have a client.
if not cl:isvisible() then
-- But it is not visible. So we will add it to the current
-- tag of the screen where it currently is
local t = assert(awful.tag.selected(cl.screen))
-- Add our tag to the client
undo[#undo + 1] = { cl, t }
awful.client.toggletag(t, cl)
end
-- Focus and raise the client
if s ~= cl.screen then
mouse.screen = cl.screen
end
client.focus = cl
cl:raise()
else
-- OK, we need to restore the previously pushed window to its
-- original state.
local i = #undo
while i > 0 do
local cl, t = unpack(undo[i])
-- We only handle visible clients that are attached to the
-- appropriate tag. Otherwise, we try the next one.
if cl and cl:isvisible() and t.selected and
awful.util.table.hasitem(cl:tags(), t) then
awful.client.toggletag(t, cl)
table.remove(undo, i)
return
end
i = i - 1
end
-- Clean up...
while #undo > 10 do
table.remove(undo, 1)
end
end
end
return toggle
end
-- Toggle IM conversation window
local toggle_im = toggle_window(
(function ()
local adding = true
local choose = function()
local cls = client.get()
local focus = client.focus
local rules = { { class = "Pidgin",
role = "conversation" },
{ class = "Skype",
role = "ConversationsWindow" } }
-- Score. We want a Pidgin window. Then:
-- 1. Urgent, visible, not focused
-- 2. Urgent, not visible, not focused.
-- 3. Not urgent, not visible, not focused
-- 4. Focused
-- 5. Visible, not focused
local function score(cl)
local found = false
for _, rule in pairs(rules) do
if awful.rules.match(cl, rule) then
found = true
break
end
end
if not found then return -10 end
local urgent = cl.urgent
local focused = (focus == cl)
local visible = cl:isvisible()
if urgent and visible and not focused then return 100 end
if urgent and not visible and not focused then return 90 end
if not adding and focused then return 80 end
if adding and not urgent and not visible then return 70 end
if focused then return 50 end
if not urgent and not visible then return 40 end
return 10
end
table.sort(cls, function(c1, c2)
local s1 = score(c1)
local s2 = score(c2)
return s1 > s2
end)
local candidate = cls[1]
if candidate == nil then return nil end
local found = false
for _, rule in pairs(rules) do
if awful.rules.match(candidate, rule) then
found = true
break
end
end
if not found then return nil end
-- Maybe we need to switch direction
if candidate == focus and adding then adding = false
elseif candidate ~= focus and not adding then adding = true end
return candidate
end
return choose
end)())
-- Toggle urgent window
local toggle_urgent = toggle_window(awful.client.urgent.get)
-- Focus a relative screen (similar to `awful.screen.focus_relative`)
local function screen_focus(i)
local s = awful.util.cycle(screen.count(), mouse.screen + i)
local c = awful.client.focus.history.get(s, 0)
mouse.screen = s
if c then client.focus = c end
end
local music = loadrc("spotify", "vbe/spotify")
local display_nmaster_ncol =
(function()
local nid = nil
return function()
local nmaster = awful.tag.getnmaster()
local ncol = awful.tag.getncol()
nid = naughty.notify(
{ title = "Tag configuration",
timeout = 5,
text = "Number of masters: " .. nmaster ..
"\nNumber of columns: " .. ncol,
replaces_id = nid }).id
end
end)()
config.keys.global = awful.util.table.join(
keydoc.group("Focus"),
awful.key({ modkey, }, "j",
function ()
awful.client.focus.byidx( 1)
if client.focus then
client.focus:raise()
end
end,
"Focus next window"),
awful.key({ modkey, }, "k",
function ()
awful.client.focus.byidx(-1)
if client.focus then
client.focus:raise()
end
end,
"Focus previous window"),
awful.key({ modkey, }, "u", toggle_im,
"Toggle Pidgin conversation window"),
awful.key({ modkey, "Control" }, "j", function ()
screen_focus(-1)
end,
"Jump to next screen"),
awful.key({ modkey, "Control" }, "k", function ()
screen_focus( 1)
end),
keydoc.group("Layout manipulation"),
awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
"Increase master-width factor"),
awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
"Decrease master-width factor"),
awful.key({ modkey, "Shift" }, "l", function ()
awful.tag.incnmaster(1)
display_nmaster_ncol()
end,
"Increase number of masters"),
awful.key({ modkey, "Shift" }, "h", function ()
awful.tag.incnmaster(-1)
display_nmaster_ncol()
end,
"Decrease number of masters"),
awful.key({ modkey, "Control" }, "l", function ()
awful.tag.incncol(1)
display_nmaster_ncol()
end,
"Increase number of columns"),
awful.key({ modkey, "Control" }, "h", function ()
awful.tag.incncol(-1)
display_nmaster_ncol()
end,
"Decrease number of columns"),
awful.key({ modkey, }, "space", function () awful.layout.inc(config.layouts, 1) end,
"Next layout"),
awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(config.layouts, -1) end,
"Previous layout"),
awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end,
"Swap with next window"),
awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end,
"Swap with previous window"),
keydoc.group("Misc"),
-- Spawn a terminal
awful.key({ modkey, }, "Return", function () awful.util.spawn(config.terminal) end,
"Spawn a terminal"),
-- Screenshot
awful.key({}, "Print", screenshot),
-- Restart awesome
awful.key({ modkey, "Control" }, "r", awesome.restart),
-- Multimedia keys
awful.key({ }, "XF86MonBrightnessUp", brightness.increase),
awful.key({ }, "XF86MonBrightnessDown", brightness.decrease),
awful.key({ }, "XF86AudioRaiseVolume", function() volume.increase("Master") end),
awful.key({ }, "XF86AudioLowerVolume", function() volume.decrease("Master") end),
awful.key({ }, "XF86AudioMute", function() volume.toggle("Master") end),
awful.key({ }, "XF86AudioMicMute", function() volume.toggle("Capture") end),
awful.key({ }, "XF86AudioPlay", music.playpause),
awful.key({ }, "XF86AudioPause", music.pause),
awful.key({ }, "XF86AudioStop", music.stop),
awful.key({ }, "XF86AudioNext", music.next),
awful.key({ }, "XF86AudioPrev", music.previous),
awful.key({ modkey }, "s", function()
keygrabber.run(function(mod, key, event)
if event == "release" then
return true
end
keygrabber.stop()
if key == "z" then music.previous()
elseif key == "x" then music.play()
elseif key == "c" then music.pause()
elseif key == "v" then music.stop()
elseif key == "b" then music.next()
elseif key == "s" then music.show()
elseif key == "m" then music.mixer()
end
return true
end)
end),
-- Help
awful.key({ modkey, }, "F1", keydoc.display)
)
config.keys.client = awful.util.table.join(
keydoc.group("Window-specific bindings"),
awful.key({ modkey, }, "f",
function (c)
c.sticky = false
c.fullscreen = not c.fullscreen
c:raise()
end,
"Fullscreen"),
awful.key({ modkey, }, "x", function (c) c:kill() end,
"Close"),
awful.key({ modkey, }, "o",
function (c)
if screen.count() == 1 then return nil end
local s = awful.util.cycle(screen.count(), c.screen + 1)
if awful.tag.selected(s) then
c.screen = s
client.focus = c
c:raise()
end
end, "Move to the other screen"),
awful.key({ modkey, "Control" }, "s", function (c) c.sticky = not c.sticky end, "Toggle stickyness"),
awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle, "Toggle floating"),
awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
"Switch with master window"),
awful.key({ modkey, }, "i", dbg,
"Get client-related information"),
awful.key({ modkey, }, "m",
function (c)
c.sticky = false
c.maximized_horizontal = not c.maximized_horizontal
c.maximized_vertical = not c.maximized_vertical
c:raise()
end,
"Maximize")
)
keydoc.group("Misc")
config.mouse.client = awful.util.table.join(
awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
awful.button({ modkey }, 1, awful.mouse.client.move),
awful.button({ modkey }, 3, awful.mouse.client.resize))

View file

@ -1,104 +0,0 @@
local colors = {
header = theme.fg_widget_clock,
count = theme.fg_widget_label,
index = theme.fg_widget_label,
name = theme.fg_widget_value_important,
}
local function client_info(c)
local v = ""
-- object
local c = c or client.focus
v = v .. tostring(c)
-- geometry
local cc = c:geometry()
local signx = (cc.x > 0 and "+") or ""
local signy = (cc.y > 0 and "+") or ""
v = v .. " @ " .. cc.width .. 'x' .. cc.height .. signx .. cc.x .. signy .. cc.y .. "\n\n"
local inf = {
"name", "icon_name", "type", "class", "role", "instance", "pid",
"skip_taskbar", "id", "group_window", "leader_id", "machine",
"screen", "hidden", "minimized", "size_hints_honor", "titlebar", "urgent",
"focus", "opacity", "ontop", "above", "below", "fullscreen", "transient_for",
"maximixed_horizontal", "maximixed_vertical", "sticky", "modal", "focusable"
}
for i = 1, #inf do
v = v .. string.format('%2s: <span color="%s">%-20s</span> = <span color="%s">%s</span>\n',
i,
beautiful.fg_widget_label, inf[i],
beautiful.fg_widget_value, tostring(c[inf[i]]))
end
naughty.notify{ text = string.format('<span font="' .. theme.font .. '">%s</span>', v:sub(1,#v-1)),
timeout = 0, margin = 10, screen = c.screen }
end
local function dbg_get(var, depth, indent)
local a = ""
local text = ""
local name = ""
local vtype = type(var)
local vstring = tostring(var)
if vtype == "table" or vtype == "userdata" then
if vtype == "userdata" then var = getmetatable(var) end
-- element count and longest key
local count = 0
local longest_key = 3
for k,v in pairs(var) do
count = count + 1
longest_key = math.max(#tostring(k), longest_key)
end
text = text .. vstring .. " <span color='"..colors.count.."'>#" .. count .. "</span>"
-- descend a table
if depth > 0 then
-- sort keys FIXME: messes up sorting number
local sorted = {}
for k, v in pairs(var) do table.insert(sorted, { k, v }) end
table.sort(sorted, function(a, b) return tostring(a[1]) < tostring(b[1]) end)
-- go through elements
for _, p in ipairs(sorted) do
local key = p[1]; local value = p[2]
-- don't descend _M
local d; if key ~= "_M" then d = depth - 1 else d = 0 end
-- get content and add to output
local content = dbg_get(value, d, indent + longest_key + 1)
text = text .. '\n' .. string.rep(" ", indent) ..
string.format("<span color='"..colors.index.."'>%-"..longest_key.."s</span> %s",
tostring(key), content)
end
end
else
if vtype == "tag" or vtype == "client" then
name = " [<span color='"..colors.name.."'>" .. (var.name or ''):sub(1,10) .. "</span>]"
end
text = text .. vstring .. name or ""
end
return text
end
function dbg(...)
local num = table.maxn(arg)
local text = "<span color='"..colors.header.."'>dbg</span> <span color='"..colors.count.."'>#"..num.."</span>"
local depth = 2
local clients = 0
for i = 1, num do
local desc = dbg_get(arg[i], depth, 3)
text = text .. string.format("\n<span color='"..colors.index.."'>%2d</span> %s", i, desc)
if type(arg[i]) == "client" then
client_info(arg[i])
clients = clients + 1
end
end
-- Display only if we don't have only clients to be displayed
if clients ~= num then
naughty.notify{ text = text, timeout = 0, hover_timeout = 2, screen = screen.count() }
end
end

View file

@ -1,14 +0,0 @@
-- Handle runtime errors after startup
do
local in_error = false
awesome.add_signal("debug::error", function (err)
-- Make sure we don't go into an endless error loop
if in_error then return end
in_error = true
naughty.notify({ preset = naughty.config.presets.critical,
title = "Oops, an error happened!",
text = err })
in_error = false
end)
end

View file

@ -1,10 +0,0 @@
local quake = loadrc("quake", "vbe/quake")
local quakeconsole = quake({ terminal = config.terminal,
argname = "--name %s",
height = 0.3 })
config.keys.global = awful.util.table.join(
config.keys.global,
awful.key({ modkey }, "`",
function () quakeconsole:toggle() end,
"Toggle Quake console"))

View file

@ -1,62 +0,0 @@
local icons = loadrc("icons", "vbe/icons")
awful.rules.rules = {
-- All clients will match this rule.
{ rule = { },
properties = { border_width = beautiful.border_width,
border_color = beautiful.border_normal,
focus = true,
maximized_vertical = false,
maximized_horizontal = false,
keys = config.keys.client,
buttons = config.mouse.client }},
-- i3lock
{ rule = { name = "i3lock" },
properties = { ontop = true } },
-- Browser stuff
{ rule = { role = "browser" },
callback = function(c)
if not c.icon then
local icon = icons.lookup({ name = "web-browser",
type = "apps" })
if icon then
c.icon = image(icon)
end
end
end },
{ rule = { class = config.termclass },
properties = { icon = image(icons.lookup({ name = "gnome-terminal",
type = "apps" })) } },
{ rule_any = { class = { "Iceweasel", "Firefox", "Chromium", "Conkeror", "Google-chrome" } },
callback = function(c)
-- All windows should be slaves, except the browser windows.
if c.role ~= "browser" then awful.client.setslave(c) end
end },
-- See also tags.lua
-- Pidgin
{ rule = { class = "Pidgin" },
except = { role = "buddy_list" },
properties = { }, callback = awful.client.setslave },
{ rule = { class = "Pidgin", role = "buddy_list" },
properties = { }, callback = awful.client.setmaster },
-- Shadow
{ rule = { class = "Shadow" },
properties = { fullscreen = true }},
-- Zoom dialogs should not have focus
{ rule = { class = "zoom", type = "dialog" },
properties = { focus = false }},
-- Should not be master
{ rule_any = { class =
{ config.termclass,
"Transmission-gtk"
}, instance = { "Download" }},
except = { icon_name = "QuakeConsoleNeedsUniqueName" },
properties = { },
callback = awful.client.setslave },
-- Picture in picture
{ rule = { name = "Picture-in-Picture" },
properties = { floating = true, ontop = true } },
-- Floating windows
{ rule_any = { class = { "Display.im6", "Key-mon" } },
properties = { floating = true }},
}

View file

@ -1,92 +0,0 @@
local icons = loadrc("icons", "vbe/icons")
-- Did we get the focus because of sloppy focus?
local focus_from_mouse = false
local function mouse_follow_focus(c)
-- Move the mouse to the top left corner
if c.type ~= "dialog" then
local cc = c:geometry()
local _, x, y = awful.mouse.client.corner(nil, "top_left")
if x and y then
mouse.coords({ x = x + 20 , y = y + cc.height / 2 }, true)
end
end
end
-- Signal function to execute when a new client appears.
client.add_signal("manage",
function (c, startup)
-- Enable sloppy focus
c:add_signal("mouse::enter",
function(c)
-- If magnifier suit, only give sloppy focus to master window
if ((awful.layout.get(c.screen) ~= awful.layout.suit.magnifier or
awful.client.getmaster(c.screen) == c)
-- Don't give focus to a client already having focus
and client.focus ~= c
-- Don't give focus to a window that does not want focus
and awful.client.focus.filter(c)) then
focus_from_mouse = c
client.focus = c
end
end)
-- If a window change its geometry, track it with the mouse
c:add_signal("property::geometry",
function()
-- Check if the current focused client is our
if client.focus ~=c then return end
-- Check that no button is pressed
local buttons = mouse.coords().buttons
for _, state in pairs(buttons) do
if state then return end
end
mouse_follow_focus(c)
end)
-- If this is Spotify and it sets the urgent property, unset it
if c.instance == "spotify" then
c.urgent = false
c:add_signal("property::urgent",
function()
c.urgent = false
end)
end
-- Setup icon if none exists
if not c.icon then
local icon = icons.lookup({ name = { c.class, c.instance },
type = "apps" })
if icon then
c.icon = image(icon)
end
end
if not startup then
-- Put windows in a smart way, only if they does not set an initial position.
if not c.size_hints.user_position and not c.size_hints.program_position then
awful.placement.no_overlap(c)
awful.placement.no_offscreen(c)
end
c:raise()
end
end)
client.add_signal("focus", function(c)
c.border_color = beautiful.border_focus
c.opacity = 1
if focus_from_mouse ~= c then
mouse_follow_focus(c)
c:raise()
end
focus_from_mouse = false
end)
client.add_signal("unfocus", function(c)
c.border_color = beautiful.border_normal
if (not c.fullscreen and
not awful.rules.match_any(c, { name = { "Picture-in-Picture" },
class = { "zoom" }})) then
c.opacity = 0.85
end
end)

View file

@ -1,164 +0,0 @@
-- Tags
local shifty = loadrc("shifty", "vbe/shifty")
local keydoc = loadrc("keydoc", "vbe/keydoc")
local tagicon = function(icon)
if screen.count() > 1 then
return beautiful.icons .. "/taglist/" .. icon .. ".png"
end
return nil
end
shifty.config.tags = {
www = {
position = 3,
mwfact = 0.7,
exclusive = true,
max_clients = 1,
screen = math.min(screen.count(), 2),
spawn = "xdg-open about:newtab",
icon = tagicon("web")
},
emacs = {
position = 2,
mwfact = 0.6,
exclusive = true,
screen = 1,
spawn = "emacs",
icon = tagicon("dev"),
},
xterm = {
position = 1,
layout = awful.layout.suit.fair,
exclusive = true,
slave = true,
spawn = config.terminal,
icon = tagicon("main"),
},
spotify = {
screen = 1,
exclusive = true
}
}
-- Also, see rules.lua
shifty.config.apps = {
{
match = { role = { "browser" } },
tag = "www",
},
{
match = { "emacs" },
tag = "emacs",
},
{
match = { class = { "Spotify" } },
tag = "spotify"
},
{
match = { config.termclass },
startup = {
tag = "xterm"
},
intrusive = true, -- Display even on exclusive tags
},
{
match = { class = { "Key[-]mon" },
role = { "pop[-]up" },
name = { "Firebug", "Picture-in-Picture" },
instance = { "plugin[-]container", "exe" } },
intrusive = true,
},
}
shifty.config.defaults = {
layout = config.layouts[1],
mwfact = 0.6,
ncol = 1,
sweep_delay = 1,
}
shifty.taglist = config.taglist -- Set in widget.lua
shifty.init()
local tag_del_or_rename = function(tag)
if not shifty.del(tag) then
shifty.rename(tag)
end
end
config.keys.global = awful.util.table.join(
config.keys.global,
keydoc.group("Tag management"),
awful.key({ modkey }, "Tab", awful.tag.history.restore, "Switch to previous tag"),
awful.key({ modkey }, "Left", awful.tag.viewprev),
awful.key({ modkey }, "Right", awful.tag.viewnext),
awful.key({ modkey, "Shift"}, "o",
function()
if screen.count() == 1 then return nil end
local t = awful.tag.selected()
if t == nil then return nil end
local s = awful.util.cycle(screen.count(), t.screen + 1)
awful.tag.history.restore()
t = shifty.tagtoscr(s, t)
awful.tag.viewonly(t)
end,
"Send tag to next screen"),
awful.key({ modkey, "Control", "Shift"}, "o",
function()
if screen.count() == 1 then return nil end
local t = awful.tag.selected()
if t == nil then return nil end
local o = t.screen
local s = awful.util.cycle(screen.count(), o + 1)
for _, t in pairs(screen[o]:tags()) do
shifty.tagtoscr(s, t)
end
end,
"Send all tags to next screen"),
awful.key({ modkey }, 0, shifty.add, "Create a new tag"),
awful.key({ modkey, "Shift" }, 0, tag_del_or_rename),
awful.key({ modkey, "Control" }, 0, tag_del_or_rename, "Rename or delete tag"))
-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it works on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, (shifty.config.maxtags or 9) do
config.keys.global = awful.util.table.join(
config.keys.global,
keydoc.group("Tag management"),
awful.key({ modkey }, i,
function ()
local t = shifty.getpos(i)
local s = t.screen
local c = awful.client.focus.history.get(s, 0)
awful.tag.viewonly(t)
mouse.screen = s
if c then client.focus = c end
end,
i == 5 and "Display only this tag" or nil),
awful.key({ modkey, "Control" }, i,
function ()
local t = shifty.getpos(i)
t.selected = not t.selected
end,
i == 5 and "Toggle display of this tag" or nil),
awful.key({ modkey, "Shift" }, i,
function ()
local c = client.focus
if c then
local t = shifty.getpos(i, {nospawn = true })
awful.client.movetotag(t, c)
end
end,
i == 5 and "Move window to this tag" or nil),
awful.key({ modkey, "Control", "Shift" }, i,
function ()
if client.focus then
awful.client.toggletag(shifty.getpos(i, {nospawn = true}))
end
end,
i == 5 and "Toggle this tag on this window" or nil),
keydoc.group("Misc"))
end

View file

@ -1,74 +0,0 @@
-- Small modifications to anrxc's zenburn theme
local na = awful.util.color_strip_alpha
local icons = awful.util.getdir("config") .. "/icons"
local function scale()
local xrdb = io.popen("xrdb -query")
if xrdb then
for line in xrdb:lines() do
output = line:match("^Xft.dpi:\t(%d+)$")
if output then
xrdb:close()
return tonumber(output)/96
end
end
xrdb:close()
end
return 1
end
theme = {}
theme.scale = scale()
theme.icons = icons
theme.wallpaper_cmd = { "/bin/true" }
theme.font = "Terminus " .. 9 * theme.scale
theme.tasklist_font = "DejaVu Sans " .. 8 * theme.scale
theme.bg_normal = "#22222299"
theme.bg_focus = "#d8d8d8bb"
theme.bg_urgent = "#d02e5499"
theme.bg_minimize = "#44444499"
theme.fg_normal = "#cccccc"
theme.fg_focus = "#000000"
theme.fg_urgent = "#ffffff"
theme.fg_minimize = "#ffffff"
theme.border_width = 4
theme.border_normal = "#00000000"
theme.border_focus = "#FF7F00"
theme.border_marked = "#91231c66"
-- Widget stuff
theme.bg_widget = "#000000BB"
theme.fg_widget_label = "#737d8c"
theme.fg_widget_value = na(theme.fg_normal)
theme.fg_widget_value_important = "#E80F28"
theme.fg_widget_border = theme.fg_widget_label
theme.fg_widget_clock = na(theme.border_focus)
-- Taglist
theme.taglist_squares_sel = icons .. "/taglist/squarefw.png"
theme.taglist_squares_unsel = icons .. "/taglist/squarew.png"
-- Layout icons
for _, l in pairs(config.layouts) do
theme["layout_" .. l.name] = icons .. "/layouts/" .. l.name .. ".png"
end
-- Naughty
naughty.config.presets.normal.bg = "#111111"
for _, preset in pairs({"normal", "low", "critical"}) do
naughty.config.presets[preset].font = "DejaVu Sans " .. 10 * theme.scale
naughty.config.presets[preset].margin = 12 * theme.scale
naughty.config.presets[preset].border_width = 3 * theme.scale
end
naughty.config.notify_callback = function(args)
if args.icon ~= nil and type(args.icon) ~= "string" then
args.icon = nil
end
return args
end
return theme

View file

@ -1,318 +0,0 @@
-- Widgets
require("vicious")
local icons = loadrc("icons", "vbe/icons")
-- Separators
local sepopen = widget({ type = "imagebox" })
sepopen.image = image(beautiful.icons .. "/widgets/left.png")
local sepclose = widget({ type = "imagebox" })
sepclose.image = image(beautiful.icons .. "/widgets/right.png")
local spacer = widget({ type = "imagebox" })
spacer.image = image(beautiful.icons .. "/widgets/spacer.png")
-- Date
local datewidget = widget({ type = "textbox" })
local dateformat = "%a %d/%m, %H:%M"
vicious.register(datewidget, vicious.widgets.date,
'<span color="' .. beautiful.fg_widget_clock .. '">' ..
dateformat .. '</span>')
local dateicon = widget({ type = "imagebox" })
dateicon.image = image(beautiful.icons .. "/widgets/clock.png")
local cal = (
function()
local calendar = nil
local offset = 0
local remove_calendar = function()
if calendar ~= nil then
naughty.destroy(calendar)
calendar = nil
offset = 0
end
end
local add_calendar = function(inc_offset)
local save_offset = offset
remove_calendar()
offset = save_offset + inc_offset
local curdate = os.date("*t")
local datespec = curdate.year * 12 + curdate.month - 1 + offset
datespec = (datespec % 12 + 1) .. " " .. math.floor(datespec / 12)
local cal = awful.util.pread("ncal -h -w -m " .. datespec)
-- Highlight the current date and month
if offset == 0 then
cal, n = cal:gsub(string.format("( %d)([ \n])", curdate.day),
string.format('<span color="%s">%%1</span>%%2',
beautiful.fg_widget_clock),
1)
end
-- Month and year
cal = cal:gsub("^( +[^ ]+ [0-9]+) *",
string.format('<span color="%s">%%1</span>',
beautiful.fg_widget_clock))
-- Turn anything other than days in labels
cal = cal:gsub("(\n[^%d ]+)",
string.format('<span color="%s">%%1</span>',
beautiful.fg_widget_label))
cal = cal:gsub("([%d ]+)\n?$",
string.format('<span color="%s">%%1</span>',
beautiful.fg_widget_label))
calendar = naughty.notify(
{
text = string.format('<span font="%s">%s</span>',
theme.font,
cal:gsub(" +\n","\n")),
timeout = 0, hover_timeout = 0.5,
width = 160 * theme.scale,
screen = mouse.screen,
})
end
return { add = add_calendar,
rem = remove_calendar }
end)()
datewidget:add_signal("mouse::enter", function() cal.add(0) end)
datewidget:add_signal("mouse::leave", cal.rem)
datewidget:buttons(awful.util.table.join(
awful.button({ }, 3, function() cal.add(-1) end),
awful.button({ }, 1, function() cal.add(1) end)))
-- CPU usage
local cpuwidget = widget({ type = "textbox" })
vicious.register(cpuwidget, vicious.widgets.cpu,
function (widget, args)
return string.format('<span color="' .. beautiful.fg_widget_value .. '">%2d%%</span>',
args[1])
end, 7)
local cpuicon = widget({ type = "imagebox" })
cpuicon.image = image(beautiful.icons .. "/widgets/cpu.png")
-- Battery
local batwidget = { widget = "" }
if awful.util.table.hasitem({"guybrush", "zoro"}, config.hostname) then
local bat = "BAT0"
batwidget.widget = widget({ type = "textbox" })
vicious.register(batwidget.widget, vicious.widgets.bat,
function (widget, args)
local color = beautiful.fg_widget_value
local current = args[2]
if current < 10 and args[1] == "-" then
color = beautiful.fg_widget_value_important
-- Maybe we want to display a small warning?
if current ~= batwidget.lastwarn then
batwidget.lastid = naughty.notify(
{ title = "Battery low!",
preset = naughty.config.presets.critical,
timeout = 20,
text = "Battery level is currently " ..
current .. "%.\n" .. args[3] ..
" left before running out of power.",
icon = icons.lookup({name = "battery-caution",
type = "status"}),
replaces_id = batwidget.lastid }).id
batwidget.lastwarn = current
end
end
return string.format('<span color="' .. color ..
'">%s%d%%</span>', args[1], current)
end,
59, bat)
end
local baticon = widget({ type = "imagebox" })
baticon.image = image(beautiful.icons .. "/widgets/bat.png")
-- Network
local netup = widget({ type = "textbox" })
local netdown = widget({ type = "textbox" })
local netupicon = widget({ type = "imagebox" })
netupicon.image = image(beautiful.icons .. "/widgets/up.png")
local netdownicon = widget({ type = "imagebox" })
netdownicon.image = image(beautiful.icons .. "/widgets/down.png")
local netgraph = awful.widget.graph()
netgraph:set_width(80 * theme.scale):set_height(16 * theme.scale)
netgraph:set_stack(true):set_scale(true)
netgraph:set_border_color(beautiful.fg_widget_border)
netgraph:set_stack_colors({ "#EF8171", "#cfefb3" })
netgraph:set_background_color("#00000033")
vicious.register(netup, vicious.widgets.net,
function (widget, args)
-- We sum up/down value for all interfaces
local up = 0
local down = 0
local iface
for name, value in pairs(args) do
iface = name:match("^{(%S+) down_b}$")
if iface and iface ~= "lo" then down = down + value end
iface = name:match("^{(%S+) up_b}$")
if iface and iface ~= "lo" then up = up + value end
end
-- Update the graph
netgraph:add_value(up, 1)
netgraph:add_value(down, 2)
-- Format the string representation
local format = function(val)
if val > 500000 then
return string.format("%.1f MB", val/1000000.)
elseif val > 500 then
return string.format("%.1f KB", val/1000.)
end
return string.format("%d B", val)
end
-- Down
netdown.text = string.format('<span color="' .. beautiful.fg_widget_value ..
'">%08s</span>', format(down))
-- Up
return string.format('<span color="' .. beautiful.fg_widget_value ..
'">%08s</span>', format(up))
end, 3)
-- Memory usage
local memwidget = widget({ type = "textbox" })
vicious.register(memwidget, vicious.widgets.mem,
'<span color="' .. beautiful.fg_widget_value .. '">$1%</span>',
19)
local memicon = widget({ type = "imagebox" })
memicon.image = image(beautiful.icons .. "/widgets/mem.png")
-- Volume level
local volwidget = widget({ type = "textbox" })
vicious.register(volwidget, vicious.widgets.volume,
'<span color="' .. beautiful.fg_widget_value .. '">$2 $1%</span>',
17, "-D pulse Master")
volume = loadrc("volume", "vbe/volume")
volwidget:buttons(awful.util.table.join(
awful.button({ }, 1, volume.mixer),
awful.button({ }, 3, function() volume.toggle("Master") end),
awful.button({ }, 4, function() volume.increase("Master") end),
awful.button({ }, 5, function() volume.decrease("Master") end)))
-- File systems
local fs = { "/",
"/home",
"/var",
"/usr",
"/tmp",
"/var/lib/systems" }
local fsicon = widget({ type = "imagebox" })
fsicon.image = image(beautiful.icons .. "/widgets/disk.png")
local fswidget = widget({ type = "textbox" })
vicious.register(fswidget, vicious.widgets.fs,
function (widget, args)
local result = ""
for _, path in pairs(fs) do
local used = args["{" .. path .. " used_p}"]
local color = beautiful.fg_widget_value
if used then
if used > 90 then
color = beautiful.fg_widget_value_important
end
local name = string.gsub(path, "[%w/]*/(%w+)", "%1")
if name == "/" then name = "root" end
result = string.format(
'%s%s<span color="' .. beautiful.fg_widget_label .. '">%s: </span>' ..
'<span color="' .. color .. '">%2d%%</span>',
result, #result > 0 and " " or "", name, used)
end
end
return result
end, 53, "-lx fuse -x aufs")
local notifications = widget({ type = "imagebox" })
notifications.image = image(beautiful.icons .. "/widgets/notifications-enabled.png")
notifications:buttons(awful.util.table.join(
awful.button({ }, 1,
function()
local state = "enabled"
naughty.toggle()
if naughty.is_suspended() then
state = "disabled"
end
notifications.image = image(beautiful.icons .. "/widgets/notifications-" .. state .. ".png")
end)))
local systray = widget({ type = "systray" })
-- Wibox initialisation
local wibox = {}
local promptbox = {}
local layoutbox = {}
local taglist = {}
local tasklist = {}
tasklist.buttons = awful.util.table.join(
awful.button({ }, 1, function (c)
if not c:isvisible() then
awful.tag.viewonly(c:tags()[1])
end
-- This will also un-minimize
-- the client, if needed
client.focus = c
c:raise()
end))
for s = 1, screen.count() do
promptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright })
layoutbox[s] = awful.widget.layoutbox(s)
tasklist[s] = awful.widget.tasklist(
function(c)
local title, color, _, icon = awful.widget.tasklist.label.currenttags(c, s)
return title, color, nil, icon
end, tasklist.buttons)
-- Create the taglist
taglist[s] = awful.widget.taglist.new(s,
awful.widget.taglist.label.all)
-- Create the wibox
wibox[s] = awful.wibox({ screen = s,
fg = beautiful.fg_normal,
bg = beautiful.bg_widget,
position = "top",
height = 16 * theme.scale,
})
-- Add widgets to the wibox
local on = function(n, what)
if s == n or n > screen.count() then return what end
return ""
end
wibox[s].widgets = {
{
screen.count() > 1 and sepopen or "",
taglist[s],
screen.count() > 1 and spacer or "",
layoutbox[s],
screen.count() > 1 and sepclose or "",
promptbox[s],
layout = awful.widget.layout.horizontal.leftright
},
on(1, systray),
on(1, notifications),
sepclose, datewidget, screen.count() > 1 and dateicon or "", spacer,
on(2, volwidget), on(2, spacer),
on(2, batwidget.widget),
on(2, batwidget.widget ~= "" and baticon or ""),
on(2, batwidget.widget ~= "" and spacer or ""),
on(2, fswidget), screen.count() > 1 and on(2, fsicon) or "",
screen.count() > 1 and on(2, sepopen) or on(2, spacer),
screen.count() > 1 and on(1, netgraph.widget) or "",
on(1, netdownicon), on(1, netdown),
on(1, netupicon), on(1, netup), on(1, spacer),
on(1, memwidget), on(1, memicon), on(1, spacer),
on(1, cpuwidget), on(1, cpuicon), on(1, sepopen),
tasklist[s],
layout = awful.widget.layout.horizontal.rightleft }
end
config.keys.global = awful.util.table.join(
config.keys.global,
awful.key({ modkey }, "r", function () promptbox[mouse.screen]:run() end,
"Prompt for a command"))
config.taglist = taglist

View file

@ -1,10 +0,0 @@
-- Lockscreen
local lock = function()
os.execute("xset s activate")
end
config.keys.global = awful.util.table.join(
config.keys.global,
awful.key({}, "XF86ScreenSaver", lock),
awful.key({ modkey, }, "Delete", lock))

View file

@ -1,66 +0,0 @@
-- Menu with autorandr choices
local icons = loadrc("icons", "vbe/icons")
-- Build available choices
local function menu()
return {
{ "Autodetect", "autorandr --change" },
{ "Clone", "autorandr --load common" },
{ "Horizontal", "autorandr --load horizontal" },
{ "Vertical", "autorandr --load vertical" },
{ "Keep current configuration", nil },
}
end
-- Display xrandr notifications from choices
local state = { iterator = nil,
timer = nil,
cid = nil }
local function xrandr()
-- Stop any previous timer
if state.timer then
state.timer:stop()
state.timer = nil
end
-- Build the list of choices
if not state.iterator then
state.iterator = awful.util.table.cycle(
menu(),
function() return true end)
end
-- Select one and display the appropriate notification
local next = state.iterator()
local label, action
if not next then
state.iterator = nil
return xrandr()
else
label, action = unpack(next)
end
state.cid = naughty.notify({ text = label,
icon = icons.lookup({ name = "display", type = "devices" }),
timeout = 4,
screen = mouse.screen, -- Important, not all screens may be visible
font = "Free Sans 18",
replaces_id = state.cid }).id
-- Setup the timer
state.timer = timer { timeout = 4 }
state.timer:add_signal("timeout",
function()
state.timer:stop()
state.timer = nil
state.iterator = nil
if action then
awful.util.spawn(action, false)
end
end)
state.timer:start()
end
config.keys.global = awful.util.table.join(
config.keys.global,
awful.key({}, "XF86Display", xrandr))

View file

@ -1,16 +0,0 @@
[Unit]
Description=Awesome window manager for %I
PartOf=graphical-session@%i.target
After=autorandr@%i.service
After=picom@%i.service
After=xsettingsd@%i.service
After=tmux.service
After=ssh-agent.service
Before=nm-applet@%i.service
Before=wallpaper@%i.service
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/awesome
ExecStopPost=/bin/systemctl --user stop graphical-session@%i.target
Restart=on-failure

View file

@ -1,18 +0,0 @@
[Unit]
Description=Graphical user session for %I
StopWhenUnneeded=yes
Wants=autorandr@%i.service
Wants=awesome@%i.service
Wants=picom@%i.service
Wants=inputplug@%i.service
Wants=misc-x@%i.service
Wants=nm-applet@%i.service
Wants=policykit-agent@%i.service
Wants=redshift@%i.service
Wants=wallpaper@%i.timer
Wants=xiccd@%i.service
Wants=xsettingsd@%i.service
Wants=xss-lock@%i.service
Wants=tmux.service
Wants=ssh-agent.service
Wants=pulseaudio.service

View file

@ -1,9 +0,0 @@
[Unit]
Description=XInput event monitor for %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStartPre=/usr/bin/setxkbmap us
ExecStart=%h/.local/bin/inputplug -d -0 -c %h/.config/awesome/bin/input-event
Restart=on-failure

View file

@ -1,11 +0,0 @@
[Unit]
Description=Miscellaneous settings for X11 on %I
PartOf=graphical-session@%i.target
After=ssh-agent.service
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/xset -b
ExecStart=%h/.config/awesome/bin/ssh-add
Type=oneshot
RemainAfterExit=false

View file

@ -1,8 +0,0 @@
[Unit]
Description=Network Manager applet for %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/nm-applet
Restart=on-failure

View file

@ -1,10 +0,0 @@
[Unit]
Description=Compositor for X11 on %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/picom --backend glx \
--xrender-sync-fence \
--vsync
Restart=on-failure

View file

@ -1,9 +0,0 @@
[Unit]
Description=SSH key agent
[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStartPre=/usr/bin/dbus-update-activation-environment SSH_AUTH_SOCK
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
Restart=always

View file

@ -1,14 +0,0 @@
[Unit]
Description=Build a wallpaper for %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
Environment=WALLPAPER_DIRECTORY=%h/.config/awesome/wallpapers
Environment=WALLPAPER_OUTPUT=%h/.cache/awesome/current-wallpaper-%i.png
ExecStart=%h/.config/awesome/bin/build-wallpaper --crop \
--directory $WALLPAPER_DIRECTORY \
--target $WALLPAPER_OUTPUT
ExecStart=/usr/bin/fvwm-root -r $WALLPAPER_OUTPUT
Type=oneshot
RemainAfterExit=false

View file

@ -1,7 +0,0 @@
[Unit]
Description=Wallpaper rotation for %I
PartOf=graphical-session@%i.target
[Timer]
OnUnitActiveSec=2h
RandomizedDelaySec=10m

View file

@ -1,8 +0,0 @@
[Unit]
Description=X color management for %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/xiccd --edid
Restart=on-failure

View file

@ -1,3 +0,0 @@
[Unit]
Description=X session on %I
BindsTo=graphical-session@%i.target

View file

@ -1,9 +0,0 @@
[Unit]
Description=XSETTINGS daemon for %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStart=/usr/bin/xsettingsd -c %h/.xsettingsd
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=on-failure

View file

@ -1,8 +0,0 @@
[Unit]
Description=Manage X screen saver on %I
PartOf=graphical-session@%i.target
[Service]
Environment=DISPLAY=%I
ExecStart=%h/.config/awesome/bin/xss-lock start
Restart=on-failure

View file

@ -3,9 +3,6 @@
# Ensure we use the appropriate gtkrc-2.0 file
export GTK2_RC_FILES=$HOME/.gtkrc-2.0
# Java incompatibility with awesome
export _JAVA_AWT_WM_NONREPARENTING=1
# We do not want to rely on crappy mailcap
export MAILCAPS=$HOME/.mailcap
@ -20,9 +17,20 @@ export NO_AT_BRIDGE=1
unset LC_ALL
[ -e ~/.zshenv ] && . ~/.zshenv
# Copy dotfiles
while read source target; do
mkdir -p $(dirname $target)
ln -sf ~/.config/i3/dotfiles/$source $HOME/$target
done <<EOF
Xresources .Xresources
gtkrc-2.0 .gtkrc-2.0
gtkrc-3.0 .config/gtk-3.0/settings.ini
qt5ct.conf .config/qt5ct/qt5ct.conf
systemd .config/systemd/user
firefox.js .mozilla/firefox/*/user.js
EOF
# Services are started with systemd
systemctl --user import-environment
mkdir -p ~/.config/systemd
ln -nsf ~/.config/awesome/systemd ~/.config/systemd/user
systemctl --user daemon-reload
exec systemctl --user start --wait xsession@$(systemd-escape -- "$DISPLAY").target
exec systemctl --user start --wait xsession.target