update: dotfiles

This commit is contained in:
rxyhn 2022-03-26 20:33:46 +07:00
parent 18dbc601b7
commit fcbd548c7d
41 changed files with 1789 additions and 2106 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,133 +1,120 @@
#!/bin/bash
#!/bin/sh
# stolen from snap
<<screensht
_____ _____ _____ _____ _____ _____ _____ _____ _____
| __| | __ | __| __| | | __| | |_ _|
|__ | --| -| __| __| | | |__ | | | |
|_____|_____|__|__|_____|_____|_|___|_____|__|__| |_|
~ Script to take screenshots with maim ~
_____ _____ _____ _____ _____ _____ _____ _____ _____
| __| | __ | __| __| | | __| | |_ _|
|__ | --| -| __| __| | | |__ | | | |
|_____|_____|__|__|_____|_____|_|___|_____|__|__| |_|
~ Script to take screenshots using maim and AwesomeWM API ~
screensht
# =============================================
screenshot_dir=$(xdg-user-dir PICTURES)/Screenshots/
# Directory
_SCREENSHOT_DIR_=$HOME/Pictures/Screenshots
_ORIGINAL_DIR_=$_SCREENSHOT_DIR_/Original
# Color
_FG_COLOR_='#1d1f21'
_BG_COLOR_='#c5c8c6'
_BG_SIZE_=10
# Border Size Applied when value greater than or equal 3
_BORDER_SIZE_=0
_SHADOW_SIZE_='50x10+0+10' # [ weight ] x [ radius ] + [ horizontal ] x [ vertical ]
_ROUNDED_CORNER_=4
# =============================================
# List of Colors
Light_Red="\033[1;31m"
Light_Green="\033[1;32m"
Yellow="\033[1;33m"
Light_Blue="\033[1;34m"
Light_Purple="\033[1;35m"
Light_Cyan="\033[1;36m"
NoColor="\033[0m"
function check() {
if [[ $? -eq 1 && ${PIPESTATUS[0]} -eq 1 ]]; then
exit 1
fi
# Check save directory
# Create it if it doesn't exist
function check_dir() {
if [ ! -d "$screenshot_dir" ];
then
mkdir -p "$screenshot_dir"
fi
}
function get_latest_img() {
_LATEST_IMAGE_=$(/bin/ls -th $_SCREENSHOT_DIR_ | grep -vE '.screensht.png$' | grep -E '.png$' | head -n 1)
# Main function
function shot() {
check_dir
file_loc="${screenshot_dir}screensht_$(date +%y-%m-%d_%H:%M:%S).png"
maim_command="$1"
notif_message="$2"
# Execute maim command
${maim_command} "${file_loc}"
# Exit if the user cancels the screenshot
# So it means there's no new screenshot image file
if [ ! -f "${file_loc}" ];
then
exit;
fi
# Copy to clipboard
xclip -selection clipboard -t image/png -i "${screenshot_dir}"/`ls -1 -t "${screenshot_dir}" | head -1` &
awesome-client "
-- IMPORTANT NOTE: THIS PART OF THE SCRIPT IS LUA!
naughty = require('naughty')
awful = require('awful')
beautiful = require('beautiful')
dpi = beautiful.xresources.apply_dpi
local open_image = naughty.action {
name = 'Open',
icon_only = false,
}
local open_folder = naughty.action {
name = 'Open Folder',
icon_only = false,
}
local delete_image = naughty.action {
name = 'Delete',
icon_only = false,
}
-- Execute the callback when 'Open' is pressed
open_image:connect_signal('invoked', function()
awful.spawn('xdg-open ' .. '${file_loc}', false)
end)
open_folder:connect_signal('invoked', function()
awful.spawn('xdg-open ' .. '${screenshot_dir}', false)
end)
-- Execute the callback when 'Delete' is pressed
delete_image:connect_signal('invoked', function()
awful.spawn('gio trash ' .. '${file_loc}', false)
end)
-- Show notification
naughty.notification ({
app_name = 'Screenshot Tool',
icon = '${file_loc}',
timeout = 10,
title = '<b>Screensht!</b>',
message = '${notif_message}',
actions = { open_image, open_folder, delete_image }
})
"
if [[ $( echo "$_LATEST_IMAGE_" | wc -w ) -eq 0 ]]; then
exit 1
else
_LATEST_IMAGE_="$_SCREENSHOT_DIR_/$_LATEST_IMAGE_"
fi
}
function convert() {
_target_file_=$( echo "$_LATEST_IMAGE_" | sed 's/.png/.screensht.png/g' )
# Check the args passed
if [ -z "$1" ] || ([ "$1" != 'full' ] && [ "$1" != 'area' ]);
then
echo "
Requires an argument:
area - Area screenshot
full - Fullscreen screenshot
if [[ $_BORDER_SIZE_ -ge 3 ]]; then
magick convert "$_LATEST_IMAGE_" \
-format 'roundrectangle 1,1 %[fx:w+4],%[fx:h+4] '"$_ROUNDED_CORNER_"','"$_ROUNDED_CORNER_"''\
info: > $_SCREENSHOT_DIR_/_rounded_.mvg
check
magick convert "$_LATEST_IMAGE_" -border $_BORDER_SIZE_ -alpha transparent \
-background none -fill white -stroke none -strokewidth 0 \
-draw "@"$_SCREENSHOT_DIR_"/_rounded_.mvg" $_SCREENSHOT_DIR_/_rounded_mask_.png
check
magick convert "$_LATEST_IMAGE_" -border $_BORDER_SIZE_ -alpha transparent \
-background none -fill none -stroke $_FG_COLOR_ -strokewidth $_BORDER_SIZE_ \
-draw "@"$_SCREENSHOT_DIR_"/_rounded_.mvg" $_SCREENSHOT_DIR_/_rounded_overlay_.png
check
magick convert "$_LATEST_IMAGE_" -alpha set -bordercolor none -border $_BORDER_SIZE_ \
$_SCREENSHOT_DIR_/_rounded_mask_.png -compose DstIn -composite \
$_SCREENSHOT_DIR_/_rounded_overlay_.png -compose Over -composite \
"$_target_file_" && \
rm -f $_SCREENSHOT_DIR_/_rounded_*
check
else
magick convert "$_LATEST_IMAGE_" \( +clone -alpha extract -draw 'fill black polygon 0,0 0,'"$_ROUNDED_CORNER_"' '"$_ROUNDED_CORNER_"',0 fill white circle '"$_ROUNDED_CORNER_"','"$_ROUNDED_CORNER_"' '"$_ROUNDED_CORNER_"',0' \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite -compose over "$_target_file_"
check
fi
magick convert "$_target_file_" \( +clone -background black -shadow $_SHADOW_SIZE_ \) +swap -background none -layers merge +repage "$_target_file_" \
&& magick convert "$_target_file_" -bordercolor $_BG_COLOR_ -border $_BG_SIZE_ "$_target_file_"
check
magick convert "$_target_file_" -gravity North -background $_BG_COLOR_ -splice 0x$(( $_BG_SIZE_ / 2 )) "$_target_file_"
check
magick convert "$_target_file_" -profile /usr/share/color/icc/colord/sRGB.icc "$_target_file_"
check
}
function summary() {
_runtime_job_=$(($2-$1))
hours=$((_runtime_job_ / 3600)); minutes=$(( (_runtime_job_ % 3600) / 60 )); seconds=$(( (_runtime_job_ % 3600) % 60 ))
if [[ $3 != "failed" ]]; then
xclip -selection clipboard -t image/png -i $_target_file_ && notify-send -u normal -t 3000 "Awesome-Maim: $_target_file_ Copied"
fi
}
function main() {
_start_job_=$(date +%Y.%m.%d-%H.%M.%S)
maim -u -b 3 -m 5 -s ~/Pictures/Screenshots/$_start_job_.png> /dev/null 2>&1
check
get_latest_img
convert
mv $_LATEST_IMAGE_ ~/Pictures/Screenshots/Original/
notify-send -i ~/Pictures/Screenshots/Original/$_start_job_.png "Screenshot Taken" "saved to ~/Pictures/Screenshots"
_end_job_=$(date +%s)
}
if [[ ! -d "$_SCREENSHOT_DIR_" || ! -d "$_ORIGINAL_DIR_" ]]; then
mkdir -p "$_SCREENSHOT_DIR_"
mkdir -p "$_ORIGINAL_DIR_"
Example:
./screensht area
./screensht full
"
elif [ "$1" = 'full' ];
then
msg="Full screenshot saved and copied to clipboard!"
shot 'maim -u -m 5' "${msg}"
elif [ "$1" = 'area' ];
then
msg='Area screenshot saved and copied to clipboard!'
shot 'maim -u -b 2 -m 5 -s' "${msg}"
fi
clear
main

View file

@ -10,9 +10,14 @@ local function run_once(cmd)
findme, cmd), false)
end
-- picom
-- music
run_once("mpd")
run_once("mpDris2")
run_once("picom --experimental-backends --config " ..
gears.filesystem.get_configuration_dir() .. "theme/picom.conf")
-- picom
run_once("picom --experimental-backends --config " .. theme_dir .. "picom.conf")
-- auth
run_once("/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1")
return autostart

View file

@ -1,51 +0,0 @@
local awful = require("awful")
local wibox = require("wibox")
local beautiful = require("beautiful")
local bling = require("module.bling")
bling.module.flash_focus.enable()
-- Set Tile Wallpaper
-- bling.module.tiled_wallpaper("", s, {
-- fg = beautiful.lighter_bg,
-- bg = beautiful.xbackground,
-- offset_y = 6,
-- offset_x = 18,
-- font = "Iosevka",
-- font_size = 17,
-- padding = 70,
-- zickzack = true
-- })
-- Enable Tag Preview Module from Bling
bling.widget.tag_preview.enable {
show_client_content = false,
placement_fn = function(c)
awful.placement.left(c, {
margins = {
left = beautiful.wibar_width + 11
}
})
end,
scale = 0.15,
honor_padding = true,
honor_workarea = false,
background_widget = wibox.widget {
bg = beautiful.xbackground,
widget = wibox.widget.background
}
}
-- Enable Task Preview Module from Bling
bling.widget.task_preview.enable {
placement_fn = function(c)
awful.placement.top_left(c, {
margins = {
top = 10,
left = beautiful.wibar_width + 11
}
})
end
}
require('ui.widgets.window_switcher').enable()

View file

@ -1,35 +0,0 @@
-- Standard awesome library
local gears = require("gears")
local naughty = require("naughty")
local awful = require("awful")
require("awful.autofocus")
-- Theme handling library
local beautiful = require("beautiful")
local dpi = beautiful.xresources.apply_dpi
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
naughty.connect_signal("request::display_error", function(message, startup)
naughty.notification {
urgency = "critical",
title = "Oops, an error happened" ..
(startup and " during startup!" or "!"),
message = message
}
end)
-- set wallpapers
awful.screen.connect_for_each_screen(function(s)
gears.wallpaper.maximized(beautiful.wallpaper, s, false, nil)
end)
-- Screen Padding and Tags
screen.connect_signal("request::desktop_decoration", function(s)
-- Screen padding
screen[s].padding = {left = 0, right = 0, top = 0, bottom = 0}
-- Each screen has its own tag table.
awful.tag({"1", "2", "3", "4", "5"}, s, awful.layout.layouts[1])
end)

View file

@ -0,0 +1,96 @@
-- Standard awesome library
local awful = require("awful")
require("awful.autofocus")
local gears = require("gears")
local gfs = gears.filesystem
local naughty = require("naughty")
local wibox = require("wibox")
-- Theme handling library
local beautiful = require("beautiful")
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
naughty.connect_signal("request::display_error", function(message, startup)
naughty.notification {
urgency = "critical",
title = "Oops, an error happened" ..
(startup and " during startup!" or "!"),
message = message
}
end)
client.connect_signal("request::manage", function(c)
-- Add missing icon to client
if not c.icon then
local icon = gears.surface(beautiful.awesome_logo)
c.icon = icon._native
icon:finish()
end
-- Set the windows at the slave,
if awesome.startup and not c.size_hints.user_position and
not c.size_hints.program_position then
-- Prevent clients from being unreachable after screen count changes.
awful.placement.no_offscreen(c)
end
end)
-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
c:emit_signal("request::activate", "mouse_enter", {raise = false})
end)
client.connect_signal("focus",
function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus",
function(c) c.border_color = beautiful.border_normal end)
-- Hide all windows when a splash is shown
awesome.connect_signal("widgets::splash::visibility", function(vis)
local t = screen.primary.selected_tag
if vis then
for idx, c in ipairs(t:clients()) do c.hidden = true end
else
for idx, c in ipairs(t:clients()) do c.hidden = false end
end
end)
--Bling
----------
local bling = require("module.bling")
bling.module.flash_focus.enable()
-- Tag Preview
bling.widget.tag_preview.enable {
show_client_content = false,
placement_fn = function(c)
awful.placement.top_left(c, {
margins = {
top = 99,
left = beautiful.wibar_width + 55
}
})
end,
scale = 0.15,
honor_padding = true,
honor_workarea = false,
background_widget = wibox.widget {
-- image = beautiful.wallpaper,
-- horizontal_fit_policy = "fit",
-- vertical_fit_policy = "fit",
-- widget = wibox.widget.imagebox
bg = beautiful.wibar_bg,
widget = wibox.container.bg
}
}
require('ui.widgets.window_switcher').enable()

View file

@ -1,6 +1,86 @@
require("configuration.bling")
-- Standard awesome library
local awful = require("awful")
local gears = require("gears")
local gfs = gears.filesystem
local wibox = require("wibox")
-- Theme handling library
local beautiful = require("beautiful")
-- Helpers
local helpers = require("helpers")
-- Bling Module
local bling = require("module.bling")
-- Layout Machi
local machi = require("module.layout-machi")
beautiful.layout_machi = machi.get_icon()
-- This is to slave windows' positions in floating layout
require("module.savefloats")
-- Better mouse resizing on tiled
require("module.better-resize")
-- Desktop
-------------
-- Custom Layouts
local mstab = bling.layout.mstab
local centered = bling.layout.centered
local horizontal = bling.layout.horizontal
local equal = bling.layout.equalarea
local deck = bling.layout.deck
machi.editor.nested_layouts = {
["0"] = deck,
["1"] = awful.layout.suit.spiral,
["2"] = awful.layout.suit.fair,
["3"] = awful.layout.suit.fair.horizontal
}
-- Set the layouts
tag.connect_signal("request::default_layouts", function()
awful.layout.append_default_layouts({
awful.layout.suit.tile, awful.layout.suit.floating, centered, mstab,
horizontal, machi.default_layout, equal, deck
})
end)
-- Screen Padding and Tags
screen.connect_signal("request::desktop_decoration", function(s)
-- Screen padding
screen[s].padding = {left = dpi(40), right = dpi(15), top = dpi(15), bottom = dpi(15)}
-- Each screen has its own tag table.
awful.tag({"1", "2", "3", "4", "5"}, s, awful.layout.layouts[1])
end)
-- Wallpapers
-- set wallpapers
awful.screen.connect_for_each_screen(function(s)
-- gears.wallpaper.maximized(beautiful.wallpaper, s, false, nil)
gears.wallpaper.set(beautiful.xcolor8)
end)
-- Set Tile Wallpaper
-- bling.module.tiled_wallpaper("", s, {
-- fg = beautiful.lighter_bg,
-- bg = beautiful.xbackground,
-- offset_y = 6,
-- offset_x = 18,
-- font = "Iosevka",
-- font_size = 17,
-- padding = 70,
-- zickzack = true
-- })
-- Stuff
-----------
require("configuration.keys")
require("configuration.ruled")
require("configuration.window")
require("configuration.desktop")
require("configuration.extras")
require("configuration.menu")

View file

@ -16,6 +16,7 @@ local naughty = require("naughty")
-- Bling
local bling = require("module.bling")
local playerctl = bling.signal.playerctl.lib()
-- Machi
local machi = require("module.layout-machi")
@ -25,7 +26,7 @@ local helpers = require("helpers")
-- Default modkey.
modkey = "Mod4"
altkey = "Mod1"
alt = "Mod1"
ctrl = "Control"
shift = "Shift"
@ -40,31 +41,34 @@ awful.keyboard.append_global_keybindings({
end,
{description = "open applications menu", group = "launcher"}),
awful.key({modkey, shift}, "d", function()
dash_toggle()
dashboard_toggle()
end,
{description = "toggle dashboard", group = "launcher"}),
awful.key({modkey}, "f", function()
awful.spawn(filemanager)
awful.spawn(file_manager)
end,
{description = "open file manager", group = "launcher"}),
awful.key({modkey}, "w", function()
awful.spawn.with_shell(browser)
end,
{description = "open web browser", group = "launcher"}),
awful.key({modkey}, "x", function()
awful.spawn.with_shell("xcolor-pick")
end,
{description = "open color-picker", group = "launcher"})
})
-- Client and Tabs Bindings
awful.keyboard.append_global_keybindings({
awful.key({altkey}, "a", function()
awful.key({alt}, "a", function()
bling.module.tabbed.pick_with_dmenu()
end,
{description = "pick client to add to tab group", group = "tabs"}),
awful.key({altkey}, "s", function()
awful.key({alt}, "s", function()
bling.module.tabbed.iter()
end,
{description = "iterate through tabbing group", group = "tabs"}),
awful.key({altkey}, "d", function()
awful.key({alt}, "d", function()
bling.module.tabbed.pop()
end,
{description = "remove focused client from tabbing group",group = "tabs"}),
@ -107,73 +111,82 @@ awful.keyboard.append_global_keybindings({
awful.key({modkey}, "u",
awful.client.urgent.jumpto,
{description = "jump to urgent client", group = "client"}),
awful.key({altkey}, "Tab", function()
awful.key({alt}, "Tab", function()
awesome.emit_signal("bling::window_switcher::turn_on")
end,
{description = "window switcher", group = "client"})
})
-- Awesomewm
-- Hotkeys
awful.keyboard.append_global_keybindings({
-- Brightness Control
awful.key({}, "XF86MonBrightnessUp", function()
awful.spawn("brightnessctl set 5%+ -q")
end,
{description = "increase brightness", group = "awesome"}),
{description = "increase brightness", group = "hotkeys"}),
awful.key({}, "XF86MonBrightnessDown", function()
awful.spawn("brightnessctl set 5%- -q")
end,
{description = "decrease brightness", group = "awesome"}),
{description = "decrease brightness", group = "hotkeys"}),
-- Volume control
awful.key({}, "XF86AudioRaiseVolume", function()
awful.spawn("amixer -D pulse set Master 5%+")
helpers.volume_control(5)
end,
{description = "increase volume", group = "awesome"}),
{description = "increase volume", group = "hotkeys"}),
awful.key({}, "XF86AudioLowerVolume", function()
awful.spawn("amixer -D pulse set Master 5%-")
helpers.volume_control(-5)
end,
{description = "decrease volume", group = "awesome"}),
{description = "decrease volume", group = "hotkeys"}),
awful.key({}, "XF86AudioMute", function()
awful.spawn("amixer -D pulse set Master 1+ toggle")
helpers.volume_control(0)
end,
{description = "mute volume", group = "awesome"}),
{description = "mute volume", group = "hotkeys"}),
-- Media Control
-- Music
awful.key({}, "XF86AudioPlay", function()
awful.spawn("playerctl play-pause")
playerctl:play_pause()
end,
{description = "toggle playerctl", group = "awesome"}),
{description = "toggle music", group = "hotkeys"}),
awful.key({}, "XF86AudioPrev", function()
awful.spawn("playerctl previous")
playerctl:previous()
end,
{description = "playerctl previous", group = "awesome"}),
{description = "previous music", group = "hotkeys"}),
awful.key({}, "XF86AudioNext", function()
awful.spawn("playerctl next")
playerctl:next()
end,
{description = "playerctl next", group = "awesome"}),
{description = "next music", group = "hotkeys"}),
-- Screenshots
awful.key({}, "Print", function()
awful.spawn.with_shell("screensht")
awful.key({}, "Print", function()
awful.spawn.with_shell("screensht full")
end,
{description = "take a screenshot", group = "awesome"}),
{description = "take a full screenshot", group = "hotkeys"}),
awful.key({alt}, "Print", function()
awful.spawn.with_shell("screensht area")
end,
{description = "take a area screenshot", group = "hotkeys"}),
-- Lockscreen
awful.key({modkey}, "x", function()
lock_screen_show()
awful.key({modkey, ctrl}, "l", function()
lock_screen_show()
end,
{description = "lock screen", group = "awesome"}),
{description = "lock screen", group = "hotkeys"})
})
-- Awesome stuff
awful.key({modkey}, "F1",
-- Awesome stuff
awful.keyboard.append_global_keybindings({
awful.key({modkey}, "F1",
hotkeys_popup.show_help,
{description = "show help", group = "awesome"}),
awful.key({modkey, "Control"}, "r",
awful.key({modkey, ctrl}, "r",
awesome.restart,
{description = "reload awesome", group = "awesome"}),
awful.key({modkey, "Shift"}, "q",
awful.key({modkey, ctrl}, "q",
awesome.quit,
{description = "quit awesome", group = "awesome"})
})
@ -237,10 +250,10 @@ awful.keyboard.append_global_keybindings({
{description = "select previous layout", group = "layout"}),
-- Tag
awful.key({ modkey, altkey}, "Left",
awful.key({ modkey, alt}, "Left",
awful.tag.viewprev,
{description = "view previous", group = "tag"}),
awful.key({ modkey, altkey}, "Right",
awful.key({ modkey, alt}, "Right",
awful.tag.viewnext,
{description = "view next", group = "tag"}),
awful.key({ modkey}, "Escape",
@ -394,15 +407,6 @@ awful.keyboard.append_global_keybindings({
if tag then client.focus:toggle_tag(tag) end
end
end
}, awful.key {
modifiers = {modkey},
keygroup = "numpad",
description = "select layout directly",
group = "layout",
on_press = function(index)
local t = awful.screen.focused().selected_tag
if t then t.layout = t.layouts[index] or t.layout end
end
}
})
@ -419,9 +423,9 @@ awful.mouse.append_global_mousebindings({
end
end),
-- Right click
-- Middle click
awful.button({}, 2, function()
dash_toggle()
dashboard_toggle()
end),
-- Right click
@ -451,4 +455,4 @@ client.connect_signal("request::default_mousebindings", function()
end)
})
end)
-- EOF ------------------------------------------------------------------------

View file

@ -9,6 +9,8 @@ awful.screen.connect_for_each_screen(function(s)
-- Submenu
awesomemenu = {
{"Hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end},
{"Manual", terminal .. " -e man awesome"},
{"Edit Config", editor .. " " .. awesome.conffile},
{"Restart", awesome.restart},
{"Quit", function() awesome.quit() end}
}
@ -27,11 +29,11 @@ awful.screen.connect_for_each_screen(function(s)
-- Mainmenu
mymainmenu = awful.menu({
items = {
{"Terminal", terminal, beautiful.awesome_logo},
{"Code Editor", vscode},
{"File Manager", filemanager},
{"Web Browser", browser},
{"Discord", discord},
{"Terminal", function() awful.spawn.with_shell(terminal) end, beautiful.awesome_logo},
{"Code Editor", function() awful.spawn.with_shell(vscode) end},
{"File Manager", function() awful.spawn.with_shell(file_manager) end},
{"Web Browser", function() awful.spawn.with_shell(browser) end},
{"Music", function() awful.spawn.with_shell(music_client) end},
{"AwesomeWM", awesomemenu},
{"Power Menu", powermenu}
}

View file

@ -1,7 +1,23 @@
-- Standard awesome library
local gears = require("gears")
local awful = require("awful")
-- Theme handling library
local beautiful = require("beautiful")
-- Notification handling library
local naughty = require("naughty")
-- Ruled
local ruled = require("ruled")
-- Helpers
local helpers = require("helpers")
-- Get screen geometry
local screen_width = awful.screen.focused().geometry.width
local screen_height = awful.screen.focused().geometry.height
ruled.client.connect_signal("request::rules", function()
-- Global
@ -13,11 +29,12 @@ ruled.client.connect_signal("request::rules", function()
raise = true,
size_hints_honor = false,
screen = awful.screen.preferred,
titlebars_enabled = beautiful.titlebar_enabled,
placement = awful.placement.no_overlap+awful.placement.no_offscreen
}
}
-- tasklist order
-- Tasklist order
ruled.client.append_rule {
id = "tasklist_order",
rule = {},
@ -25,58 +42,135 @@ ruled.client.connect_signal("request::rules", function()
callback = awful.client.setslave
}
-- Float em
ruled.client.append_rule {
id = "floating",
rule_any = {
class = {"Arandr", "Blueman-manager", "Sxiv", "fzfmenu"},
role = {
"pop-up" -- e.g. Google Chrome's (detached) Developer Tools.
},
name = {"Friends List", "Steam - News"},
instance = {"spad", "discord", "music"}
},
properties = {floating = true, placement = awful.placement.centered}
}
-- Borders
ruled.client.append_rule {
id = "borders",
rule_any = {type = {"normal", "dialog"}},
except_any = {
role = {"Popup"},
type = {"splash"},
name = {"^discord.com is sharing your screen.$"}
},
properties = {
border_width = beautiful.border_width,
border_color = beautiful.border_normal
}
}
-- Center Placement
ruled.client.append_rule {
id = "center_placement",
rule_any = {
type = {"dialog"},
class = {"Steam", "discord", "markdown_input"},
instance = {"markdown_input"},
role = {"GtkFileChooserDialog", "conversation"}
},
properties = {placement = awful.placement.center}
}
-- Titlebar rules
ruled.client.append_rule {
id = "titlebars",
rule_any = {type = {"normal", "dialog"}},
except_any = {
class = {"Steam", "zoom", "jetbrains-studio", "chat", "Org.gnome.Nautilus", "Firefox", "Google-chrome", "Brave-browser"},
type = {"splash"},
instance = {"onboard"},
name = {"^discord.com is sharing your screen.$"}
rule_any = {
class = {
"discord",
"Spotify",
"firefox",
"Org.gnome.Nautilus"
},
type = {
"splash"
},
name = {
"^discord.com is sharing your screen.$" -- Discord (running in browser) screen sharing popup
}
},
properties = {titlebars_enabled = true}
properties = {
titlebars_enabled = false
}
}
-- Float
ruled.client.append_rule {
id = "floating",
rule_any = {
instance = {
"Devtools", -- Firefox devtools
},
class = {
"Lxappearance",
"Nm-connection-editor",
},
name = {
"Event Tester", -- xev
},
role = {
"AlarmWindow",
"pop-up",
"GtkFileChooserDialog",
"conversation",
},
type = {
"dialog",
}
},
properties = { floating = true, placement = helpers.centered_client_placement }
}
-- Centered
ruled.client.append_rule {
id = "centered",
rule_any = {
type = {
"dialog",
},
class = {
-- "discord",
},
role = {
"GtkFileChooserDialog",
"conversation",
}
},
properties = { placement = helpers.centered_client_placement },
}
-- Music clients (usually a terminal running ncmpcpp)
ruled.client.append_rule {
rule_any = {
class = {
"music"
},
instance = {
"music"
}
},
properties = {
floating = true,
width = screen_width * 0.25,
height = screen_height * 0.4,
placement = helpers.centered_client_placement
}
}
-- Image viewers
ruled.client.append_rule {
rule_any = {
class = {
"feh",
"imv"
}
},
properties = {
floating = true,
width = screen_width * 0.7,
height = screen_height * 0.75
},
callback = function (c)
awful.placement.centered(c,{honor_padding = true, honor_workarea=true})
end
}
-- Mpv
ruled.client.append_rule {
rule = { class = "mpv" },
properties = {},
callback = function (c)
-- make it floating, ontop and move it out of the way if the current tag is maximized
if awful.layout.get(awful.screen.focused()) == awful.layout.suit.floating then
c.floating = true
c.ontop = true
c.width = screen_width * 0.30
c.height = screen_height * 0.35
awful.placement.bottom_right(c, {
honor_padding = true,
honor_workarea = true,
margins = { bottom = beautiful.useless_gap * 2, right = beautiful.useless_gap * 2 }
})
awful.titlebar.hide(c, beautiful.titlebar_pos)
end
-- restore `ontop` after fullscreen is disabled
c:connect_signal("property::fullscreen", function ()
if not c.fullscreen then
c.ontop = true
end
end)
end
}
end)

View file

@ -1,170 +0,0 @@
local awful = require("awful")
local gears = require("gears")
local gfs = gears.filesystem
local wibox = require("wibox")
local beautiful = require("beautiful")
local dpi = require("beautiful.xresources").apply_dpi
local helpers = require("helpers")
-- Bling Module
local bling = require("module.bling")
-- Layout Machi
local machi = require("module.layout-machi")
beautiful.layout_machi = machi.get_icon()
-- This is to slave windows' positions in floating layout
require("module.savefloats")
-- Better mouse resizing on tiled
require("module.better-resize")
client.connect_signal("request::manage", function(c)
if not c.icon then
local i = gears.surface(gfs.get_configuration_dir() ..
"theme/assets/icons/awesome.png")
c.icon = i._native
end
-- Set the windows at the slave,
if awesome.startup and not c.size_hints.user_position and
not c.size_hints.program_position then
-- Prevent clients from being unreachable after screen count changes.
awful.placement.no_offscreen(c)
end
end)
-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
c:emit_signal("request::activate", "mouse_enter", {raise = false})
end)
client.connect_signal("focus",
function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus",
function(c) c.border_color = beautiful.border_normal end)
-- Custom Layouts -------------------------------------------------------------
local mstab = bling.layout.mstab
local centered = bling.layout.centered
local horizontal = bling.layout.horizontal
local equal = bling.layout.equalarea
local deck = bling.layout.deck
machi.editor.nested_layouts = {
["0"] = deck,
["1"] = awful.layout.suit.spiral,
["2"] = awful.layout.suit.fair,
["3"] = awful.layout.suit.fair.horizontal
}
-- Set the layouts
tag.connect_signal("request::default_layouts", function()
awful.layout.append_default_layouts({
awful.layout.suit.tile, awful.layout.suit.floating, centered, mstab,
horizontal, machi.default_layout, equal, deck
})
end)
-- Layout List Widget ---------------------------------------------------------
-- List
local ll = awful.widget.layoutlist {
source = awful.widget.layoutlist.source.default_layouts, -- DOC_HIDE
spacing = dpi(24),
base_layout = wibox.widget {
spacing = dpi(24),
forced_num_cols = 4,
layout = wibox.layout.grid.vertical
},
widget_template = {
{
{
id = "icon_role",
forced_height = dpi(68),
forced_width = dpi(68),
widget = wibox.widget.imagebox
},
margins = dpi(24),
widget = wibox.container.margin
},
id = "background_role",
forced_width = dpi(68),
forced_height = dpi(68),
widget = wibox.container.background
}
}
-- Popup
local layout_popup = awful.popup {
widget = wibox.widget {
{ll, margins = dpi(24), widget = wibox.container.margin},
bg = beautiful.xbackground,
shape = helpers.rrect(beautiful.border_radius),
border_color = beautiful.widget_border_color,
border_width = beautiful.widget_border_width,
widget = wibox.container.background
},
placement = awful.placement.centered,
ontop = true,
visible = false,
bg = beautiful.xbackground .. "00"
}
-- Key Bindings for Widget ----------------------------------------------------
function gears.table.iterate_value(t, value, step_size, filter, start_at)
local k = gears.table.hasitem(t, value, true, start_at)
if not k then return end
step_size = step_size or 1
local new_key = gears.math.cycle(#t, k + step_size)
if filter and not filter(t[new_key]) then
for i = 1, #t do
local k2 = gears.math.cycle(#t, new_key + i)
if filter(t[k2]) then return t[k2], k2 end
end
return
end
return t[new_key], new_key
end
awful.keygrabber {
start_callback = function() layout_popup.visible = true end,
stop_callback = function() layout_popup.visible = false end,
export_keybindings = true,
stop_event = "release",
stop_key = {"Escape", "Super_L", "Super_R", "Mod4"},
keybindings = {
{
{modkey, "Shift"}, " ", function()
awful.layout.set(gears.table.iterate_value(ll.layouts,
ll.current_layout, -1),
nil)
end
}, {
{modkey}, " ", function()
awful.layout.set(gears.table.iterate_value(ll.layouts,
ll.current_layout, 1),
nil)
end
}
}
}
-- Hide all windows when a splash is shown
awesome.connect_signal("widgets::splash::visibility", function(vis)
local t = screen.primary.selected_tag
if vis then
for idx, c in ipairs(t:clients()) do c.hidden = true end
else
for idx, c in ipairs(t:clients()) do c.hidden = false end
end
end)
-- EOF ------------------------------------------------------------------------

View file

@ -473,6 +473,12 @@ function helpers.float_and_resize(c, width, height)
c:raise()
end
function helpers.centered_client_placement(c)
return gears.timer.delayed_call(function ()
awful.placement.centered(c, {honor_padding = true, honor_workarea=true})
end)
end
-- Useful for periodically checking the output of a command that
-- requires internet access.
-- Ensures that `command` will be run EXACTLY once during the desired
@ -544,7 +550,12 @@ function helpers.music_control(state)
awful.spawn.with_shell(cmd)
end
function helpers.send_key(c, key)
awful.spawn.with_shell("xdotool key --window "..tostring(c.window).." "..key)
end
function helpers.send_key_sequence(c, seq)
awful.spawn.with_shell("xdotool type --delay 5 --window "..tostring(c.window).." "..seq)
end
return helpers
-- EOF ------------------------------------------------------------------------

View file

@ -7,3 +7,4 @@ The following developers have contributed major code to bling:
* [HumblePresent](https://github.com/HumblePresent)
* [Kasper24](https://github.com/Kasper24)
* [undefinedDarkness](https://github.com/undefinedDarkness)
* [eylles](https://github.com/eylles)

View file

@ -8,37 +8,27 @@ mylayout.name = "centered"
function mylayout.arrange(p)
local area = p.workarea
local t = p.tag or screen[p.screen].selected_tag
local mwfact = t.master_width_factor
local nmaster = math.min(t.master_count, #p.clients)
local nslaves = #p.clients - nmaster
local master_area_width = area.width * mwfact
local slave_area_width = area.width - master_area_width
local master_area_x = area.x + 0.5 * slave_area_width
local master_area_width = area.width * t.master_width_factor
if t.master_count == 0 then master_area_width = 0 end
local slave_width = 0.5 * (area.width - master_area_width)
local master_area_x = area.x + slave_width
local number_of_left_sided_slaves = math.floor(nslaves / 2)
local number_of_right_sided_slaves = nslaves - number_of_left_sided_slaves
local left_iterator = 0
local right_iterator = 0
-- Special case: no maters -> rrelapse into awesomes fair layout
if t.master_count == 0 then
awful.layout.suit.fair.arrange(p)
return
end
-- Special case: one slave -> relapse into awesomes masterstack tile layout
if nslaves == 1 then
awful.layout.suit.tile.right.arrange(p)
return
end
-- Special case: no slaves -> fullscreen master area
if nslaves < 1 then
master_area_width = area.width
-- Special case: few slaves -> make masters take more space - unless requested otherwise!
if nslaves < 2 and t.master_fill_policy ~= "master_width_factor" then
master_area_x = area.x
if nslaves == 1 then
slave_width = area.width - master_area_width
else
master_area_width = area.width
end
end
-- iterate through masters
for idx = 1, nmaster do
local c = p.clients[idx]
@ -52,8 +42,14 @@ function mylayout.arrange(p)
p.geometries[c] = g
end
-- iterate through slaves
for idx = 1, nslaves do -- idx=nmaster+1,#p.clients do
local number_of_left_sided_slaves = math.floor(nslaves / 2)
local number_of_right_sided_slaves = nslaves - number_of_left_sided_slaves
local left_iterator = 0
local right_iterator = 0
for idx = 1, nslaves do
local c = p.clients[idx + nmaster]
local g
if idx % 2 == 0 then
@ -62,17 +58,17 @@ function mylayout.arrange(p)
y = area.y
+ left_iterator
* (area.height / number_of_left_sided_slaves),
width = slave_area_width / 2,
width = slave_width,
height = area.height / number_of_left_sided_slaves,
}
left_iterator = left_iterator + 1
else
g = {
x = area.x + master_area_width + slave_area_width / 2,
x = master_area_x + master_area_width,
y = area.y
+ right_iterator
* (area.height / number_of_right_sided_slaves),
width = slave_area_width / 2,
width = slave_width,
height = area.height / number_of_right_sided_slaves,
}
right_iterator = right_iterator + 1

View file

@ -7,6 +7,7 @@ local mylayout = {}
mylayout.name = "mstab"
local tabbar_disable = beautiful.mstab_bar_disable or false
local tabbar_ontop = beautiful.mstab_bar_ontop or false
local tabbar_padding = beautiful.mstab_bar_padding or "default"
local border_radius = beautiful.mstab_border_radius
@ -193,16 +194,18 @@ function mylayout.arrange(p)
local tabbar_width_change = 0
local tabbar_y_change = 0
local tabbar_x_change = 0
if tabbar_position == "top" then
tabbar_size_change = tabbar_size + tabbar_padding
tabbar_y_change = tabbar_size + tabbar_padding
elseif tabbar_position == "bottom" then
tabbar_size_change = tabbar_size + tabbar_padding
elseif tabbar_position == "left" then
tabbar_width_change = tabbar_size + tabbar_padding
tabbar_x_change = tabbar_size + tabbar_padding
elseif tabbar_position == "right" then
tabbar_width_change = tabbar_size + tabbar_padding
if not tabbar_disable then
if tabbar_position == "top" then
tabbar_size_change = tabbar_size + tabbar_padding
tabbar_y_change = tabbar_size + tabbar_padding
elseif tabbar_position == "bottom" then
tabbar_size_change = tabbar_size + tabbar_padding
elseif tabbar_position == "left" then
tabbar_width_change = tabbar_size + tabbar_padding
tabbar_x_change = tabbar_size + tabbar_padding
elseif tabbar_position == "right" then
tabbar_width_change = tabbar_size + tabbar_padding
end
end
-- Iterate through slaves
@ -231,14 +234,16 @@ function mylayout.arrange(p)
p.geometries[c] = g
end
update_tabbar(
slave_clients,
t,
t.top_idx,
area,
master_area_width,
slave_area_width
)
if not tabbar_disable then
update_tabbar(
slave_clients,
t,
t.top_idx,
area,
master_area_width,
slave_area_width
)
end
end
return mylayout

View file

@ -5,7 +5,7 @@ local op = beautiful.flash_focus_start_opacity or 0.6
local stp = beautiful.flash_focus_step or 0.01
local flashfocus = function(c)
if c then
if c and #c.screen.clients > 1 then
c.opacity = op
local q = op
local g = gears.timer({

View file

@ -1,16 +1,111 @@
local awful = require("awful")
local gears = require("gears")
local naughty = require("naughty")
local ruled
if awesome.version ~= "v4.3" then
ruled = require("ruled")
end
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
local capi = { awesome = awesome, client = client }
local ruled = capi.awesome.version ~= "v4.3" and require("ruled") or nil
local pairs = pairs
local Scratchpad = { mt = {} }
--- Called when the turn off animation has ended
local function on_animate_turn_off_end(self, tag)
-- When toggling off a scratchpad that's present on multiple tags
-- depsite still being unminizmied on the other tags it will become invisible
-- as it's position could be outside the screen from the animation
self.client:geometry({
x = self.geometry.x + self.client.screen.geometry.x,
y = self.geometry.y + self.client.screen.geometry.y,
width = self.geometry.width,
height = self.geometry.height,
})
helpers.client.turn_off(self.client, tag)
self.turning_off = false
self:emit_signal("turn_off", self.client)
end
--- The turn off animation
local function animate_turn_off(self, anim, axis)
self.screen_on_toggled_scratchpad = self.client.screen
self.tag_on_toggled_scratchpad = self.screen_on_toggled_scratchpad.selected_tag
if self.client.floating == false then
-- Save the client geometry before floating it
local non_floating_x = self.client.x
local non_floating_y = self.client.y
local non_floating_width = self.client.width
local non_floating_height = self.client.height
-- Can't animate non floating clients
self.client.floating = true
-- Set the client geometry back to what it was before floating it
self.client:geometry({
x = non_floating_x,
y = non_floating_y,
width = non_floating_width,
height = non_floating_height,
})
end
if axis == "x" then
anim.pos = self.client.x
else
anim.pos = self.client.y
end
anim:set(anim:initial())
end
-- Handles changing tag mid animation
local function abort_if_tag_was_switched(self)
-- Check for the following scenerio:
-- Toggle on scratchpad at tag 1
-- Toggle on scratchpad at tag 2
-- Toggle off scratchpad at tag 1
-- Switch to tag 2
-- Outcome: The client will remain on tag 1 and will instead be removed from tag 2
if (self.turning_off) and (self.screen_on_toggled_scratchpad and
self.screen_on_toggled_scratchpad.selected_tag) ~= self.tag_on_toggled_scratchpad
then
if self.rubato.x then
self.rubato.x:abort()
end
if self.rubato.y then
self.rubato.y:abort()
end
on_animate_turn_off_end(self, self.tag_on_toggled_scratchpad)
self.screen_on_toggled_scratchpad.selected_tag = nil
self.tag_on_toggled_scratchpad = nil
end
end
--- The turn on animation
local function animate_turn_on(self, anim, axis)
-- Check for the following scenerio:
-- Toggle on scratchpad at tag 1
-- Toggle on scratchpad at tag 2
-- The animation will instantly end
-- as the timer pos is already at the on position
-- from toggling on the scratchpad at tag 1
if axis == "x" and anim.pos == self.geometry.x then
anim.pos = anim:initial()
else
if anim.pos == self.geometry.y then
anim.pos = anim:initial()
end
end
if axis == "x" then
anim:set(self.geometry.x)
else
anim:set(self.geometry.y)
end
end
--- Creates a new scratchpad object based on the argument
--
-- @param args A table of possible arguments
@ -25,10 +120,40 @@ function Scratchpad:new(args)
end
args.rubato = args.rubato or {}
args.in_anim = false
local ret = gears.object({})
local ret = gears.object{}
gears.table.crush(ret, Scratchpad)
gears.table.crush(ret, args)
if ret.rubato.x then
ret.rubato.x:subscribe(function(pos)
if ret.client and ret.client.valid then
ret.client.x = pos
end
abort_if_tag_was_switched(ret)
end)
ret.rubato.x.ended:subscribe(function()
if ((ret.rubato.y and ret.rubato.y.state == false) or (ret.rubato.y == nil)) and ret.turning_off == true then
on_animate_turn_off_end(ret)
end
end)
end
if ret.rubato.y then
ret.rubato.y:subscribe(function(pos)
if ret.client and ret.client.valid then
ret.client.y = pos
end
abort_if_tag_was_switched(ret)
end)
ret.rubato.y.ended:subscribe(function()
if ((ret.rubato.x and ret.rubato.x.state == false) or (ret.rubato.x == nil)) and ret.turning_off == true then
on_animate_turn_off_end(ret)
end
end)
end
return ret
end
@ -56,6 +181,7 @@ function Scratchpad:apply(c)
width = self.geometry.width,
height = self.geometry.height,
})
if self.autoclose then
c:connect_signal("unfocus", function(c1)
c1.sticky = false -- client won't turn off if sticky
@ -64,82 +190,48 @@ function Scratchpad:apply(c)
end
end
--- The turn on animation
local function animate_turn_on(self, c, anim, axis)
-- Check for the following scenerio:
-- Toggle on scratchpad at tag 1
-- Toggle on scratchpad at tag 2
-- The animation will instantly end
-- as the timer pos is already at the on position
-- from toggling on the scratchpad at tag 1
if axis == "x" and anim.pos == self.geometry.x then
anim.pos = anim:initial()
else
if anim.pos == self.geometry.y then
anim.pos = anim:initial()
end
end
anim:subscribe(function(pos)
if c and c.valid then
if axis == "x" then
c.x = pos
else
c.y = pos
end
end
self.in_anim = true
end)
if axis == "x" then
anim:set(self.geometry.x)
else
anim:set(self.geometry.y)
end
anim.ended:subscribe(function()
self.in_anim = false
anim:unsubscribe()
anim.ended:unsubscribe()
end)
end
--- Turns the scratchpad on
function Scratchpad:turn_on()
local c = self:find()[1]
self.client = self:find()[1]
local anim_x = self.rubato.x
local anim_y = self.rubato.y
if c and not self.in_anim and c.first_tag and c.first_tag.selected then
c:raise()
client.focus = c
local in_anim = false
if (anim_x and anim_x.state == true) or (anim_y and anim_y.state == true) then
in_anim = true
end
if self.client and not in_anim and self.client.first_tag and self.client.first_tag.selected then
self.client:raise()
capi.client.focus = self.client
return
end
if c and not self.in_anim then
if self.client and not in_anim then
-- if a client was found, turn it on
if self.reapply then
self:apply(c)
self:apply(self.client)
end
-- c.sticky was set to false in turn_off so it has to be reapplied anyway
c.sticky = self.sticky
self.client.sticky = self.sticky
if anim_x then
animate_turn_on(self, c, anim_x, "x")
animate_turn_on(self, anim_x, "x")
end
if anim_y then
animate_turn_on(self, c, anim_y, "y")
animate_turn_on(self, anim_y, "y")
end
helpers.client.turn_on(c)
self:emit_signal("turn_on", c)
helpers.client.turn_on(self.client)
self:emit_signal("turn_on", self.client)
return
end
if not c then
if not self.client then
-- if no client was found, spawn one, find the corresponding window,
-- apply the properties only once (until the next closing)
local pid = awful.spawn.with_shell(self.command)
if awesome.version ~= "v4.3" then
if capi.awesome.version ~= "v4.3" then
ruled.client.append_rule({
id = "scratchpad",
rule = self.rule,
@ -159,6 +251,8 @@ function Scratchpad:turn_on()
autostart = true,
single_shot = true,
callback = function()
self.client = c
self:apply(c)
c.hidden = false
c.minimized = false
@ -166,10 +260,10 @@ function Scratchpad:turn_on()
c:activate({})
if anim_x then
animate_turn_on(self, c, anim_x, "x")
animate_turn_on(self, anim_x, "x")
end
if anim_y then
animate_turn_on(self, c, anim_y, "y")
animate_turn_on(self, anim_y, "y")
end
self:emit_signal("inital_apply", c)
@ -189,12 +283,14 @@ function Scratchpad:turn_on()
else
local function inital_apply(c1)
if helpers.client.is_child_of(c1, pid) then
self.client = c1
self:apply(c1)
if anim_x then
animate_turn_on(self, c1, anim_x, "x")
animate_turn_on(self, anim_x, "x")
end
if anim_y then
animate_turn_on(self, c1, anim_y, "y")
animate_turn_on(self, anim_y, "y")
end
self:emit_signal("inital_apply", c1)
client.disconnect_signal("manage", inital_apply)
@ -205,111 +301,32 @@ function Scratchpad:turn_on()
end
end
--- Called when the turn off animation has ended
local function on_animate_turn_off_end(self, c, anim, tag, turn_off_on_end)
anim:unsubscribe()
anim.ended:unsubscribe()
if turn_off_on_end then
-- When toggling off a scratchpad that's present on multiple tags
-- depsite still being unminizmied on the other tags it will become invisible
-- as it's position could be outside the screen from the animation
c:geometry({
x = self.geometry.x + c.screen.geometry.x,
y = self.geometry.y + c.screen.geometry.y,
width = self.geometry.width,
height = self.geometry.height,
})
helpers.client.turn_off(c, tag)
self:emit_signal("turn_off", c)
self.in_anim = false
end
end
--- The turn off animation
local function animate_turn_off(self, c, anim, axis, turn_off_on_end)
local screen_on_toggled_scratchpad = c.screen
local tag_on_toggled_scratchpad = screen_on_toggled_scratchpad.selected_tag
if c.floating == false then
-- Save the client geometry before floating it
local non_floating_x = c.x
local non_floating_y = c.y
local non_floating_width = c.width
local non_floating_height = c.height
-- Can't animate non floating clients
c.floating = true
-- Set the client geometry back to what it was before floating it
c:geometry({
x = non_floating_x,
y = non_floating_y,
width = non_floating_width,
height = non_floating_height,
})
end
if axis == "x" then
anim.pos = c.x
else
anim.pos = c.y
end
anim:subscribe(function(pos)
if c and c.valid then
if axis == "x" then
c.x = pos
else
c.y = pos
end
end
self.in_anim = true
-- Handles changing tag mid animation
-- Check for the following scenerio:
-- Toggle on scratchpad at tag 1
-- Toggle on scratchpad at tag 2
-- Toggle off scratchpad at tag 1
-- Switch to tag 2
-- Outcome: The client will remain on tag 1 and will instead be removed from tag 2
if screen_on_toggled_scratchpad.selected_tag ~= tag_on_toggled_scratchpad then
on_animate_turn_off_end(self, c, anim, tag_on_toggled_scratchpad, true)
end
end)
anim:set(anim:initial())
anim.ended:subscribe(function()
on_animate_turn_off_end(self, c, anim, nil, turn_off_on_end)
end)
end
--- Turns the scratchpad off
function Scratchpad:turn_off()
local c = self:find()[1]
if c and not self.in_anim then
-- Get the tweens
local anim_x = self.rubato.x
local anim_y = self.rubato.y
self.client = self:find()[1]
local anim_x_duration = (anim_x and anim_x.duration) or 0
local anim_y_duration = (anim_y and anim_y.duration) or 0
-- Get the tweens
local anim_x = self.rubato.x
local anim_y = self.rubato.y
local turn_off_on_end = (anim_x_duration >= anim_y_duration) and true or false
local in_anim = false
if (anim_x and anim_x.state == true) or (anim_y and anim_y.state == true) then
in_anim = true
end
if self.client and not in_anim then
if anim_x then
animate_turn_off(self, c, anim_x, "x", turn_off_on_end)
self.turning_off = true
animate_turn_off(self, anim_x, "x")
end
if anim_y then
animate_turn_off(self, c, anim_y, "y", not turn_off_on_end)
self.turning_off = true
animate_turn_off(self, anim_y, "y")
end
if not anim_x and not anim_y then
helpers.client.turn_off(c)
self:emit_signal("turn_off", c)
helpers.client.turn_off(self.client)
self:emit_signal("turn_off", self.client)
end
end
end
@ -335,8 +352,8 @@ function Scratchpad:toggle()
end
end
else
is_turn_off = client.focus
and awful.rules.match(client.focus, self.rule)
is_turn_off = capi.client.focus
and awful.rules.match(capi.client.focus, self.rule)
end
if is_turn_off then

View file

@ -53,36 +53,37 @@ function apply(wallpaper_object, args)
args.offset = args.offset or { x = 0, y = 0 }
args.scale = args.scale or 1
local positions = {
["centered"] = function()
["centered"] = function(s)
gears.wallpaper.centered(
wallpaper_object,
args.screen,
s,
args.background,
args.scale
)
end,
["tiled"] = function()
gears.wallpaper.tiled(wallpaper_object, args.screen, args.offset)
["tiled"] = function(s)
gears.wallpaper.tiled(wallpaper_object, s, args.offset)
end,
["maximized"] = function()
["maximized"] = function(s)
gears.wallpaper.maximized(
wallpaper_object,
args.screen,
s,
args.ignore_aspect,
args.offset
)
end,
["fit"] = function()
gears.wallpaper.fit(wallpaper_object, args.screen, args.background)
["fit"] = function(s)
gears.wallpaper.fit(wallpaper_object, s, args.background)
end,
}
local call_func = nil
if
type(wallpaper_object) == "string"
and gears.filesystem.file_readable(wallpaper_object)
then
-- path of an image file, we use a position function
local p = args.position or "centered"
positions[p]()
call_func = positions[p]
elseif type(wallpaper_object) == "function" then
-- function
wallpaper_object(args)
@ -91,10 +92,13 @@ function apply(wallpaper_object, args)
and args.position
then
-- if the user sets a position function, wallpaper_object should be a cairo surface
positions[args.position]()
call_func = positions[args.position]
else
gears.wallpaper.set(wallpaper_object)
end
if call_func then
call_func(args.screen)
end
end
--- Converts `args.wallpaper` to a list of `wallpaper_objects` readable by `apply` function).
@ -154,7 +158,15 @@ local simple_index = 0
function setters.simple(args)
local wallpapers = prepare_list(args)
simple_index = (simple_index % #wallpapers) + 1
apply(wallpapers[simple_index], args)
if type(args.screen) == 'table' then
for _,v in ipairs(args.screen) do
args.screen = v
apply(wallpapers[simple_index], args)
args.screen = nil
end
else
apply(wallpapers[simple_index], args)
end
end
--- Set a random wallpaper from a list.
@ -164,7 +176,15 @@ end
-- @see prepare_list
function setters.random(args)
local wallpapers = prepare_list(args)
apply(wallpapers[math.random(#wallpapers)], args)
if type(args.screen) == 'table' then
for _,v in ipairs(args.screen) do
args.screen = v
apply(wallpapers[math.random(#wallpapers)], args)
args.screen = nil
end
else
apply(wallpapers[math.random(#wallpapers)], args)
end
end
local simple_schedule_object = nil
@ -310,7 +330,10 @@ function setup(args)
config.set_function = config.set_function
or (config.wallpaper and setters.simple or setters.awesome_wallpaper)
local function set_wallpaper(s)
config.screen = s or config.screen
if type(config.screen) ~= 'table' then
if config.screen and s and config.screen ~= s then return end
config.screen = s or config.screen
end
config.set_function(config)
end

View file

@ -11,53 +11,93 @@ local helpers = require(tostring(...):match(".*bling") .. ".helpers")
local window_swallowing_activated = false
-- you might want to add or remove applications here
local dont_swallow_classname_list = beautiful.dont_swallow_classname_list
local parent_filter_list = beautiful.parent_filter_list
or beautiful.dont_swallow_classname_list
or { "firefox", "Gimp", "Google-chrome" }
local activate_dont_swallow_filter = beautiful.dont_swallow_filter_activated
or true
local child_filter_list = beautiful.child_filter_list
or beautiful.dont_swallow_classname_list or { }
-- checks if client classname matches with any entry of the dont-swallow-list
local function check_if_swallow(c)
if not activate_dont_swallow_filter then
return true
end
for _, classname in ipairs(dont_swallow_classname_list) do
if classname == c.class then
return false
-- for boolean values the or chain way to set the values breaks with 2 vars
-- and always defaults to true so i had to do this to se the right value...
local swallowing_filter = true
local filter_vars = { beautiful.swallowing_filter, beautiful.dont_swallow_filter_activated }
for _, var in pairs(filter_vars) do
swallowing_filter = var
end
-- check if element exist in table
-- returns true if it is
local function is_in_table(element, table)
local res = false
for _, value in pairs(table) do
if element:match(value) then
res = true
break
end
end
return true
return res
end
-- if the swallowing filter is active checks the child and parent classes
-- against their filters
local function check_swallow(parent, child)
local res = true
if swallowing_filter then
local prnt = not is_in_table(parent, parent_filter_list)
local chld = not is_in_table(child, child_filter_list)
res = ( prnt and chld )
end
return res
end
-- async function to get the parent's pid
-- recieves a child process pid and a callback function
-- parent_pid in format "init(1)---ancestorA(pidA)---ancestorB(pidB)...---process(pid)"
function get_parent_pid(child_ppid, callback)
local ppid_cmd = string.format("pstree -A -p -s %s", child_ppid)
awful.spawn.easy_async(ppid_cmd, function(stdout, stderr, reason, exit_code)
-- primitive error checking
if stderr and stderr ~= "" then
callback(stderr)
return
end
local ppid = stdout
callback(nil, ppid)
end)
end
-- the function that will be connected to / disconnected from the spawn client signal
local function manage_clientspawn(c)
-- get the last focused window to check if it is a parent window
local parent_client = awful.client.focus.history.get(c.screen, 1)
if not parent_client then
return
elseif parent_client.type == "dialog" or parent_client.type == "splash" then
return
end
-- io.popen is normally discouraged. Should probably be changed
local handle = io.popen(
[[pstree -T -p -a -s ]]
.. tostring(c.pid)
.. [[ | sed '2q;d' | grep -o '[0-9]*$' | tr -d '\n']]
)
local parent_pid = handle:read("*a")
handle:close()
get_parent_pid(c.pid, function(err, ppid)
if err then
return
end
parent_pid = ppid
if
(tostring(parent_pid) == tostring(parent_client.pid))
and check_if_swallow(c)
-- will search for "(parent_client.pid)" inside the parent_pid string
( tostring(parent_pid):find("("..tostring(parent_client.pid)..")") )
and check_swallow(parent_client.class, c.class)
then
c:connect_signal("unmanage", function()
helpers.client.turn_on(parent_client)
helpers.client.sync(parent_client, c)
if parent_client then
helpers.client.turn_on(parent_client)
helpers.client.sync(parent_client, c)
end
end)
helpers.client.sync(c, parent_client)
helpers.client.turn_off(parent_client)
end
end)
end
-- without the following functions that module would be autoloaded by require("bling")

View file

@ -42,6 +42,7 @@ theme.tabbar_bg_normal_inactive = nil -- background color of unfocused clients o
theme.tabbar_fg_normal_inactive = nil -- foreground color of unfocused clients on the tabbar when inactive
-- mstab
theme.mstab_bar_disable = false -- disable the tabbar
theme.mstab_bar_ontop = false -- whether you want to allow the bar to be ontop of clients
theme.mstab_dont_resize_slaves = false -- whether the tabbed stack windows should be smaller than the
-- currently focused stack window (set it to true if you use

View file

@ -281,8 +281,8 @@ local function search(self, text)
text = text:gsub( "%W", "" )
-- Check if there's a match by the app name or app command
if string.find(entry.name, case_insensitive_pattern(text)) ~= nil or
self.search_commands and string.find(entry.commandline, case_insensitive_pattern(text)) ~= nil
if string.find(entry.name:lower(), text:lower(), 1, true) ~= nil or
self.search_commands and string.find(entry.commandline, text:lower(), 1, true) ~= nil
then
table.insert(self._private.matched_entries, {
name = entry.name,
@ -498,7 +498,6 @@ local function scroll_right(self)
local rows, columns = self._private.grid:get_dimension()
local pos = self._private.grid:get_widget_position(self._private.active_widget)
local is_less_than_max_column = pos.col < columns
local is_less_than_max_page = self._private.current_page < self._private.pages_count
-- Check if we can scroll down the app list
if is_less_than_max_column then
@ -773,6 +772,7 @@ local function new(args)
args.icon_theme = args.icon_theme or nil
args.icons_size = args.icons_size or nil
args.type = args.type or "dock"
args.show_on_focused_screen = args.show_on_focused_screen == nil and true or args.show_on_focused_screen
args.screen = args.screen or capi.screen.primary
args.placement = args.placement or awful.placement.centered
@ -919,7 +919,7 @@ local function new(args)
}
ret._private.widget = awful.popup
{
type = "dock",
type = args.type,
visible = false,
ontop = true,
placement = ret.placement,

View file

@ -182,6 +182,7 @@ function module.create(args_or_name, editor, default_cmd)
end
local function get_instance_data(screen, tag)
if screen == nil then return end
local workarea = screen.workarea
local instance = get_instance_(tag)
local cmd = instance.cmd or module.global_default_cmd

View file

@ -1,627 +0,0 @@
---------------------------------------------------------------------------
-- A layout that allows its children to take more space than what's available
-- in the surrounding container. If the content does exceed the available
-- size, a scrollbar is added and scrolling behavior enabled.
--
--@DOC_wibox_layout_defaults_overflow_EXAMPLE@
-- @author Lucas Schwiderski
-- @copyright 2021 Lucas Schwiderski
-- @layoutmod wibox.layout.overflow
---------------------------------------------------------------------------
local base = require('wibox.widget.base')
local fixed = require('wibox.layout.fixed')
local separator = require('wibox.widget.separator')
local gtable = require('gears.table')
local gshape = require('gears.shape')
local gobject = require('gears.object')
local mousegrabber = mousegrabber
local overflow = { mt = {} }
-- Determine the required space to draw the layout's children and, if necessary,
-- the scrollbar.
function overflow:fit(context, orig_width, orig_height)
local widgets = self._private.widgets
local num_widgets = #widgets
if num_widgets < 1 then
return 0, 0
end
local width, height = orig_width, orig_height
local scrollbar_width = self._private.scrollbar_width
local scrollbar_enabled = self._private.scrollbar_enabled
local used_in_dir, used_max = 0, 0
local is_y = self._private.dir == "y"
local avail_in_dir = is_y and orig_height or orig_width
-- Set the direction covered by scrolling to the maximum value
-- to allow widgets to take as much space as they want.
if is_y then
height = math.huge
else
width = math.huge
end
-- First, determine widget sizes.
-- Only when the content doesn't fit and needs scrolling should
-- we reduce content size to make space for a scrollbar.
for _, widget in pairs(widgets) do
local w, h = base.fit_widget(self, context, widget, width, height)
if is_y then
used_max = math.max(used_max, w)
used_in_dir = used_in_dir + h
else
used_in_dir = used_in_dir + w
used_max = math.max(used_max, h)
end
end
local spacing = self._private.spacing * (num_widgets - 1)
used_in_dir = used_in_dir + spacing
local need_scrollbar = used_in_dir > avail_in_dir and scrollbar_enabled
-- If the direction perpendicular to scrolling (e.g. width in vertical
-- scrolling) is not fully covered by any of the widgets, we can add our
-- scrollbar width to that value. Otherwise widget size will be reduced
-- during `layout` to make space for the scrollbar.
if need_scrollbar
and (
(is_y and used_max < orig_width)
or (not is_y and used_max < orig_height)
) then
used_max = used_max + scrollbar_width
end
if is_y then
return used_max, used_in_dir
else
return used_in_dir, used_max
end
end
-- Layout children, scrollbar and spacing widgets.
-- Only those widgets that are currently visible will be placed.
function overflow:layout(context, orig_width, orig_height)
local result = {}
local is_y = self._private.dir == "y"
local widgets = self._private.widgets
local avail_in_dir = is_y and orig_height or orig_width
local scrollbar_width = self._private.scrollbar_width
local scrollbar_enabled = self._private.scrollbar_enabled
local scrollbar_position = self._private.scrollbar_position
local width, height = orig_width, orig_height
local widget_x, widget_y = 0, 0
local used_in_dir, used_max = 0, 0
-- Set the direction covered by scrolling to the maximum value
-- to allow widgets to take as much space as they want.
if is_y then
height = math.huge
else
width = math.huge
end
-- First, determine widget sizes.
-- Only when the content doesn't fit and needs scrolling should
-- we reduce content size to make space for a scrollbar.
for _, widget in pairs(widgets) do
local w, h = base.fit_widget(self, context, widget, width, height)
if is_y then
used_max = math.max(used_max, w)
used_in_dir = used_in_dir + h
else
used_in_dir = used_in_dir + w
used_max = math.max(used_max, h)
end
end
used_in_dir = used_in_dir + self._private.spacing * (#widgets-1)
-- Save size for scrolling behavior
self._private.avail_in_dir = avail_in_dir
self._private.used_in_dir = used_in_dir
local need_scrollbar = used_in_dir > avail_in_dir and scrollbar_enabled
local scroll_position = self._private.position
if need_scrollbar then
local scrollbar_widget = self._private.scrollbar_widget
local bar_x, bar_y = 0, 0
local bar_w, bar_h
-- The percentage of how much of the content can be visible within
-- the available space
local visible_percent = avail_in_dir / used_in_dir
-- Make scrollbar length reflect `visible_percent`
-- TODO: Apply a default minimum length
local bar_length = math.floor(visible_percent * avail_in_dir)
local bar_pos = (avail_in_dir - bar_length) * self._private.position
if is_y then
bar_w, bar_h = base.fit_widget(self, context, scrollbar_widget, scrollbar_width, bar_length)
bar_y = bar_pos
if scrollbar_position == "left" then
widget_x = widget_x + bar_w
elseif scrollbar_position == "right" then
bar_x = orig_width - bar_w
end
self._private.bar_length = bar_h
width = width - bar_w
else
bar_w, bar_h = base.fit_widget(self, context, scrollbar_widget, bar_length, scrollbar_width)
bar_x = bar_pos
if scrollbar_position == "top" then
widget_y = widget_y + bar_h
elseif scrollbar_position == "bottom" then
bar_y = orig_height - bar_h
end
self._private.bar_length = bar_w
height = height - bar_h
end
table.insert(result, base.place_widget_at(
scrollbar_widget,
math.floor(bar_x),
math.floor(bar_y),
math.floor(bar_w),
math.floor(bar_h)
))
end
local pos, spacing = 0, self._private.spacing
local interval = used_in_dir - avail_in_dir
local spacing_widget = self._private.spacing_widget
if spacing_widget then
if is_y then
local _
_, spacing = base.fit_widget(self, context, spacing_widget, width, spacing)
else
spacing = base.fit_widget(self, context, spacing_widget, spacing, height)
end
end
for i, w in pairs(widgets) do
local content_x, content_y
local content_w, content_h = base.fit_widget(self, context, w, width, height)
-- When scrolling down, the content itself moves up -> substract
local scrolled_pos = pos - (scroll_position * interval)
-- Stop processing completely once we're passed the visible portion
if scrolled_pos > avail_in_dir then
break
end
if is_y then
content_x, content_y = widget_x, scrolled_pos
pos = pos + content_h + spacing
if self._private.fill_space then
content_w = width
end
else
content_x, content_y = scrolled_pos, widget_y
pos = pos + content_w + spacing
if self._private.fill_space then
content_h = height
end
end
local is_in_view = is_y
and (scrolled_pos + content_h > 0)
or (scrolled_pos + content_w > 0)
if is_in_view then
-- Add the spacing widget, but not before the first widget
if i > 1 and spacing_widget then
table.insert(result, base.place_widget_at(
spacing_widget,
-- The way how spacing is added for regular widgets
-- and the `spacing_widget` is disconnected:
-- The offset for regular widgets is added to `pos` one
-- iteration _before_ the one where the widget is actually
-- placed.
-- Because of that, the placement for the spacing widget
-- needs to substract that offset to be placed right after
-- the previous regular widget.
math.floor(is_y and content_x or (content_x - spacing)),
math.floor(is_y and (content_y - spacing) or content_y),
math.floor(is_y and content_w or spacing),
math.floor(is_y and spacing or content_h)
))
end
table.insert(result, base.place_widget_at(
w,
math.floor(content_x),
math.floor(content_y),
math.floor(content_w),
math.floor(content_h)
))
end
end
return result
end
function overflow:before_draw_children(_, cr, width, height)
-- Clip drawing for children to the space we're allowed to draw in
cr:rectangle(0, 0, width, height)
cr:clip()
end
--- The amount of units to advance per scroll event.
-- This affects calls to `scroll` and the default mouse wheel handler.
--
-- The default is `10`.
--
-- @property step
-- @tparam number step The step size.
-- @see set_step
--- Set the step size.
--
-- @method overflow:set_step
-- @tparam number step The step size.
-- @see step
function overflow:set_step(step)
self._private.step = step
-- We don't need to emit enything here, since changing step only really
-- takes effect the next time the user scrolls
end
--- Scroll the layout's content by `amount * step`.
-- A positive amount scroll down/right, a negative amount scrolls up/left.
--
-- @method overflow:scroll
-- @tparam number amount The amount to scroll by.
-- @emits property::overflow::position
-- @emitstparam property::overflow::position number position The new position.
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
-- @see step
function overflow:scroll(amount)
if amount == 0 then
return
end
local interval = self._private.used_in_dir
local delta = self._private.step / interval
local pos = self._private.position + (delta * amount)
self:set_position(pos)
end
--- The scroll position.
-- The position is represented as a fraction from `0` to `1`.
--
-- @property position
-- @tparam number position The position.
-- @propemits true false
-- @see set_position
--- Set the current scroll position.
--
-- @method overflow:set_position
-- @tparam number position The new position.
-- @propemits true false
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
-- @see position
function overflow:set_position(pos)
local current = self._private.position
local interval = self._private.used_in_dir - self._private.avail_in_dir
if current == pos
-- the content takes less space than what is available, i.e. everything
-- is already visible
or interval <= 0
-- the position is out of range
or (current <= 0 and pos < 0)
or (current >= 1 and pos > 1) then
return
end
self._private.position = math.min(1, math.max(pos, 0))
self:emit_signal("widget::layout_changed")
self:emit_signal("property::position", pos)
end
--- Get the current scroll position.
--
-- @method overflow:get_position
-- @treturn number position The current position.
-- @see position
function overflow:get_position()
return self._private.position
end
--- The scrollbar width.
-- For horizontal scrollbars, this is the scrollbar height
--
-- The default is `5`.
--
--@DOC_wibox_layout_overflow_scrollbar_width_EXAMPLE@
--
-- @property scrollbar_width
-- @tparam number scrollbar_width The scrollbar width.
-- @propemits true false
-- @see set_scrollbar_width
--- Set the scrollbar width.
--
-- @method overflow:set_scrollbar_width
-- @tparam number scrollbar_width The new scrollbar width.
-- @propemits true false
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
-- @see scrollbar_width
function overflow:set_scrollbar_width(width)
if self._private.scrollbar_width == width then
return
end
self._private.scrollbar_width = width
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scrollbar_width", width)
end
--- The scrollbar position.
--
-- For horizontal scrollbars, this can be `"top"` or `"bottom"`,
-- for vertical scrollbars this can be `"left"` or `"right"`.
-- The default is `"left"`/`"bottom"`.
--
--@DOC_wibox_layout_overflow_scrollbar_position_EXAMPLE@
--
-- @property scrollbar_position
-- @tparam string scrollbar_position The scrollbar position.
-- @propemits true false
-- @see set_scrollbar_position
--- Set the scrollbar position.
--
-- @method overflow:set_scrollbar_position
-- @tparam string scrollbar_position The new scrollbar position.
-- @propemits true false
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
-- @see scrollbar_position
function overflow:set_scrollbar_position(position)
if self._private.scrollbar_position == position then
return
end
self._private.scrollbar_position = position
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scrollbar_position", position)
end
--- The scrollbar visibility.
-- If this is set to `false`, no scrollbar will be rendered, even if the layout's
-- content overflows. Mouse wheel scrolling will work regardless.
--
-- The default is `true`.
--
-- @property scrollbar_enabled
-- @tparam boolean scrollbar_enabled The scrollbar visibility.
-- @propemits true false
-- @see set_scrollbar_enabled
--- Enable or disable the scrollbar visibility.
--
-- @method overflow:set_scrollbar_enabled
-- @tparam boolean scrollbar_enabled The new scrollbar visibility.
-- @propemits true false
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
-- @see scrollbar_enabled
function overflow:set_scrollbar_enabled(enabled)
if self._private.scrollbar_enabled == enabled then
return
end
self._private.scrollbar_enabled = enabled
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scrollbar_enabled", enabled)
end
-- Wraps a callback function for `mousegrabber` that is capable of
-- updating the scroll position.
local function build_grabber(container)
local is_y = container._private.dir == "y"
local bar_interval = container._private.avail_in_dir - container._private.bar_length
local start_pos = container._private.position * bar_interval
local coords = mouse.coords()
local start = is_y and coords.y or coords.x
return function(mouse)
if not mouse.buttons[1] then
return false
end
local pos = is_y and mouse.y or mouse.x
container:set_position((start_pos + (pos - start)) / bar_interval)
return true
end
end
-- Applies a mouse button signal using `build_grabber` to a scrollbar widget.
local function apply_scrollbar_mouse_signal(container, w)
w:connect_signal('button::press', function(_, _, _, button_id)
if button_id ~= 1 then
return
end
mousegrabber.run(build_grabber(container), "fleur")
end)
end
--- The scrollbar widget.
-- This widget is rendered as the scrollbar element.
--
-- The default is `awful.widget.separator{ shape = gears.shape.rectangle }`.
--
--@DOC_wibox_layout_overflow_scrollbar_widget_EXAMPLE@
--
-- @property scrollbar_widget
-- @tparam widget scrollbar_widget The scrollbar widget.
-- @propemits true false
-- @see set_scrollbar_widget
--- Set the scrollbar widget.
--
-- This will also apply the mouse button handler.
--
-- @method overflow:set_scrollbar_widget
-- @tparam widget scrollbar_widget The new scrollbar widget.
-- @propemits true false
-- @emits widget::layout_changed
-- @see scrollbar_widget
function overflow:set_scrollbar_widget(widget)
local w = base.make_widget_from_value(widget)
apply_scrollbar_mouse_signal(self, w)
self._private.scrollbar_widget = w
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scrollbar_widget", widget)
end
local function new(dir, ...)
local ret = fixed[dir](...)
gtable.crush(ret, overflow, true)
ret.widget_name = gobject.modulename(2)
-- Manually set the position here. We don't know the bounding size yet.
ret._private.position = 0
-- Apply defaults. Bypass setters to avoid signals.
ret._private.step = 10
ret._private.fill_space = true
ret._private.scrollbar_width = 5
ret._private.scrollbar_enabled = true
ret._private.scrollbar_position = dir == "vertical" and "right" or "bottom"
local scrollbar_widget = separator({ shape = gshape.rectangle })
apply_scrollbar_mouse_signal(ret, scrollbar_widget)
ret._private.scrollbar_widget = scrollbar_widget
ret:connect_signal('button::press', function(self, _, _, button)
if button == 4 then
if self.scroll_speed == nil or self.scroll_speed <= 0 then
self:scroll(-1)
else
self:scroll(-1 * self.scroll_speed)
end
elseif button == 5 then
if self.scroll_speed == nil or self.scroll_speed <= 0 then
self:scroll(1)
else
self:scroll(1 * self.scroll_speed)
end
end
end)
return ret
end
--- Returns a new horizontal overflow layout.
-- Child widgets are placed similar to `wibox.layout.fixed`, except that
-- they may take as much width as they want. If the total width of all child
-- widgets exceeds the width available whithin the layout's outer container
-- a scrollbar will be added and scrolling behavior enabled.
-- @tparam widget ... Widgets that should be added to the layout.
-- @constructorfct wibox.layout.overflow.horizontal
function overflow.horizontal(...)
return new("horizontal", ...)
end
--- Returns a new vertical overflow layout.
-- Child widgets are placed similar to `wibox.layout.fixed`, except that
-- they may take as much height as they want. If the total height of all child
-- widgets exceeds the height available whithin the layout's outer container
-- a scrollbar will be added and scrolling behavior enabled.
-- @tparam widget ... Widgets that should be added to the layout.
-- @constructorfct wibox.layout.fixed.horizontal
function overflow.vertical(...)
return new("vertical", ...)
end
--- Add spacing between each layout widgets.
--
-- This behaves just like in `wibox.layout.fixed`:
--
--@DOC_wibox_layout_fixed_spacing_EXAMPLE@
--
-- @property spacing
-- @tparam number spacing Spacing between widgets.
-- @propemits true false
-- @see wibox.layout.fixed
--- The widget used to fill the spacing between the layout elements.
-- By default, no widget is used.
--
-- This behaves just like in `wibox.layout.fixed`:
--
--@DOC_wibox_layout_fixed_spacing_widget_EXAMPLE@
--
-- @property spacing_widget
-- @tparam widget spacing_widget
-- @propemits true false
-- @see wibox.layout.fixed
--- Set the layout's fill_space property.
--
-- If this property is `true`, widgets
-- take all space in the non-scrolling directing (e.g. `width` for vertical
-- scrolling). If `false`, they will only take as much as they need for their
-- content.
--
-- The default is `true`.
--
--@DOC_wibox_layout_overflow_fill_space_EXAMPLE@
--
-- @property fill_space
-- @tparam boolean fill_space
-- @propemits true false
--@DOC_fixed_COMMON@
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(overflow, overflow.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View file

@ -13,7 +13,8 @@ Basically like [awestore](https://github.com/K4rakara/awestore) but not really.
Join the cool curve crew
<img src="https://cdn.discordapp.com/attachments/702548961780826212/879022533314216007/download.jpeg" height=160>
<!-- look colleges might see this and think its distasteful so I'm commenting it out for the moment
<img src="https://cdn.discordapp.com/attachments/702548961780826212/879022533314216007/download.jpeg" height=160>-->
<h1 id="background">Background and Explanation</h1>
@ -210,82 +211,127 @@ In practice, creating your own easing would look like this:
1. Go to [easings.net](https://easings.net)
For the sake of this tutorial, we'll do an extremely complex easing, "ease in elastic"
For the sake of this tutorial, we'll do an extremely complex (hellish? easing, "ease in elastic"
For the sake of this tutorial, we'll do both an easy easing and a complex one. The easy easing will
be the beautifully simple and quite frankly obvious quadratic. The much worse easing will be "ease
in elastic."
2. Find the necessary information
**Important:** You should really use sagemath or Wolfram Mathematica to get as exact of a derivative
as you can. Wolfram Alpha doesn't cut it. I personally used sagemath because it's actually free,
which is pretty cool. To take that one step further, I'd suggest using jupyter notebook in tandem
with sagemath because if you run `%display latex` you get a super good looking output. If you can't
use jupyter (or don't want to), `%display ascii_art` is a pretty cool alternative.
For quadratic we already know the function: `y=x^2`. I don't even need to use latex it's that easy.
For ease in elastic, we use the function given [here](https://easings.net/#easeInElastic):
The initial function, given by [easings.net](https://easings.net), is as follows:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f(x)=-2^{10 \, x - 10}\times \sin\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right))">
3. Take the derivative
Quadratic: `y=2x`, easy as that.
**Important:** Look. Computers aren't the greatest at indefinite mathematics. As such, it's
possible that, like myself, you will have a hard time getting the correct derivative if it's as
complicated as these here. Don't be discouraged, however! Sagemath (making sure not to factor
anything) could correctly do out this math, even if I had a bit of a scare realizing that when I
was factoring it I was just being saved by `override_simulate` being accidentally set to true.
Anyways, use sagemath and jupyter notebook. I don't know if all sagemaths come with it
preinstalled, but nix makes it so easy that all I have to do is `sage -n jupyter` and it'll open it
right up. `%display latex` in jupiter makes it look pretty, whereas `%display ascii_art` will make
it look *presentable* in tui sagemath.
The derivative (via sagemath) is as follows:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f^\prime (x)=-\frac{5}{3} \, {\left(2 \, \pi \cos\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) %2B 3 \, \log\left(2\right) \sin\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right)\right)}\times 2^{10 \, x - 9}">
First we double check that `f'(0)=0`, which in this case it is not.
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f^\prime (x)=-\frac{20}{3} \, \pi 2^{10 \, x - 10} \cos\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) - 10 \cdot 2^{10 \, x - 10} \log\left(2\right) \sin\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right)">
4. Double check that `f'(0)=0`
Quadratic: `2*0 = 0` so we're good
Ease in elastic not so much, however:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f^\prime (0)=\frac{5}{1536} \, \sqrt{3} \pi - \frac{5}{1024} \, \log\left(2\right)">
We'll subtract this value from `f(x)` so that our new `f(x)`, let's say `f_2(x)` has a point at
(0, 0).
so now we subtract `f'(0)` from `f'(x)` and get a pretty messy function, let's say `f_2(x)`.
Regrettably, we're about to mess up that function a little more. Next we check that `f_2(1)=1`. In
this case, once again, it doesn't. We get
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f_2(1)=-\frac{5}{3072} \, \sqrt{3} {\left(2 \, \pi - 2049 \, \sqrt{3}\times \log\left(2\right)\right)}">
5. Double check that `f_2(1)=1`
So now we divide our `f(x)` by `f(1)`, to get our final function, `f_e(x)` (easing function) (I am
so good at naming these kinds of things)
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f_e(x)=\frac{6 \, \pi %2B \sqrt{3} \pi \times 2^{10 \, x %2B 2}\times \cos\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) %2B 3 \, \sqrt{3}\times 2^{10 \, x %2B 1}\times \log\left(2\right) \sin\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) - 3 \, \sqrt{3}\times \log\left(2\right)}{3 \, {\left(2 \, \pi - 2049 \, \sqrt{3} \times\log\left(2\right)\right)}}">
Quadratic: No, actually. This means we have to do a wee bit of work: `f(1)=2`, so to counteract this,
we'll create a new (and final) function that we can call `f_e` (easing function) by dividing `f(x)`
by `f(1)`. In practice this looks like this:
Great... This is going to be a treat to write as lua... Anyways, our final step is to find the
definite integral from 0 to 1 of our `f(x)`, which is this
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}\int_0^1 f_e(x) \,dx=\frac{20 \, \pi - 10 \, \sqrt{3}\times \log\left(2\right) - 2049 \, \sqrt{3}}{10 \, {\left(2 \, \pi - 2049 \, \sqrt{3}\times \log\left(2\right)\right)}}">
```
f(1)=2, f(x)/f(1) = 2x / 2 = x, f_e(x)=x
```
Now I'm sure that looks pretty daunting. However, these functions are kinda stupidly easy to find
with sagemath. You basically only have to run these commands:
Easy as that!
Or so you thought. Now let's check the same for ease in elastic:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f_2(1)=-\frac{5}{1536} \, \sqrt{3} \pi %2B \frac{10245}{1024} \, \log\left(2\right)">
Hence the need for sagemath. Once we divide the two we get our final easing function, this:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}f_e(x)=\frac{4096 \, \pi 2^{10 \, x - 10} \cos\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) %2B 6144 \cdot 2^{10 \, x - 10} \log\left(2\right) \sin\left(-\frac{43}{6} \, \pi %2B \frac{20}{3} \, \pi x\right) %2B 2 \, \sqrt{3} \pi - 3 \, \log\left(2\right)}{2 \, \sqrt{3} \pi - 6147 \, \log\left(2\right)}">
What on god's green earth is that. Well whatever, at least it works (?).
6. Finally, we get the definite integral from 0 to 1 of our `f(x)`
For `f(x)=x` we can do that in our heads, it's just `1/2`.
For ease in elastic not so much. You can do this with sagemath and eventually get this:
<img src="https://render.githubusercontent.com/render/math?math=\color{blue}\frac{20 \, \sqrt{3} \pi - 30 \, \log\left(2\right) - 6147}{10 \, {\left(2 \, \sqrt{3} \pi - 6147 \, \log\left(2\right)\right)}}">
So this all looked pretty daunting probably, and to be honest it took me hours of either not using
sage (I tried with wolfram alpha for a good hour) or using sage incorrectly (it took three months
to realize that this entire section of the readme was wrong and that using `factor` made it
incorrect), but now that I have this easy little code snippet you can use for sage it shouldn't be
as much of a hastle for you.
```python
from sage.symbolic.integration.integral import definite_integral
function('f')
f(x)=factor(derivative('''your function goes here''', x))
f(x)=factor(f(x)-f(0))
f(x)=factor(f(x)/f(1))
f(x)='''your function goes here'''
f(x)=derivative(f(x), x)
f(x)=f(x)-f(0)
f(x)=f(x)/f(1)
print(f(x)) # easing
print(definite_integral(f(x), x, 0, 1)) # F
```
which will tell you all you need to know.
So the thing with using `factor` is that, while on some weird other version of sage I was geting a
bunch of 0.49999s which wouldn't round to .5, the result was straight up wrong. So I advise against
it, and if you can't do the derivative then sucks to suck I guess (just lmk in an issue or
something and I'll try my very best).
It's important to use the `factor(...)` thing because otherwise you may end up with decimals, which
really should be avoided if possible. When I didn't do factor, there were 0.499999s which makes it
decently less accurate and substantially more complicated.
4. Now we just have to translate this into an actual lua table.
4. Now we just have to translate this into an actual lua table. You might want to be careful about
not doing more operations than necessary but honestly it probably doesn't much matter.
Quadratic, as usual, is easy.
```lua
local quadratic = {
F = 1/2 -- F = 1/2
easing = function(t) return t end -- f(x) = x
}
```
Ease in elastic, as usual, is not. At one point I had the willpower to try and optimize operations,
but I really don't want to simplify those equations and I can't trust `factor`, so for now it stays
as is. If it irks you, make a pull request and save us both.
```lua
--all the constants are calculated only once
local cs = {
c1 = 6 * math.pi - 3 * math.sqrt(3) * math.log(2),
c2 = math.sqrt(3) * math.pi,
c3 = 6 * math.sqrt(3) * math.log(2),
c4 = 6 * math.pi - 6147 * math.sqrt(3) * math.log(2),
c5 = 46 * math.pi / 6
}
bouncy = {
F = (20 * math.pi - (10 * math.log(2) - 2049) * math.sqrt(3)) /
(20 * math.pi - 20490 * math.sqrt(3) * math.log(2)),
easing = function(t)
--both of these values are reused
local c1 = (20 * t * math.pi) / 3 - cs.c5
local c2 = math.pow(2, 10 * t + 1) --in the 2^{10x+2} I factored out the 2 to calculate this once
return (cs.c1 + cs.c2 * c2 * math.cos(c1) + cs.c3 * c2 * math.sin(c1)) / cs.c4
end
local bouncy = {
F = (20*math.sqrt(3)*math.pi-30*math.log(2)-6147) /
(10*(2*math.sqrt(3)*math.pi-6147*math.log(2))),
easing = function(t) return
(4096*math.pi*math.pow(2, 10*t-10)*math.cos(20/3*math.pi*t-43/6*math.pi)
+6144*math.pow(2, 10*t-10)*math.log(2)*math.sin(20/3*math.pi*t-43/6*math.pi)
+2*math.sqrt(3)*math.pi-3*math.log(2)) /
(2*math.pi*math.sqrt(3)-6147*math.log(2))
end
}
-- how it would actually look in a timed object
timed = rubato.timed {
intro = 0, --we'll use this as an outro, since it's weird as an intro
outro = 0.7,
@ -350,3 +396,5 @@ about in the first place. Plus, it'll be the first of my projects without garbag
- [ ] only apply corrective coefficient to plateau
- [ ] Do `prop_intro` more intelligently so it doesn't have to do so many comparisons
- [ ] Make things like `abort` more useful
- [ ] Merge that pr by @Kasper so instant works
- [ ] Add a manager (this proceeds the above todo thing)

View file

@ -25,18 +25,19 @@ local b_cs = {
c5 = 46 * math.pi / 6
}
--the bouncy one as seen in the readme
-- Okay look. It works. It's not terribly slow because computers can do math
-- quick. The other one decidedly does not work (thanks sagemath, I trusted
-- you...) so this will have to do. I may try to fix it up at some point, I may
-- just leave it be and laugh to myself whenever I see this. As they say, if
-- As they say, if you want something fixed that badly, make a pull request lol
local bouncy = {
F = (20 * math.pi - (10 * math.log(2) - 2049) * math.sqrt(3)) /
(20 * math.pi - 20490 * math.sqrt(3) * math.log(2)),
easing = function(t)
--short circuit
if t == 0 then return 0 end
if t == 1 then return 1 end
local c1 = (20 * t * math.pi) / 3 - b_cs.c5
local c2 = math.pow(2, 10 * t + 1)
return (b_cs.c1 + b_cs.c2 * c2 * math.cos(c1) + b_cs.c3 * c2 * math.sin(c1)) / b_cs.c4
F = (20*math.sqrt(3)*math.pi-30*math.log(2)-6147) /
(10*(2*math.sqrt(3)*math.pi-6147*math.log(2))),
easing = function(t) return
(4096*math.pi*math.pow(2, 10*t-10)*math.cos(20/3*math.pi*t-43/6*math.pi)
+6144*math.pow(2, 10*t-10)*math.log(2)*math.sin(20/3*math.pi*t-43/6*math.pi)
+2*math.sqrt(3)*math.pi-3*math.log(2)) /
(2*math.pi*math.sqrt(3)-6147*math.log(2))
end
}

View file

@ -44,11 +44,12 @@ local function simulate_easing(pos, duration, intro, intro_e, outro, outro_e, m,
local ps_pos = pos
local dx
-- Key for cacheing results
local key = string.format("%f %f %f %s %f %s %s %s",
local key = string.format("%f %f %f %s %f %s %f %f",
pos, duration,
intro, intro_e,
outro, outro_e,
intro, tostring(intro_e),
outro, tostring(outro_e),
m, b)
-- Short circuits if it's already done the calculation
@ -106,22 +107,24 @@ local function timed(args)
obj.easing_inter = args.easing_inter or obj.easing
--dev interface changes
obj.log = args.log or false
obj.log = args.log or function() end
obj.awestore_compat = args.awestore_compat or false
--animation logic changes
obj.override_simulate = args.override_simulate or true
obj.rapid_set = args.rapid_set ~= nil and args.rapid_set or obj.awestore_compat
obj.rate = args.rate or RUBATO_DEF_RATE or 30
obj.override_dt = args.override_dt or RUBATO_OVERRIDE_DT or true
obj.override_simulate = args.override_simulate or false
--[[ rapid_set is allowed by awestore but I don't like it, so it's bound to awestore_compat if not explicitly set
override_dt doesn't work well with big animations or scratchpads (blame awesome not me) (probably) so that too is
is tied to awestore_compat if not explicitly set, then to the default value ]]
obj.rapid_set = args.rapid_set == nil and obj.awestore_compat or args.rapid_set
obj.override_dt = args.override_dt == nil and (not obj.awestore_compat and RUBATO_OVERRIDE_DT) or args.override_dt
-- hidden properties
obj._props = {
target = obj.pos
target = obj.pos,
rate = args.rate or RUBATO_DEF_RATE
}
-- annoying awestore compatibility
-- awestore compatibility
if obj.awestore_compat then
obj._initial = obj.pos
obj._last = 0
@ -134,37 +137,39 @@ local function timed(args)
end
--TODO: fix double pos thing
-- Variables used in calculation
local time = 0
local dt = 1 / obj.rate
local dx = 0
local m
local b
local is_inter --whether or not it's in an intermittent state
-- Variables used in calculation, defined once bcz less operations
local time = 0 -- current time
local dt = 1 / obj._props.rate -- change in time
local dx = 0 -- value of slope at current time
local m -- slope
local b -- y-intercept
local is_inter --whether or not it's in an intermittent state
local last_frame_time = 0 --the time before the last frame
local raw_dt = dt
local last_frame_time --the time at the last frame
local frame_time = dt --duration of the last frame (placeholder)
-- Variables used in simulation
local ps_pos
local coef
local ps_pos -- pseudoposition
local coef -- corrective coefficient TODO: apply to plateau
-- The timer that does all the animating
local timer = gears.timer()
local timer = gears.timer { timeout = dt }
timer:connect_signal("timeout", function()
-- Find the correct dt if it's not already correct
if (obj.override_dt) then
dt = os.clock() - last_frame_time
if (obj.override_dt and last_frame_time) then
frame_time = os.clock() - last_frame_time
if (raw_dt < dt) then timer.timeout = dt
else dt = raw_dt end
last_frame_time = os.clock()
--[[ if frame time is bigger than dt, we must readjust dt by the difference
between dt and the last frame. Basically, dt + (frame_time - dt) which just
results in frame_time ]]
if (frame_time > timer.timeout) then dt = frame_time
else dt = timer.timeout end
end
-- for the next timeout event
if (obj.override_dt) then last_frame_time = os.clock() end
--increment time
time = time + dt
@ -181,7 +186,7 @@ local function timed(args)
obj.pos = obj.pos + dx * dt * coef
--sets up when to stop by time
--weirdness is to try to get closest to duration
--weirdness is to try to get as close to duration as possible
if obj.duration - time < dt / 2 then
obj.pos = obj._props.target --snaps to target in case of small error
time = obj.duration --snaps time to duration
@ -192,7 +197,7 @@ local function timed(args)
--run subscribed in functions
obj:fire(obj.pos, time, dx)
-- awestore compatibility....
-- awestore compatibility...
if obj.awestore_compat then obj.ended:fire(obj.pos, time, dx) end
--otherwise it just fires normally
@ -203,19 +208,18 @@ local function timed(args)
-- Set target and begin interpolation
local function set(target_new)
--disallow setting it twice (because it makes it go wonky)
--disallow setting it twice (because it makes it go wonky sometimes)
if not obj.rapid_set and obj._props.target == target_new then return end
--animation values
obj._props.target = target_new --sets target
time = 0 --resets time
coef = 1 --resets coefficient
obj._props.target = target_new --sets target
time = 0 --resets time
coef = 1 --resets coefficient
--rate stuff
dt = 1 / obj.rate
raw_dt = dt
last_frame_time = os.clock()
timer.timeout = dt
--both of these values would ideally be timer.timeout so that's their default
dt, frame_time = timer.timeout, timer.timeout
last_frame_time = nil --is given a value after the first frame
-- does annoying awestore compatibility
if obj.awestore_compat then
@ -223,6 +227,7 @@ local function timed(args)
obj.started:fire(obj.pos, time, dx)
end
-- if it's already started, reflect that in is_inter
is_inter = timer.started
--set initial position if interrupting another animation
@ -238,7 +243,9 @@ local function timed(args)
b)
--if it will make a mistake (or override_simulate is true), fix it
if obj.override_simulate or b / math.abs(b) ~= m / math.abs(m) then
--it should only make a mistake when switching direction
--b ~= zero protection so that I won't get any NaNs (because NaN ~= NaN)
if obj.override_simulate or (b ~= 0 and b / math.abs(b) ~= m / math.abs(m)) then
ps_pos = simulate_easing(obj.pos, obj.duration,
(is_inter and obj.inter or obj.intro) * (obj.prop_intro and obj.duration or 1),
is_inter and obj.easing_inter.easing or obj.easing.easing,
@ -248,7 +255,7 @@ local function timed(args)
--get coefficient by calculating ratio of theoretical range : experimental range
coef = (obj.pos - obj._props.target) / (obj.pos - ps_pos)
if coef ~= coef then coef = 1 end --check for div by 0 resulting in nan
if coef ~= coef then coef = 1 end --check for div by 0 resulting in NaN
end
if not timer.started then timer:start() end
@ -268,8 +275,7 @@ local function timed(args)
b = nil
is_inter = false
coef = 1
dt = 1 / obj.rate
timer.timeout = dt
dt = timer.timeout
end
-- Effectively pauses the timer
@ -282,7 +288,6 @@ local function timed(args)
obj.subscribe_callback = function(func) func(obj.pos, time, dt) end
if args.subscribed ~= nil then obj:subscribe(args.subscribed) end
-- Metatable for cooler api
local mt = {}
function mt:__index(key)
@ -302,6 +307,11 @@ local function timed(args)
-- Changing target should call set
elseif key == "target" then set(value) --set target
-- Changing rate should also update timeout
elseif key == "rate" then
self._props.rate = value
timer.timeout = 1 / value
-- If it's in _props set it there
elseif self._props[key] ~= nil then self._props[key] = value

View file

@ -1,78 +0,0 @@
-- Credits to https://github.com/WillPower3309/awesome-widgets/blob/master/wallpaper-blur.lua
-- @author William McKinnon
-- I tried implementing this with `gears.wallpaper` but the latency was just too much, so feh is preferable here
local awful = require("awful")
local gears = require("gears")
local naughty = require("naughty")
local beautiful = require("beautiful")
local blurred = false;
local wallpaper = beautiful.wallpaper
local blurredWallpaper = beautiful.wallpaper_blur
awful.spawn.with_shell("feh --bg-fill " .. wallpaper)
local function exists(file)
local ok, err, code = os.rename(file, file)
if not ok then if code == 13 then return true end end
return ok, err
end
if not exists(blurredWallpaper) then
naughty.notify({
preset = naughty.config.presets.normal,
title = 'Wallpaper',
text = 'Generating blurred wallpaper...'
})
-- uses image magick to create a blurred version of the wallpaper
awful.spawn.with_shell(
"convert -filter Gaussian -blur 0x20 " .. wallpaper .. " " ..
blurredWallpaper)
naughty.notify({
preset = naughty.config.presets.normal,
title = 'Wallpaper',
text = 'Blurred wallpaper generated!'
})
end
-- changes to blurred wallpaper
local function blur()
if not blurred then
awful.spawn.with_shell("feh --bg-fill " .. blurredWallpaper)
blurred = true
end
end
-- changes to normal wallpaper
local function unblur()
if blurred then
awful.spawn.with_shell("feh --bg-fill " .. wallpaper)
blurred = false
end
end
-- blur / unblur on tag change
tag.connect_signal('property::selected', function(t)
-- if tag has clients
for _ in pairs(t:clients()) do
blur()
return
end
-- if tag has no clients
unblur()
end)
-- check if wallpaper should be blurred on client open
client.connect_signal("manage", function(c) blur() end)
-- check if wallpaper should be unblurred on client close
client.connect_signal("unmanage", function(c)
local t = awful.screen.focused().selected_tag
-- check if any open clients
for _ in pairs(t:clients()) do return end
-- unblur if no open clients
unblur()
end)

View file

@ -1,392 +0,0 @@
local cairo = require("lgi").cairo
local awful = require("awful")
local gears = require("gears")
local wibox = require("wibox")
local beautiful = require("beautiful")
local helpers = require("helpers")
local dpi = beautiful.xresources.apply_dpi
local window_switcher_first_client -- The client that was focused when the window_switcher was activated
local window_switcher_minimized_clients = {} -- The clients that were minimized when the window switcher was activated
local window_switcher_grabber
local get_num_clients = function(s)
local minimized_clients_in_tag = 0
local matcher = function(c)
return awful.rules.match(c, {
minimized = true,
skip_taskbar = false,
hidden = false,
first_tag = s.selected_tag
})
end
for c in awful.client.iterate(matcher) do
minimized_clients_in_tag = minimized_clients_in_tag + 1
end
return minimized_clients_in_tag + #s.clients
end
local window_switcher_hide = function()
-- Add currently focused client to history
if client.focus then
local window_switcher_last_client = client.focus
awful.client.focus.history.add(window_switcher_last_client)
-- Raise client that was focused originally
-- Then raise last focused client
if window_switcher_first_client and window_switcher_first_client.valid then
window_switcher_first_client:raise()
window_switcher_last_client:raise()
end
end
-- Minimize originally minimized clients
local s = awful.screen.focused()
local clients = s.selected_tag:clients()
for _, c in pairs(window_switcher_minimized_clients) do
if c and c.valid and not (client.focus and client.focus == c) then
c.minimized = true
end
end
-- Reset helper table
window_switcher_minimized_clients = {}
-- Resume recording focus history
awful.client.focus.history.enable_tracking()
-- Stop and hide window_switcher
awful.keygrabber.stop(window_switcher_grabber)
s.window_switcher_box.visible = false
end
local function draw_widget(s, type, client_width, client_height, client_margin,
background, border_radius, border_width,
border_color, text_font, font_icons, font_icons_font,
mouse_keys)
local set_icon = function(item, c)
local i = font_icons[c.class] or font_icons['_']
item:get_children_by_id('text_icon')[1].markup =
"<span foreground='" .. i.color .. "'>" .. i.symbol .. "</span>"
end
local update_thumbnail = function(self, c)
local content = gears.surface(c.content)
local cr = cairo.Context(content)
local x, y, w, h = cr:clip_extents()
local img = cairo.ImageSurface.create(cairo.Format.ARGB32, w - x, h - y)
cr = cairo.Context(img)
cr:set_source_surface(content, 0, 0)
cr.operator = cairo.Operator.SOURCE
cr:paint()
self:get_children_by_id('thumbnail')[1].image = gears.surface.load(img)
end
local icon_widget = function()
if (font_icons) ~= nil then
return {
widget = wibox.widget.textbox,
id = 'text_icon',
font = font_icons_font,
forced_width = dpi(50),
align = "center",
valign = "center"
}
else
return {
awful.widget.clienticon,
margins = 5,
forced_width = dpi(50),
widget = wibox.container.margin
}
end
end
local tasklist_widget = function()
if type == "text" then
return awful.widget.tasklist {
screen = s,
filter = awful.widget.tasklist.filter.currenttags,
buttons = mouse_keys,
style = {font = text_font},
layout = {layout = wibox.layout.fixed.vertical},
widget_template = {
widget = wibox.container.background,
id = "bg_role",
forced_height = item_height,
create_callback = function(self, c, _, __)
set_icon(self, c)
c:connect_signal("property::class",
function()
set_icon(self, c)
end)
end,
{
layout = wibox.layout.fixed.horizontal,
icon_widget(),
{
{
widget = wibox.widget.textbox,
id = 'text_role',
align = "center"
},
widget = wibox.container.margin,
left = dpi(6),
right = dpi(14),
-- Add margins to top and bottom in order to force the
-- text to be on a single line, if needed. Might need
-- to adjust them according to font size.
top = dpi(14),
bottom = dpi(14)
}
}
}
}
else
return awful.widget.tasklist {
screen = s,
filter = awful.widget.tasklist.filter.currenttags,
buttons = mouse_keys,
style = {font = text_font},
layout = {layout = wibox.layout.flex.horizontal},
widget_template = {
widget = wibox.container.background,
id = "bg_role",
forced_width = client_width,
forced_height = client_height,
create_callback = function(self, c, _, __)
if (font_icons) ~= nil then
set_icon(self, c)
c:connect_signal("property::class",
function()
set_icon(self, c)
end)
end
update_thumbnail(self, c)
end,
update_callback = function(self, c, _, __)
if (font_icons) ~= nil then
set_icon(self, c)
c:connect_signal("property::class",
function()
set_icon(self, c)
end)
end
update_thumbnail(self, c)
end,
{
layout = wibox.layout.flex.vertical,
{
widget = wibox.container.margin,
left = dpi(6),
right = dpi(14),
-- Add margins to top and bottom in order to force the
-- text to be on a single line, if needed. Might need
-- to adjust them according to font size.
top = dpi(14),
bottom = dpi(14),
{
widget = wibox.widget.imagebox,
id = 'thumbnail',
resize = true,
horizontal_fit_policy = "fit",
vertical_fit_policy = "fit"
}
},
{
layout = wibox.layout.fixed.horizontal,
icon_widget(),
{
widget = wibox.container.margin,
left = dpi(6),
right = dpi(14),
-- Add margins to top and bottom in order to force the
-- text to be on a single line, if needed. Might need
-- to adjust them according to font size.
top = dpi(14),
bottom = dpi(14),
{
widget = wibox.widget.textbox,
id = 'text_role',
align = "center"
}
}
}
}
}
}
end
end
s.window_switcher_tasklist = tasklist_widget()
s.window_switcher_box = awful.popup({
type = "dropdown_menu",
visible = false,
ontop = true,
screen = s,
bg = "#00000000",
widget = {
{
s.window_switcher_tasklist,
margins = client_margin,
widget = wibox.container.margin
},
bg = background,
shape_border_color = border_color,
shape_border_width = border_width,
shape = helpers.rrect(border_radius),
widget = wibox.container.background
}
})
-- Center window switcher whenever its height changes
s.window_switcher_box:connect_signal("property::width", function()
awful.placement.centered(s.window_switcher_box,
{honor_workarea = true, honor_padding = true})
if s.window_switcher_box.visible and get_num_clients(s) == 0 then
window_switcher_hide()
end
end)
s.window_switcher_box:connect_signal("property::height", function()
awful.placement.centered(s.window_switcher_box,
{honor_workarea = true, honor_padding = true})
if s.window_switcher_box.visible and get_num_clients(s) == 0 then
window_switcher_hide()
end
end)
end
local enable = function(opts)
local opts = opts or {}
local type = opts.type or "thumbnail"
local client_width
if type == "thumbnail" then
client_width = opts.client_width or dpi(150)
else
client_width = opts.client_width or dpi(500)
end
local client_height = opts.client_height or dpi(250)
local client_margin = opts.client_margin or dpi(10)
local background = beautiful.window_switcher_widget_bg or "#000000"
local border_radius = beautiful.window_switcher_widget_border_radius or
dpi(0)
local border_width = beautiful.window_switcher_widget_border_width or dpi(0)
local border_color = beautiful.window_switcher_widget_border_color or
"#ffffff"
local text_font = opts.text_font or beautiful.font
local font_icons = opts.font_icons or nil
local font_icons_font = opts.font_icons_font or beautiful.font
local hide_window_switcher_key = opts.hide_window_switcher_key or 'Escape'
local select_client_key = opts.select_client_key or 1
local minimize_key = opts.minimize_key or 'n'
local unminimize_key = opts.unminimize_key or 'N'
local kill_client_key = opts.kill_client_key or 'q'
local cycle_key = opts.cycle_key or 'Tab'
local previous_key = opts.previous_key or 'Left'
local next_key = opts.next_key or 'Right'
local vim_previous_key = opts.vim_previous_key or 'h'
local vim_next_key = opts.vim_next_key or 'l'
local scroll_previous_key = opts.scroll_previous_key or 4
local scroll_next_key = opts.scroll_next_key or 5
local mouse_keys = gears.table.join(awful.button {
modifiers = {"Any"},
button = select_client_key,
on_press = function(c) client.focus = c end
}, awful.button {
modifiers = {"Any"},
button = scroll_previous_key,
on_press = function() awful.client.focus.byidx(-1) end
}, awful.button {
modifiers = {"Any"},
button = scroll_next_key,
on_press = function() awful.client.focus.byidx(1) end
})
local keyboard_keys = {
[hide_window_switcher_key] = window_switcher_hide,
[minimize_key] = function()
if client.focus then client.focus.minimized = true end
end,
[unminimize_key] = function()
if awful.client.restore() then
client.focus = awful.client.restore()
end
end,
[kill_client_key] = function()
if client.focus then client.focus:kill() end
end,
[cycle_key] = function() awful.client.focus.byidx(1) end,
[previous_key] = function() awful.client.focus.byidx(1) end,
[next_key] = function() awful.client.focus.byidx(-1) end,
[vim_previous_key] = function() awful.client.focus.byidx(1) end,
[vim_next_key] = function() awful.client.focus.byidx(-1) end
}
awesome.connect_signal("module::window_switcher::visibility", function(s)
local number_of_clients = get_num_clients(s)
if number_of_clients == 0 then return end
-- Store client that is focused in a variable
window_switcher_first_client = client.focus
-- Stop recording focus history
awful.client.focus.history.disable_tracking()
-- Go to previously focused client (in the tag)
awful.client.focus.history.previous()
-- Track minimized clients
-- Unminimize them
-- Lower them so that they are always below other
-- originally unminimized windows
local clients = s.selected_tag:clients()
for _, c in pairs(clients) do
if c.minimized then
table.insert(window_switcher_minimized_clients, c)
c.minimized = false
c:lower()
end
end
-- Start the keygrabber
window_switcher_grabber = awful.keygrabber.run(
function(_, key, event)
if event == "release" then
-- Hide if the modifier was released
-- We try to match Super or Alt or Control since we do not know which keybind is
-- used to activate the window switcher (the keybind is set by the user in keys.lua)
if key:match("Super") or key:match("Alt") or
key:match("Control") then
window_switcher_hide()
end
-- Do nothing
return
end
-- Run function attached to key, if it exists
if keyboard_keys[key] then keyboard_keys[key]() end
end)
gears.timer.delayed_call(function()
-- Finally make the window switcher wibox visible after
-- a small delay, to allow the popup size to update
draw_widget(s, type, client_width, client_height, client_margin,
background, border_radius, border_width, border_color,
text_font, font_icons, font_icons_font, mouse_keys)
s.window_switcher_box.visible = true
end)
end)
end
return {enable = enable}

View file

@ -1,12 +1,13 @@
pcall(require, "luarocks.loader")
--[[
_____ __ _ __ _____ _____ _____ _______ _____
| | | | | ___| ___| | | ___|
| - | | | | ___|___ | | | | | | ___|
|__|__|_______|_____|_____|_____|__|_|__|_____|
~ AestheticArch ~
rxyhn
--]]
pcall(require, "luarocks.loader")
-- Standard awesome library
local gfs = require("gears.filesystem")
@ -14,17 +15,18 @@ local awful = require("awful")
-- Theme handling library
local beautiful = require("beautiful")
theme_dir = gfs.get_configuration_dir() .. "theme/"
dpi = beautiful.xresources.apply_dpi
beautiful.init(gfs.get_configuration_dir() .. "theme/theme.lua")
-- Default Applications
terminal = "alacritty"
browser = "firefox"
filemanager = "nautilus"
editor = terminal .. " -e " .. os.getenv("EDITOR")
vscode = "code"
editor = os.getenv("EDITOR") or "nvim"
editor_cmd = terminal .. " -e " .. editor
discord = "discord"
launcher = "rofi -show drun"
browser = "firefox"
launcher = "rofi -show drun -theme " .. theme_dir .. "rofi.rasi"
file_manager = "nautilus"
music_client = terminal .. " --class music -e ncmpcpp"
-- Weather API
openweathermap_key = "" -- API Key
@ -49,4 +51,3 @@ require("ui")
collectgarbage("setpause", 110)
collectgarbage("setstepmul", 1000)
-- EOF ------------------------------------------------------------------------

View file

@ -6,6 +6,11 @@ local playerctl = require("module.bling").signal.playerctl.lib()
playerctl:connect_signal("metadata", function(_, title, artist, album_path, album, new, player_name)
if new == true then
naughty.notify({title = title, text = artist, image = album_path})
naughty.notify ({
app_name = 'Music',
title = title,
text = artist,
image = album_path
})
end
end)

View file

@ -12,7 +12,9 @@ local function emit_volume_info()
-- In the output of `pacmd list-sinks`, lines +7 and +11 after "* index:"
-- contain the volume level and muted state respectively
-- This is why we are using `awk` to print them.
awful.spawn.easy_async_with_shell("pacmd list-sinks | awk '/\\* index: /{nr[NR+7];nr[NR+11]}; NR in nr'", function(stdout)
awful.spawn.easy_async_with_shell(
"pacmd list-sinks | awk '/\\* index: /{nr[NR+7];nr[NR+11]}; NR in nr'",
function(stdout)
local volume = stdout:match('(%d+)%% /')
local muted = stdout:match('muted:(%s+)[yes]')
local muted_int = muted and 1 or 0
@ -42,12 +44,12 @@ local volume_script = [[
-- Kill old pactl subscribe processes
awful.spawn.easy_async({"pkill", "--full", "--uid", os.getenv("USER"), "^pactl subscribe"}, function ()
awful.spawn.easy_async({
"pkill", "--full", "--uid", os.getenv("USER"), "^pactl subscribe"
}, function ()
-- Run emit_volume_info() with each line printed
awful.spawn.with_line_callback(volume_script, {
stdout = function(line)
emit_volume_info()
end
stdout = function(line) emit_volume_info() end
})
end)

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="240"
height="240"
viewBox="0 0 240 240"
id="svg4"
sodipodi:docname="brightness-7.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1321"
inkscape:window-height="740"
id="namedview6"
showgrid="false"
inkscape:pagecheckerboard="true"
inkscape:zoom="0.98333333"
inkscape:cx="-267.45763"
inkscape:cy="120"
inkscape:window-x="45"
inkscape:window-y="28"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" />
<path
d="M 120,84.6331 A 35.366932,35.366932 0 0 0 84.6331,120 35.366932,35.366932 0 0 0 120,155.3669 35.366932,35.366932 0 0 0 155.3669,120 35.366932,35.366932 0 0 0 120,84.6331 m 0,88.4173 A 53.050398,53.050398 0 0 1 66.9496,120 53.050398,53.050398 0 0 1 120,66.9496 53.050398,53.050398 0 0 1 173.0504,120 53.050398,53.050398 0 0 1 120,173.0504 M 190.7339,90.7339 V 49.2661 H 149.2661 L 120,20 90.7339,49.2661 H 49.2661 V 90.7339 L 20,120 49.2661,149.2661 v 41.4678 H 90.7339 L 120,220 149.2661,190.7339 h 41.4678 V 149.2661 L 220,120 Z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:8.84173298" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="240"
height="240"
viewBox="0 0 240 240"
id="svg4"
sodipodi:docname="volume-high.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1321"
inkscape:window-height="740"
id="namedview6"
showgrid="false"
inkscape:pagecheckerboard="true"
inkscape:zoom="0.98333333"
inkscape:cx="-267.45763"
inkscape:cy="120"
inkscape:window-x="45"
inkscape:window-y="28"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" />
<path
d="m 142.22222,22.555558 v 22.88889 c 32.11111,9.55555 55.55556,39.33333 55.55556,74.555552 0,35.22222 -23.44445,64.88888 -55.55556,74.44444 v 23 C 186.66667,207.33333 220,167.55555 220,120 220,72.444448 186.66667,32.666668 142.22222,22.555558 M 170,120 C 170,100.33333 158.88889,83.444448 142.22222,75.222228 V 164.44444 C 158.88889,156.55555 170,139.55555 170,120 M 20,86.666668 V 153.33333 H 64.444444 L 120,208.88888 V 31.111118 l -55.555556,55.55555 z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:11.11111164" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,14 +1,15 @@
# Shadows
shadow = true;
shadow-radius = 20;
shadow-spread = 10;
shadow-offset-x = -20;
shadow-offset-y = -20;
shadow-opacity = 1.8;
shadow = true;
shadow-radius = 14;
shadow-opacity = 0.50;
shadow-offset-x = -14;
shadow-offset-y = -14;
shadow-exclude = [
"class_g = 'Synapse'",
"class_g = 'slop'",
"window_type = 'menu'",
"window_type = 'desktop'",
"_GTK_FRAME_EXTENTS@:c",
"_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
];
@ -19,34 +20,26 @@ shadow-exclude = [
fading = true;
fade-in-step = 0.03;
fade-out-step = 0.03;
fade-delta = 2;
fade-delta = 3;
no-fading-destroyed-argb = true;
no-fading-openclose = false
no-fading-destroyed-argb = true
# Corners
# corner-radius = 3
rounded-corners-exclude = [
"name *= 'screenkey'",
"window_type = 'dock'",
"window_type = 'desktop'"
fade-exclude = [
"!window_type = 'dropdown_menu'"
];
# Background-Blurring
# blur-kern = "3x3box";
blur-kern = "11x11gaussian";
blur-method = "dual_kawase";
blur-strength = 3;
blur-strength = 3.0;
blur-background = false;
blur-background-frame = false;
blur-background-fixed = false;
blur-background-frame = true;
blur-background-fixed = true;
blur-background-exclude = [
"! name~=''",
"name *= 'rofi'",
"class_g = 'slop'",
# "window_type = 'dock'",
"!window_type = 'splash'",
"window_type = 'desktop'",
"_GTK_FRAME_EXTENTS@:c",
"_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'"
@ -57,26 +50,31 @@ blur-background-exclude = [
backend = "glx";
vsync = true;
daemon = false;
dbus = false;
mark-wmwin-focused = true;
mark-ovredir-focused = true;
detect-rounded-corners = true;
detect-client-opacity = true;
refresh-rate = 0;
detect-transient = true;
glx-no-stencil = true;
use-damage = true;
resize-damage = 1;
xrender-sync-fence = true;
glx-use-copysubbuffer-mesa = false;
transparent-clipping = false;
wintypes:
{
normal = { fade = true; full-shadow = true; };
tooltip = { fade = true; };
menu = { fade = true; };
popup_menu = { fade = true; full-shadow = true; };
dropdown_menu = { fade = true; };
utility = { fade = true; };
dialog = { fade = true; };
notify = { fade = true; };
unknown = { fade = true; };
notification = { full-shadow = true; };
# dock = { shadow = false; };
dropdown_menu = { fade = true; full-shadow = true; };
tooltip = { fade = true; shadow = false; focus = true; };
menu = { fade = true; full-shadow = true; };
utility = { fade = true; full-shadow = true; };
toolbar = {full-shadow = true;};
dialog = { fade = true; full-shadow = true; };
dock = { fade = true; full-shadow = true;};
};

View file

@ -1,8 +1,8 @@
configuration {
modi: "drun";
modi: "drun";
display-drun: "Apps";
drun-display-format: "{name}";
font: "Iosevka 9";
font: "Iosevka 8";
show-icons: true;
icon-theme: "Papirus";
}
@ -13,30 +13,30 @@ configuration {
bg: #061115;
fg: #d9d7d6;
accent: #1c252c;
darker-bg: #0A1419;
darkerAccent: #162026;
active: #484e5b;
rad: 10px;
rad: 12px;
background-color: @bg;
text-color: @fg;
}
window {
transparency: "real";
text-color: @fg;
location: center;
x-offset: 0;
y-offset: 0;
width: 30%;
border-radius: 10px;
transparency: "real";
height: 94%;
width: 22%;
location: west;
x-offset: 7%;
y-offset: 0%;
border-radius: @rad;
}
inputbar {
children: [ textbox, entry ];
expand: false;
margin: 20px 20px 0;
margin: 20px 20px 0 20px;
border-radius: @rad;
background-color: @darker-bg;
background-color: @darkerAccent;
}
textbox {
@ -51,20 +51,19 @@ textbox {
font: "Material Icons 17";
}
entry{
expand: true;
padding: 2%;
placeholder: "Search";
border-radius: @rad;
background-color: @darker-bg;
background-color: @darkerAccent;
}
listview {
columns: 3;
lines: 3;
columns: 2;
lines: 2;
cycle: false;
margin: 1em;
margin: 20px;
}
element {
@ -78,11 +77,11 @@ element-text, element-icon {
background-color: inherit;
}
element-icon { size: 36px; }
element-icon { size: 48px; }
listview, element, element selected, element-text, element-icon { cursor: pointer; }
element selected {
background-color: @darker-bg;
background-color: @darkerAccent;
text-color: @fg;
border-radius: 5px;
border-radius: @rad;
}

View file

@ -9,6 +9,8 @@ local theme_assets = require("beautiful.theme_assets")
local xresources = require("beautiful.xresources")
local xrdb = xresources.get_current_theme()
local dpi = xresources.apply_dpi
-- Helpers
local helpers = require("helpers")
@ -16,27 +18,27 @@ local helpers = require("helpers")
----------
-- Load ~/.Xresources colors
theme.xbackground = xrdb.background
theme.xforeground = xrdb.foreground
theme.xcolor0 = xrdb.color0
theme.xcolor1 = xrdb.color1
theme.xcolor2 = xrdb.color2
theme.xcolor3 = xrdb.color3
theme.xcolor4 = xrdb.color4
theme.xcolor5 = xrdb.color5
theme.xcolor6 = xrdb.color6
theme.xcolor7 = xrdb.color7
theme.xcolor8 = xrdb.color8
theme.xcolor9 = xrdb.color9
theme.xcolor10 = xrdb.color10
theme.xcolor11 = xrdb.color11
theme.xcolor12 = xrdb.color12
theme.xcolor13 = xrdb.color13
theme.xcolor14 = xrdb.color14
theme.xcolor15 = xrdb.color15
theme.xbackground = xrdb.background
theme.xforeground = xrdb.foreground
theme.xcolor0 = xrdb.color0
theme.xcolor1 = xrdb.color1
theme.xcolor2 = xrdb.color2
theme.xcolor3 = xrdb.color3
theme.xcolor4 = xrdb.color4
theme.xcolor5 = xrdb.color5
theme.xcolor6 = xrdb.color6
theme.xcolor7 = xrdb.color7
theme.xcolor8 = xrdb.color8
theme.xcolor9 = xrdb.color9
theme.xcolor10 = xrdb.color10
theme.xcolor11 = xrdb.color11
theme.xcolor12 = xrdb.color12
theme.xcolor13 = xrdb.color13
theme.xcolor14 = xrdb.color14
theme.xcolor15 = xrdb.color15
theme.darker_bg = "#0a1419"
theme.lighter_bg = "#162026"
theme.dash_fg = "#666c79"
theme.dashboard_fg = "#666c79"
theme.transparent = "#00000000"
-- PFP
@ -50,6 +52,8 @@ theme.awesome_logo = gears.surface.load_uncached(gfs.get_configuration_dir() ..
-- Notifications icon
theme.notification_icon = gears.surface.load_uncached(gfs.get_configuration_dir() .. "theme/assets/icons/notification.png")
theme.volume_icon = gears.surface.load_uncached(gfs.get_configuration_dir() .. "theme/assets/icons/volume.svg")
theme.brightness_icon = gears.surface.load_uncached(gfs.get_configuration_dir() .. "theme/assets/icons/brightness.svg")
-- Fonts
theme.font_name = "Iosevka "
@ -61,95 +65,84 @@ theme.font_taglist = theme.icon_font_name .. "13"
-- Background Colors
theme.bg_dark = theme.darker_bg
theme.bg_normal = theme.xbackground
theme.bg_focus = theme.xcolor0
theme.bg_urgent = theme.xcolor8
theme.bg_minimize = theme.xcolor8
theme.bg_focus = theme.xbackground
theme.bg_urgent = theme.xbackground
theme.bg_minimize = theme.xbackground
theme.bg_secondary = theme.darker_bg
theme.bg_accent = theme.lighter_bg
-- Foreground Colors
theme.fg_normal = theme.xforeground
theme.fg_focus = theme.xcolor4
theme.fg_urgent = theme.xcolor3
theme.fg_minimize = theme.xcolor8
theme.button_close = theme.xcolor1
theme.fg_focus = theme.xforeground
theme.fg_urgent = theme.xcolor1
theme.fg_minimize = theme.xcolor0
-- Borders
theme.border_width = dpi(0)
theme.oof_border_width = theme.border_width
theme.oof_border_width = dpi(0)
theme.border_normal = theme.darker_bg
theme.border_focus = theme.darker_bg
theme.border_radius = dpi(10)
theme.client_radius = dpi(12)
theme.widget_border_width = dpi(2)
theme.widget_border_color = theme.lighter_bg
theme.widget_border_color = theme.darker_bg
-- Radius
theme.border_radius = dpi(12)
theme.client_radius = dpi(10)
theme.dashboard_radius = dpi(10)
theme.bar_radius = dpi(10)
-- Taglist
-- Generate taglist squares:
local taglist_square_size = dpi(0)
theme.taglist_squares_sel = theme_assets.taglist_squares_sel(taglist_square_size, theme.fg_normal)
theme.taglist_squares_unsel = theme_assets.taglist_squares_unsel(taglist_square_size, theme.fg_normal)
theme.taglist_font = theme.font_taglist
theme.taglist_bg = theme.wibar_bg
theme.taglist_bg_focus = theme.lighter_bg
theme.taglist_fg_focus = theme.xcolor3
theme.taglist_bg_urgent = theme.wibar_bg
theme.taglist_fg_urgent = theme.xcolor6
theme.taglist_bg_occupied = theme.wibar_bg
theme.taglist_fg_occupied = theme.xcolor6
theme.taglist_bg_empty = theme.wibar_bg
theme.taglist_fg_empty = theme.xcolor8
theme.taglist_bg_volatile = transparent
theme.taglist_fg_volatile = theme.xcolor11
theme.taglist_disable_icon = true
theme.taglist_shape_focus = helpers.rrect(theme.border_radius / 2)
theme.taglist_shape_empty = helpers.rrect(theme.border_radius / 2)
theme.taglist_shape = helpers.rrect(theme.border_radius / 2)
theme.taglist_shape_urgent = helpers.rrect(theme.border_radius / 2)
theme.taglist_shape_volatile = helpers.rrect(theme.border_radius / 2)
-- Tasklist
theme.tasklist_font = theme.font
theme.tasklist_plain_task_name = true
theme.tasklist_bg_focus = theme.lighter_bg
theme.tasklist_fg_focus = theme.xcolor6
theme.tasklist_bg_minimize = theme.xcolor0 .. 55
theme.tasklist_fg_minimize = theme.xforeground .. 55
theme.tasklist_bg_normal = theme.darker_bg
theme.tasklist_fg_normal = theme.xforeground
theme.tasklist_disable_task_name = false
theme.tasklist_disable_icon = true
theme.tasklist_bg_urgent = theme.xcolor0
theme.tasklist_fg_urgent = theme.xcolor1
theme.tasklist_align = "center"
theme.taglist_shape_focus = helpers.rrect(theme.bar_radius)
theme.taglist_shape_empty = helpers.rrect(theme.bar_radius)
theme.taglist_shape = helpers.rrect(theme.bar_radius)
theme.taglist_shape_urgent = helpers.rrect(theme.bar_radius)
theme.taglist_shape_volatile = helpers.rrect(theme.bar_radius)
-- Titlebars
theme.titlebars_enabled = true
theme.titlebar_enabled = true
theme.titlebar_size = dpi(45)
theme.titlebar_unfocused = theme.xcolor0
-- Pop up notifications
theme.pop_size = dpi(180)
theme.pop_size = dpi(200)
theme.pop_bg = theme.xbackground
theme.pop_bar_bg = theme.xcolor0
theme.pop_vol_color = theme.xcolor4
theme.pop_brightness_color = theme.xcolor3
theme.pop_brightness_color = theme.xcolor5
theme.pop_fg = theme.xforeground
theme.pop_border_radius = dpi(6)
theme.pop_border_radius = theme.border_radius
-- Tooltip
theme.tooltip_height = dpi(490)
theme.tooltip_width = dpi(310)
theme.tooltip_bg = theme.xbackground
theme.tooltip_box_bg = theme.bg_secondary
theme.tooltip_fg = theme.xforeground
theme.tooltip_box_fg = theme.xcolor8
theme.tooltip_margin = dpi(15)
theme.tooltip_box_margin = dpi(10)
theme.tooltip_bg = theme.xbackground
theme.tooltip_height = dpi(245)
theme.tooltip_width = dpi(200)
theme.tooltip_gap = dpi(10)
theme.tooltip_border_radius = dpi(6)
theme.tooltip_box_border_radius = dpi(3)
theme.tooltip_border_width = dpi(0)
theme.tooltip_border_color = theme.xcolor0
theme.tooltip_box_margin = dpi(10)
theme.tooltip_border_radius = theme.border_radius
theme.tooltip_box_border_radius = theme.bar_radius
-- Edge snap
theme.snap_bg = theme.xcolor8
@ -159,18 +152,16 @@ theme.snap_shape = helpers.rrect(0)
theme.prompt_bg = transparent
theme.prompt_fg = theme.xforeground
-- Dashboard
theme.dash_width = dpi(300)
theme.dash_box_bg = theme.lighter_bg
theme.dash_box_fg = theme.dash_fg
-- dashboard
theme.dashboard_width = dpi(300)
theme.dashboard_box_bg = theme.lighter_bg
theme.dashboard_box_fg = theme.dashboard_fg
-- Tooltips
theme.tooltip_bg = theme.xbackground
theme.tooltip_fg = theme.xforeground
theme.tooltip_font = theme.font_name .. "10"
theme.tooltip_border_width = 0
theme.tooltip_opacity = 1
theme.tooltip_align = "top"
-- Playerctl
theme.playerctl_ignore = {"firefox", "qutebrowser", "chromium", "brave"}
theme.playerctl_player = {"spotify", "mpd", "%any"}
theme.playerctl_update_on_activity = true
theme.playerctl_position_update_interval = 1
-- Menu
theme.menu_height = dpi(30)
@ -186,15 +177,18 @@ theme.menu_submenu = "» "
theme.menu_submenu_icon = nil
-- Hotkeys Pop Up
theme.hotkeys_font = theme.font
theme.hotkeys_border_color = theme.lighter_bg
theme.hotkeys_group_margin = dpi(40)
theme.hotkeys_shape = helpers.rrect(5)
theme.hotkeys_bg = theme.xbackground
theme.hotkeys_fg = theme.xforeground
theme.hotkeys_modifiers_fg = theme.xforeground
theme.hotkeys_font = theme.font_name .. "10"
theme.hotkeys_description_font = theme.font_name .. "9"
theme.hotkeys_shape = helpers.rrect(theme.border_radius)
theme.hotkeys_group_margin = dpi(30)
-- Layout List
theme.layoutlist_border_color = theme.lighter_bg
theme.layoutlist_border_width = theme.border_width
theme.layoutlist_shape_selected = helpers.rrect(3)
theme.layoutlist_shape_selected = helpers.rrect(dpi(10))
theme.layoutlist_bg_selected = theme.lighter_bg
-- Recolor Layout icons:
@ -204,24 +198,20 @@ theme = theme_assets.recolor_layout(theme, theme.xforeground)
theme.useless_gap = dpi(5)
-- Wibar
theme.wibar_height = (dpi(42) + theme.widget_border_width) * 0
theme.wibar_width = dpi(42) + theme.widget_border_width
theme.wibar_margin = dpi(15)
theme.wibar_spacing = dpi(15)
theme.wibar_width = dpi(45)
theme.wibar_bg = theme.xbackground
theme.wibar_bg_secondary = theme.lighter_bg
theme.wibar_position = "left"
-- Tabs
theme.mstab_bar_height = dpi(60)
theme.mstab_bar_padding = dpi(0)
theme.mstab_border_radius = dpi(6)
theme.mstab_border_radius = theme.border_radius
theme.tabbar_disable = true
theme.tabbar_style = "modern"
theme.tabbar_bg_focus = theme.xbackground
theme.tabbar_bg_normal = theme.xcolor0
theme.tabbar_fg_focus = theme.xcolor0
theme.tabbar_fg_normal = theme.xcolor15
theme.tabbar_bg_focus = theme.lighter_bg
theme.tabbar_bg_normal = theme.darker_bg
theme.tabbar_fg_focus = theme.xforeground
theme.tabbar_fg_normal = theme.xcolor0
theme.tabbar_position = "bottom"
theme.tabbar_AA_radius = 0
theme.tabbar_size = 40
@ -238,26 +228,27 @@ theme.dont_swallow_classname_list = {
}
-- Layout Machi
theme.machi_switcher_border_color = theme.lighter_bg
theme.machi_switcher_border_color = theme.darker_bg
theme.machi_switcher_border_opacity = 0.25
theme.machi_editor_border_color = theme.lighter_bg
theme.machi_editor_border_color = theme.darker_bg
theme.machi_editor_border_opacity = 0.25
theme.machi_editor_active_opacity = 0.25
-- Tag Preview
theme.tag_preview_widget_border_radius = theme.border_radius / 2
theme.tag_preview_client_border_radius = theme.border_radius / 2
theme.tag_preview_client_border_radius = dpi(6)
theme.tag_preview_client_opacity = 0.1
theme.tag_preview_client_bg = theme.xbackground
theme.tag_preview_client_border_color = theme.lighter_bg
theme.tag_preview_client_border_color = theme.darker_bg
theme.tag_preview_client_border_width = theme.widget_border_width
theme.tag_preview_widget_border_radius = theme.border_radius
theme.tag_preview_widget_bg = theme.xbackground
theme.tag_preview_widget_border_color = theme.widget_border_color
theme.tag_preview_widget_border_width = theme.widget_border_width * 0
theme.tag_preview_widget_margin = dpi(10)
-- Task Preview
theme.task_preview_widget_border_radius = theme.border_radius / 2
theme.task_preview_widget_border_radius = dpi(10)
theme.task_preview_widget_bg = theme.xbackground
theme.task_preview_widget_border_color = theme.widget_border_color
theme.task_preview_widget_border_width = theme.widget_border_width * 0

View file

@ -11,6 +11,7 @@ local cairo = require("lgi").cairo
-- Analog clock
------------------
-- Stolen from No37
local function create_minute_pointer(minute)
local img = cairo.ImageSurface(cairo.Format.ARGB32, 1000, 1000)

41
config/mpd/mpd.conf Normal file
View file

@ -0,0 +1,41 @@
music_directory "~/Music"
playlist_directory "~/.config/mpd/playlists"
db_file "~/.config/mpd/database"
log_file "~/.config/mpd/log"
bind_to_address "127.0.0.1"
audio_output {
type "alsa"
name "ALSA [Bit-perfect]"
device "hw:1,0"
auto_channels "no"
auto_format "no"
auto_resample "no"
dop "yes"
mixer_type "none"
replay_gain_handler "none"
buffer_time "100000"
}
audio_output {
type "pulse"
name "PulseAudio"
buffer_time "100000"
}
audio_output {
type "fifo"
name "Visualizer"
format "44100:16:2"
path "/tmp/mpd.fifo"
}
audio_output {
type "httpd"
name "lossless"
encoder "flac"
port "8000"
max_client "8"
mixer_type "software"
format "44100:16:2"
}

392
config/ncmpcpp/bindings Normal file
View file

@ -0,0 +1,392 @@
#def_key "mouse"
# mouse_event
#
def_key "k"
scroll_up
#
#def_key "shift-up"
# select_item
# scroll_up
#
def_key "j"
scroll_down
#
#def_key "shift-down"
# select_item
# scroll_down
#
#def_key "["
# scroll_up_album
#
#def_key "]"
# scroll_down_album
#
#def_key "{"
# scroll_up_artist
#
#def_key "}"
# scroll_down_artist
#
#def_key "page_up"
# page_up
#
#def_key "page_down"
# page_down
#
#def_key "home"
# move_home
#
#def_key "end"
# move_end
#
#def_key "insert"
# select_item
#
#def_key "enter"
# enter_directory
#
#def_key "enter"
# toggle_output
#
#def_key "enter"
# run_action
#
#def_key "enter"
# play_item
#
#def_key "space"
# add_item_to_playlist
#
#def_key "space"
# toggle_lyrics_update_on_song_change
#
#def_key "space"
# toggle_visualization_type
#
#def_key "delete"
# delete_playlist_items
#
#def_key "delete"
# delete_browser_items
#
#def_key "delete"
# delete_stored_playlist
#
def_key "l"
next_column
#
#def_key "right"
# slave_screen
#
#def_key "right"
# volume_up
#
#def_key "+"
# volume_up
#
def_key "h"
previous_column
#
#def_key "left"
# master_screen
#
#def_key "left"
# volume_down
#
#def_key "="
# volume_down
#
#def_key ":"
# execute_command
#
#def_key "tab"
# next_screen
#
#def_key "shift-tab"
# previous_screen
#
#def_key "f1"
# show_help
#
#def_key "1"
# show_playlist
#
#def_key "2"
# show_browser
#
#def_key "2"
# change_browse_mode
#
#def_key "3"
# show_search_engine
#
#def_key "3"
# reset_search_engine
#
#def_key "4"
# show_media_library
#
#def_key "4"
# toggle_media_library_columns_mode
#
#def_key "5"
# show_playlist_editor
#
#def_key "6"
# show_tag_editor
#
#def_key "7"
# show_outputs
#
#def_key "8"
# show_visualizer
#
#def_key "-"
# show_clock
#
#def_key "@"
# show_server_info
#
#def_key "s"
# stop
#
#def_key "p"
# pause
#
#def_key ">"
# next
#
#def_key "<"
# previous
#
#def_key "ctrl-h"
# jump_to_parent_directory
#
#def_key "ctrl-h"
# replay_song
#
#def_key "backspace"
# jump_to_parent_directory
#
#def_key "backspace"
# replay_song
#
#def_key "f"
# seek_forward
#
#def_key "b"
# seek_backward
#
#def_key "r"
# toggle_repeat
#
#def_key "z"
# toggle_random
#
#def_key "y"
# save_tag_changes
#
#def_key "y"
# start_searching
#
#def_key "y"
# toggle_single
#
#def_key "R"
# toggle_consume
#
#def_key "Y"
# toggle_replay_gain_mode
#
#def_key "T"
# toggle_add_mode
#
#def_key "|"
# toggle_mouse
#
#def_key "#"
# toggle_bitrate_visibility
#
#def_key "Z"
# shuffle
#
#def_key "x"
# toggle_crossfade
#
#def_key "X"
# set_crossfade
#
#def_key "u"
# update_database
#
#def_key "ctrl-s"
# sort_playlist
#
#def_key "ctrl-s"
# toggle_browser_sort_mode
#
#def_key "ctrl-s"
# toggle_media_library_sort_mode
#
#def_key "ctrl-r"
# reverse_playlist
#
#def_key "ctrl-f"
# apply_filter
#
#def_key "ctrl-_"
# select_found_items
#
#def_key "/"
# find
#
#def_key "/"
# find_item_forward
#
#def_key "?"
# find
#
#def_key "?"
# find_item_backward
#
#def_key "."
# next_found_item
#
#def_key ","
# previous_found_item
#
#def_key "w"
# toggle_find_mode
#
#def_key "e"
# edit_song
#
#def_key "e"
# edit_library_tag
#
#def_key "e"
# edit_library_album
#
#def_key "e"
# edit_directory_name
#
#def_key "e"
# edit_playlist_name
#
#def_key "e"
# edit_lyrics
#
#def_key "i"
# show_song_info
#
#def_key "I"
# show_artist_info
#
#def_key "g"
# jump_to_position_in_song
#
def_key "L"
show_lyrics
#
#def_key "ctrl-v"
# select_range
#
#def_key "v"
# reverse_selection
#
#def_key "V"
# remove_selection
#
#def_key "B"
# select_album
#
#def_key "a"
# add_selected_items
#
#def_key "c"
# clear_playlist
#
#def_key "c"
# clear_main_playlist
#
#def_key "C"
# crop_playlist
#
#def_key "C"
# crop_main_playlist
#
#def_key "m"
# move_sort_order_up
#
#def_key "m"
# move_selected_items_up
#
#def_key "n"
# move_sort_order_down
#
#def_key "n"
# move_selected_items_down
#
#def_key "M"
# move_selected_items_to
#
#def_key "A"
# add
#
#def_key "S"
# save_playlist
#
#def_key "o"
# jump_to_playing_song
#
#def_key "G"
# jump_to_browser
#
#def_key "G"
# jump_to_playlist_editor
#
#def_key "~"
# jump_to_media_library
#
#def_key "E"
# jump_to_tag_editor
#
#def_key "U"
# toggle_playing_song_centering
#
#def_key "P"
# toggle_display_mode
#
#def_key "\\"
# toggle_interface
#
#def_key "!"
# toggle_separators_between_albums
#
#def_key "L"
# toggle_lyrics_fetcher
#
#def_key "F"
# fetch_lyrics_in_background
#
#def_key "alt-l"
# toggle_fetching_lyrics_in_background
#
#def_key "ctrl-l"
# toggle_screen_lock
#
#def_key "`"
# toggle_library_tag_type
#
#def_key "`"
# refetch_lyrics
#
#def_key "`"
# add_random_items
#
#def_key "ctrl-p"
# set_selected_items_priority
#
#def_key "q"
# quit
#

70
config/ncmpcpp/config Normal file
View file

@ -0,0 +1,70 @@
# DIRECTORY
# ---
ncmpcpp_directory = ~/.config/ncmpcpp
lyrics_directory = ~/.config/ncmpcpp/lyrics
mpd_music_dir = ~/Music
# GENERAL
# ---
external_editor = nvim
message_delay_time = 1
playlist_disable_highlight_delay = 2
autocenter_mode = "yes"
centered_cursor = "yes"
ignore_leading_the = "yes"
allow_for_physical_item_deletion = "no"
connected_message_on_startup = "yes"
cyclic_scrolling = "yes"
mouse_support = "yes"
mouse_list_scroll_whole_page = "yes"
lines_scrolled = "1"
playlist_shorten_total_times = "yes"
playlist_display_mode = "columns"
browser_display_mode = "columns"
search_engine_display_mode = "columns"
playlist_editor_display_mode = "columns"
user_interface = "classic"
follow_now_playing_lyrics = "yes"
display_bitrate = "no"
startup_screen = "playlist"
# VISUALIZER
# ---
visualizer_data_source = "/tmp/mpd.fifo"
visualizer_output_name = "Visualizer"
visualizer_in_stereo = "no"
visualizer_sync_interval = "30"
visualizer_type = "ellipse"
visualizer_fps = "60"
visualizer_look = ●▮
visualizer_color = "33,39,63,75,81,99,117,153,189"
# PROGRESS BAR
# ---
progressbar_look = " "
progressbar_color = "black"
progressbar_elapsed_color = "yellow"
# COLORS
# ---
main_window_color = "blue"
color1 = "white"
color2 = "blue"
# UI VISIBILITY
# ---
header_visibility = "no"
statusbar_visibility = "no"
titles_visibility = "no"
# UI APPEARANCE
# ---
now_playing_prefix = "$b$8$7 "
now_playing_suffix = " $/b$8"
current_item_prefix = "$b$7$/b$3 "
current_item_suffix = " $8"
song_status_format= "$7%t"
song_list_format = "$8%a - %t$R %l"
song_columns_list_format = "(53)[white]{tr} (45)[blue]{a}"
song_library_format = {{%a - %t} (%b)}|{%f}
song_window_title_format = "Music"