mess around

This commit is contained in:
Isshi0417 2024-07-12 18:19:30 +09:00
parent 4ca5c379bf
commit de81880762
242 changed files with 15238 additions and 10 deletions

281
flake.lock generated
View File

@ -256,7 +256,234 @@
"type": "github" "type": "github"
} }
}, },
"hyprcursor": {
"inputs": {
"hyprlang": [
"hyprland",
"hyprlang"
],
"nixpkgs": [
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1720108799,
"narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprcursor",
"type": "github"
}
},
"hyprland": {
"inputs": {
"hyprcursor": "hyprcursor",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs",
"systems": "systems",
"xdph": "xdph"
},
"locked": {
"lastModified": 1720731503,
"narHash": "sha256-Qlm0IRnOrI64RW/SEvW9rA1ytVvPS1CsVvRataNvStI=",
"ref": "refs/heads/main",
"rev": "e728e56cbc6af0a9be1276b2cf8e019a894016e7",
"revCount": 4917,
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
},
"original": {
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
}
},
"hyprland-hyprspace": {
"inputs": {
"hyprland": [
"hyprland"
]
},
"locked": {
"lastModified": 1720553729,
"narHash": "sha256-9aM4MCBJn4UstcsSdukOFTxg79keUMTw9Kmqr7Wsfmw=",
"owner": "KZDKM",
"repo": "Hyprspace",
"rev": "e8662093ae5b6e13a3cf1145d21d4804a3e84aeb",
"type": "github"
},
"original": {
"owner": "KZDKM",
"repo": "Hyprspace",
"type": "github"
}
},
"hyprland-plugins": {
"inputs": {
"hyprland": [
"hyprland"
],
"nixpkgs": [
"hyprland-plugins",
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland-plugins",
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1719784423,
"narHash": "sha256-D7O5+nh2Wn9tQPJArWHrDSZeEfBCtj5zTGd86701LPE=",
"owner": "hyprwm",
"repo": "hyprland-plugins",
"rev": "98cb18c6fcfe8196ef4150d09fbae305b7bb2954",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-plugins",
"type": "github"
}
},
"hyprland-protocols": {
"inputs": {
"nixpkgs": [
"hyprland",
"xdph",
"nixpkgs"
],
"systems": [
"hyprland",
"xdph",
"systems"
]
},
"locked": {
"lastModified": 1718746314,
"narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "1b61f0093afff20ab44d88ad707aed8bf2215290",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprlang": {
"inputs": {
"hyprutils": [
"hyprland",
"hyprutils"
],
"nixpkgs": [
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1720381373,
"narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"hyprutils": {
"inputs": {
"nixpkgs": [
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1720545076,
"narHash": "sha256-Pxacc2uoxI00koXp5+CyNqHOTQlqNlK0rlRHDBHX4+g=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "6174a2a25f4e216c0f1d0c4278adc23c476b1d09",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprwayland-scanner": {
"inputs": {
"nixpkgs": [
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1720215857,
"narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": {
"lastModified": 1720542800,
"narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "feb2849fdeb70028c70d73b848214b00d324a497",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1719690277, "lastModified": 1719690277,
"narHash": "sha256-0xSej1g7eP2kaUF+JQp8jdyNmpmCJKRpO12mKl/36Kc=", "narHash": "sha256-0xSej1g7eP2kaUF+JQp8jdyNmpmCJKRpO12mKl/36Kc=",
@ -272,7 +499,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1714912032, "lastModified": 1714912032,
"narHash": "sha256-clkcOIkg8G4xuJh+1onLG4HPMpbtzdLv4rHxFzgsH9c=", "narHash": "sha256-clkcOIkg8G4xuJh+1onLG4HPMpbtzdLv4rHxFzgsH9c=",
@ -293,7 +520,10 @@
"aagl": "aagl", "aagl": "aagl",
"catppuccin": "catppuccin", "catppuccin": "catppuccin",
"home-manager": "home-manager", "home-manager": "home-manager",
"nixpkgs": "nixpkgs", "hyprland": "hyprland",
"hyprland-hyprspace": "hyprland-hyprspace",
"hyprland-plugins": "hyprland-plugins",
"nixpkgs": "nixpkgs_2",
"stylix": "stylix" "stylix": "stylix"
} }
}, },
@ -309,7 +539,7 @@
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_2",
"gnome-shell": "gnome-shell", "gnome-shell": "gnome-shell",
"home-manager": "home-manager_2", "home-manager": "home-manager_2",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1719525570, "lastModified": 1719525570,
@ -324,6 +554,51 @@
"repo": "stylix", "repo": "stylix",
"type": "github" "type": "github"
} }
},
"systems": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"xdph": {
"inputs": {
"hyprland-protocols": "hyprland-protocols",
"hyprlang": [
"hyprland",
"hyprlang"
],
"nixpkgs": [
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1720194466,
"narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@ -17,6 +17,18 @@
url = "github:ezKEa/aagl-gtk-on-nix"; url = "github:ezKEa/aagl-gtk-on-nix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1";
hyprland-plugins = {
url = "github:hyprwm/hyprland-plugins";
inputs.hyprland.follows = "hyprland";
};
hyprland-hyprspace = {
url = "github:KZDKM/Hyprspace";
inputs.hyprland.follows = "hyprland";
};
}; };
outputs = { self, nixpkgs, ... }@inputs: outputs = { self, nixpkgs, ... }@inputs:

View File

@ -82,7 +82,7 @@
users.users.shoi = { users.users.shoi = {
isNormalUser = true; isNormalUser = true;
description = "Sho Ishida"; description = "Sho Ishida";
extraGroups = [ "networkmanager" "wheel" "input" ]; extraGroups = [ "networkmanager" "wheel" "input" "audio" ];
shell = pkgs.zsh; shell = pkgs.zsh;
}; };
@ -105,6 +105,8 @@
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. # vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
lm_sensors lm_sensors
brightnessctl
inotify-tools
]; ];
# Some programs need SUID wrappers, can be configured further or are # Some programs need SUID wrappers, can be configured further or are

View File

@ -22,16 +22,22 @@
# For funsies # For funsies
spotify spotify
vesktop vesktop
ncmpcpp
mpd
mpdris2
# Other utility # Other utility
mullvad-vpn mullvad-vpn
transmission_4-gtk transmission_4-gtk
imagemagick imagemagick
neofetch
]; ];
# Enable sound control # Enable sound control
services.easyeffects.enable = true; services.easyeffects.enable = true;
services.playerctld.enable = true;
# Home Manager is pretty good at managing dotfiles. The primary way to manage # Home Manager is pretty good at managing dotfiles. The primary way to manage
# plain files is through 'home.file'. # plain files is through 'home.file'.
home.file = { home.file = {

View File

@ -28,6 +28,7 @@
# Utils # Utils
corefonts corefonts
noto-fonts noto-fonts
flameshot
]; ];
programs.firefox.enable = true; programs.firefox.enable = true;

View File

@ -0,0 +1,8 @@
{ ... }:
{
home.file.".config/awesome" = {
recursive = true;
source = ./dotfiles;
};
}

View File

@ -0,0 +1,230 @@
local helpers = {}
local awful = require("awful")
local beautiful = require("beautiful")
local gears = require("gears")
local dpi = beautiful.xresources.apply_dpi
local cairo = require("lgi").cairo
local gmatrix = require("gears.matrix")
local json = require("mods.json")
helpers.rrect = function(radius)
radius = radius or dpi(4)
return function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, radius)
end
end
helpers.addHover = function(element, bg, hbg)
element:connect_signal('mouse::enter', function(self)
self.bg = hbg
end)
element:connect_signal('mouse::leave', function(self)
self.bg = bg
end)
end
helpers.placeWidget = function(widget)
if beautiful.barDir == 'left' then
awful.placement.bottom_left(widget, { honor_workarea = true, margins = beautiful.useless_gap * 2 })
elseif beautiful.barDir == 'right' then
awful.placement.bottom_right(widget, { honor_workarea = true, margins = beautiful.useless_gap * 2 })
elseif beautiful.barDir == 'bottom' then
awful.placement.bottom(widget, { honor_workarea = true, margins = beautiful.useless_gap * 2 })
elseif beautiful.barDir == 'top' then
awful.placement.top(widget, { honor_workarea = true, margins = beautiful.useless_gap * 2 })
end
end
helpers.prect = function(tl, tr, br, bl, radius)
radius = radius or dpi(4)
return function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, tl, tr, br, bl, radius)
end
end
helpers.clickKey = function(c, key)
awful.spawn.with_shell("xdotool type --window " .. tostring(c.window) .. " '" .. key .. "'")
end
helpers.colorizeText = function(txt, fg)
if fg == "" then
fg = "#ffffff"
end
return "<span foreground='" .. fg .. "'>" .. txt .. "</span>"
end
helpers.cropSurface = function(ratio, surf)
local old_w, old_h = gears.surface.get_size(surf)
local old_ratio = old_w / old_h
if old_ratio == ratio then return surf end
local new_h = old_h
local new_w = old_w
local offset_h, offset_w = 0, 0
-- quick mafs
if (old_ratio < ratio) then
new_h = math.ceil(old_w * (1 / ratio))
offset_h = math.ceil((old_h - new_h) / 2)
else
new_w = math.ceil(old_h * ratio)
offset_w = math.ceil((old_w - new_w) / 2)
end
local out_surf = cairo.ImageSurface(cairo.Format.ARGB32, new_w, new_h)
local cr = cairo.Context(out_surf)
cr:set_source_surface(surf, -offset_w, -offset_h)
cr.operator = cairo.Operator.SOURCE
cr:paint()
return out_surf
end
helpers.inTable = function(t, v)
for _, value in ipairs(t) do
if value == v then
return true
end
end
return false
end
helpers.generateId = function()
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
return string.gsub(template, '[xy]', function(c)
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
return string.format('%x', v)
end)
end
helpers.find_last = function(haystack, needle)
-- Set the third arg to false to allow pattern matching
local found = haystack:reverse():find(needle:reverse(), nil, true)
if found then
return haystack:len() - needle:len() - found + 2
else
return found
end
end
helpers.addTables = function(a, b)
local result = {}
for _, v in pairs(a) do
table.insert(result, v)
end
for _, v in pairs(b) do
table.insert(result, v)
end
return result
end
helpers.hasKey = function(set, key)
return set[key] ~= nil
end
helpers.trim = function(string)
return string:gsub("^%s*(.-)%s*$", "%1")
end
helpers.indexOf = function(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
helpers.split = function(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
table.insert(t, str)
end
return t
end
helpers.readFile = function(file)
local f = assert(io.open(file, "rb"))
local content = f:read("*all")
f:close()
return content
end
helpers.file_exists = function(name)
local f = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
local function get_widget_geometry(_hierarchy, widget)
local width, height = _hierarchy:get_size()
if _hierarchy:get_widget() == widget then
-- Get the extents of this widget in the device space
local x, y, w, h = gmatrix.transform_rectangle(_hierarchy:get_matrix_to_device(), 0, 0, width, height)
return { x = x, y = y, width = w, height = h, hierarchy = _hierarchy }
end
for _, child in ipairs(_hierarchy:get_children()) do
local ret = get_widget_geometry(child, widget)
if ret then
return ret
end
end
end
function helpers.get_widget_geometry(wibox, widget)
return get_widget_geometry(wibox._drawable._widget_hierarchy, widget)
end
function helpers.randomColor()
local accents = {
beautiful.magenta,
beautiful.yellow,
beautiful.green,
beautiful.red,
beautiful.blue,
}
local i = math.random(1, #accents)
return accents[i]
end
helpers.readJson = function(DATA)
if helpers.file_exists(DATA) then
local f = assert(io.open(DATA, "rb"))
local lines = f:read("*all")
f:close()
local data = json.decode(lines)
return data
else
return {}
end
end
helpers.writeJson = function(PATH, DATA)
local w = assert(io.open(PATH, "w"))
w:write(json.encode(DATA, nil, { pretty = true, indent = " ", align_keys = false, array_newline = true }))
w:close()
end
-- this stands for :get_children_by_id
helpers.gc = function(widget, id)
return widget:get_children_by_id(id)[1]
end
helpers.beginsWith = function(str, pattern)
return str:find('^' .. pattern) ~= nil
end
return helpers

View File

@ -0,0 +1,21 @@
local awful = require "awful"
local brightness = {}
brightness.increase = function()
local script = [[
brightnessctl set 3%+
]]
awful.spawn.with_shell(script)
end
brightness.decrease = function()
local script = [[
brightnessctl set 3%-
]]
awful.spawn.with_shell(script)
end
return brightness

View File

@ -0,0 +1,29 @@
local awful = require "awful"
local volume = {}
volume.increase = function()
local script = [[
pamixer -i 3
]]
awful.spawn.with_shell(script)
end
volume.decrease = function()
local script = [[
pamixer -d 3
]]
awful.spawn.with_shell(script)
end
volume.mute = function()
local script = [[
pamixer -t
]]
awful.spawn.with_shell(script)
end
return volume

View File

@ -0,0 +1,8 @@
local apps = {
terminal = "wezterm",
launcher = "rofi -show drun",
browser = "firefox",
fileManager = "thunar",
}
return apps

View File

@ -0,0 +1,6 @@
#!/bin/bash
mpDris2 &
xrdb -merge ~/.Xresources
picom --config $HOME/.config/picom/picom.conf
xss-lock lock
mkdir -p ~/.cache/awesome/json/

View File

@ -0,0 +1,230 @@
local awful = require "awful"
local gears = require "gears"
local naughty = require "naughty"
local beautiful = require "beautiful"
local apps = require "main.apps"
modkey = "Mod4"
-- General awesome keybindings
awful.keyboard.append_global_keybindings({
awful.key({ modkey, "Control" }, "r", awesome.restart,
{ description = "reload awesome", group = "awesome" }),
awful.key({ modkey, "Shift" }, "q", awesome.quit,
{ description = "quit awesome", group = "awesome" }),
awful.key({ modkey, }, "Return", function() awful.spawn(apps.terminal) end,
{ description = "open a terminal", group = "launcher" }),
})
-- Tag bindings
awful.keyboard.append_global_keybindings({
awful.key({ modkey, }, "Left", awful.tag.viewprev,
{ description = "view previous", group = "tag" }),
awful.key({ modkey, }, "Right", awful.tag.viewnext,
{ description = "view next", group = "tag" }),
awful.key({ modkey, }, "Escape", awful.tag.history.restore,
{ description = "go back", group = "tag" }),
})
awful.keyboard.append_global_keybindings({
awful.key {
modifiers = { modkey },
keygroup = "numrow",
description = "only view tag",
group = "tag",
on_press = function(index)
local screen = awful.screen.focused()
local tag = screen.tags[index]
if tag then
tag:view_only()
end
end,
},
awful.key {
modifiers = { modkey, "Control" },
keygroup = "numrow",
description = "toggle tag",
group = "tag",
on_press = function(index)
local screen = awful.screen.focused()
local tag = screen.tags[index]
if tag then
awful.tag.viewtoggle(tag)
end
end,
},
awful.key {
modifiers = { modkey, "Shift" },
keygroup = "numrow",
description = "move focused client to tag",
group = "tag",
on_press = function(index)
if client.focus then
local tag = client.focus.screen.tags[index]
if tag then
client.focus:move_to_tag(tag)
end
end
end,
},
awful.key {
modifiers = { modkey, "Control", "Shift" },
keygroup = "numrow",
description = "toggle focused client on tag",
group = "tag",
on_press = function(index)
if client.focus then
local tag = client.focus.screen.tags[index]
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,
}
})
-- Focus bindings
awful.keyboard.append_global_keybindings({
awful.key({ modkey, }, "j",
function()
awful.client.focus.byidx(1)
end,
{ description = "focus next by index", group = "client" }
),
awful.key({ modkey, }, "k",
function()
awful.client.focus.byidx(-1)
end,
{ description = "focus previous by index", group = "client" }
),
awful.key({ modkey, }, "Tab",
function()
awful.client.focus.history.previous()
if client.focus then
client.focus:raise()
end
end,
{ description = "go back", group = "client" }),
awful.key({ modkey, "Control" }, "j", function() awful.screen.focus_relative(1) end,
{ description = "focus the next screen", group = "screen" }),
awful.key({ modkey, "Control" }, "k", function() awful.screen.focus_relative(-1) end,
{ description = "focus the previous screen", group = "screen" }),
awful.key({ modkey, "Control" }, "n",
function()
local c = awful.client.restore()
-- Focus restored client
if c then
c:activate { raise = true, context = "key.unminimize" }
end
end,
{ description = "restore minimized", group = "client" }),
})
-- Layout bindings
awful.keyboard.append_global_keybindings({
awful.key({ modkey, "Shift" }, "j", function() awful.client.swap.byidx(1) end,
{ description = "swap with next client by index", group = "client" }),
awful.key({ modkey, "Shift" }, "k", function() awful.client.swap.byidx(-1) end,
{ description = "swap with previous client by index", group = "client" }),
awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
{ description = "jump to urgent client", group = "client" }),
awful.key({ modkey, }, "l", function() awful.tag.incmwfact(0.05) end,
{ description = "increase master width factor", group = "layout" }),
awful.key({ modkey, }, "h", function() awful.tag.incmwfact(-0.05) end,
{ description = "decrease master width factor", group = "layout" }),
awful.key({ modkey, "Shift" }, "h", function() awful.tag.incnmaster(1, nil, true) end,
{ description = "increase the number of master clients", group = "layout" }),
awful.key({ modkey, "Shift" }, "l", function() awful.tag.incnmaster(-1, nil, true) end,
{ description = "decrease the number of master clients", group = "layout" }),
awful.key({ modkey, "Control" }, "h", function() awful.tag.incncol(1, nil, true) end,
{ description = "increase the number of columns", group = "layout" }),
awful.key({ modkey, "Control" }, "l", function() awful.tag.incncol(-1, nil, true) end,
{ description = "decrease the number of columns", group = "layout" }),
awful.key({ modkey, }, "space", function() awful.layout.inc(1) end,
{ description = "select next", group = "layout" }),
awful.key({ modkey, "Shift" }, "space", function() awful.layout.inc(-1) end,
{ description = "select previous", group = "layout" }),
})
-- Client bindings
client.connect_signal("request::default_keybindings", function()
awful.keyboard.append_client_keybindings({
awful.key({ modkey, }, "f",
function(c)
c.fullscreen = not c.fullscreen
c:raise()
end,
{ description = "toggle fullscreen", group = "client" }),
awful.key({ modkey, "Shift" }, "c", function(c) c:kill() end,
{ description = "close", group = "client" }),
awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle,
{ description = "toggle floating", group = "client" }),
awful.key({ modkey, "Control" }, "Return", function(c) c:swap(awful.client.getmaster()) end,
{ description = "move to master", group = "client" }),
awful.key({ modkey, }, "o", function(c) c:move_to_screen() end,
{ description = "move to screen", group = "client" }),
awful.key({ modkey, }, "t", function(c) c.ontop = not c.ontop end,
{ description = "toggle keep on top", group = "client" }),
awful.key({ modkey, }, "n",
function(c)
-- The client currently has the input focus, so it cannot be
-- minimized, since minimized clients can't have the focus.
c.minimized = true
end,
{ description = "minimize", group = "client" }),
awful.key({ modkey, }, "m",
function(c)
c.maximized = not c.maximized
c:raise()
end,
{ description = "(un)maximize", group = "client" }),
awful.key({ modkey, "Control" }, "m",
function(c)
c.maximized_vertical = not c.maximized_vertical
c:raise()
end,
{ description = "(un)maximize vertically", group = "client" }),
awful.key({ modkey, "Shift" }, "m",
function(c)
c.maximized_horizontal = not c.maximized_horizontal
c:raise()
end,
{ description = "(un)maximize horizontally", group = "client" }),
})
end)
-- Mouse bindings
local menu = require("ui.rightclick")
awful.mouse.append_global_mousebindings({
awful.button({}, 3, function()
menu.desktop:toggle()
return
end),
})
client.connect_signal("request::default_mousebindings", function()
awful.mouse.append_client_mousebindings({
awful.button({}, 1, function(c)
c:activate { context = "mouse_click" }
end),
awful.button({ modkey }, 1, function(c)
c:activate { context = "mouse_click", action = "mouse_move" }
end),
awful.button({ modkey }, 3, function(c)
c:activate { context = "mouse_click", action = "mouse_resize" }
end),
})
end)

View File

@ -0,0 +1,45 @@
local awful = require "awful"
local volume = require "lib.volume"
local brightness = require "lib.brightness"
-- Volume
awful.keyboard.append_global_keybindings({
awful.key({}, "XF86AudioRaiseVolume", function()
volume.increase()
awesome.emit_signal("open::osd")
end),
awful.key({}, "XF86AudioLowerVolume", function()
volume.decrease()
awesome.emit_signal("open::osd")
end),
awful.key({}, "XF86AudioMute", function()
volume.mute()
awesome.emit_signal("open::osd")
end)
})
-- Brightness
awful.keyboard.append_global_keybindings({
awful.key({}, "XF86MonBrightnessUp", function()
brightness.increase()
awesome.emit_signal("open::osdb")
end),
awful.key({}, "XF86MonBrightnessDown", function()
brightness.decrease()
awesome.emit_signal("open::osdb")
end),
awful.key({ modkey, }, "a",
function(c)
awesome.emit_signal("toggle::launcher")
end),
awful.key({ modkey, }, "x",
function(c)
awesome.emit_signal("toggle::exit")
end),
awful.key({ modkey, }, "q",
function(c)
awesome.emit_signal("toggle::scrotter")
end),
})

View File

@ -0,0 +1,9 @@
local naughty = require "naughty"
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)

View File

@ -0,0 +1,10 @@
-- init config
require "main.wallpaper"
require "main.layout"
require "main.rules"
require "main.bindings.bindings"
require "main.bindings.custom_bindings"
require "main.tags"
require "main.swallow"
require "main.error_handling"
require "main.scratch"

View File

@ -0,0 +1,16 @@
local awful = require "awful"
local gears = require "gears"
local beautiful = require "beautiful"
awful.layout.layouts = {
awful.layout.suit.tile,
awful.layout.suit.floating,
}
client.connect_signal("mouse::enter", function(c)
c:activate { context = "mouse_enter", raise = false }
end)
client.connect_signal("manage", function(c)
if awesome.startup then awful.client.setslave(c) end
end)

View File

@ -0,0 +1,35 @@
local awful = require "awful"
local gears = require "gears"
local ruled = require "ruled"
ruled.client.connect_signal("request::rules", function()
ruled.client.append_rule {
id = "global",
rule = {},
properties = {
focus = awful.client.focus.filter,
raise = true,
screen = awful.screen.preferred,
placement = awful.placement.no_overlap + awful.placement.no_offscreen,
},
}
ruled.client.append_rule {
id = "titlebars",
rule_any = {
type = { "normal", "dialog" },
},
properties = {
titlebars_enabled = true
}
}
ruled.client.append_rule {
id = "desktop",
rule_any = {
class = {
"Nemo-desktop"
}
},
properties = { sticky = true, tag = " " }
}
end)

View File

@ -0,0 +1,162 @@
local awful = require("awful")
local gears = require("gears")
local beautiful = require("beautiful")
local ruled = require("ruled")
local Scratchpad = { mt = {} } -- scratch init
-- make a new instance of scratchpad
function Scratchpad:new(args)
local ret = gears.object {}
gears.table.crush(ret, Scratchpad)
gears.table.crush(ret, args)
return ret
end
local findClient = function(rule)
local function matcher(c)
return awful.rules.match(c, rule)
end
local clients = client.get()
local findex = gears.table.hasitem(clients, client.focus) or 1
local start = gears.math.cycle(#clients, findex + 1)
local matches = {}
for c in awful.client.iterate(matcher, start) do
matches[#matches + 1] = c
end
return matches
end
function Scratchpad:find()
return findClient(self.rule)
end
function Scratchpad:become(c)
if not c or not c.valid then return end
c.floating = true
c.sticky = false
c.fullscreen = false
c.maximised = false
c:geometry({
x = (1920 - self.width) / 2,
y = (1080 - self.height) / 2,
width = self.width,
height = self.height
})
end
function on(c)
local current_tag = c.screen.selected_tag
ctags = { current_tag }
for k, tag in pairs(c:tags()) do
if tag ~= current_tag then
table.insert(ctags, tag)
end
end
c:tags(ctags)
c:raise()
client.focus = c
end
function Scratchpad:on()
self.client = self:find()[1]
if not self.client then
local pid = awful.spawn.with_shell(self.command)
ruled.client.append_rule({
id = "scratch",
rule = self.rule,
properties = {
tag = awful.screen.focused().selected_tag,
switch_to_tags = false,
hidden = true,
minimized = true,
},
callback = function(c)
gears.timer({
timeout = 0.1,
autostart = true,
single_shot = true,
callback = function()
self.client = c
self:become(c)
c.hidden = false
c.minimized = false
c:activate({})
self:emit_signal("inital_apply", c)
if c.name ~= "Discord Updater" then
ruled.client.remove_rule("scratch")
end
c:connect_signal("request::unmanage", function()
ruled.client.remove_rule("scratch")
end)
end
})
end
})
else
self.client:raise()
client.focus = self.client
on(self.client)
self:become(self.client)
end
end
function turn_off(c)
current_tag = c.screen.selected_tag
local ctags = {}
for k, tag in pairs(c:tags()) do
if tag ~= current_tag then
table.insert(ctags, tag)
end
end
c:tags(ctags)
c.sticky = false
end
function Scratchpad:off()
self.client = self:find()[1]
turn_off(self.client)
end
function Scratchpad:toggle()
local is_turn_off = client.focus and awful.rules.match(client.focus, self.rule)
if is_turn_off then
self:off()
else
self:on()
end
end
function Scratchpad.mt:__call(...)
return Scratchpad:new(...)
end
local createScratch = function(command, width, height, k)
local scratch = Scratchpad:new {
--command = 'kitty' .. ' --class "' .. command .. 'pad" -e sh -c "' .. command .. '; $SHELL"',
command = 'wezterm start --class ' .. command .. 'pad -e sh -c "' .. command .. '; $SHELL"',
rule = { class = command .. 'pad' },
height = height,
width = width,
}
awful.keyboard.append_global_keybindings {
awful.key {
modifiers = { "Mod4" },
key = k,
description = 'show help',
group = 'awesome',
on_press = function() scratch:toggle() end,
},
}
awesome.connect_signal("toggle::" .. command .. "pad", function()
scratch:toggle()
end)
return scratch
end
local default = createScratch("clear", 1000, 650, 'v')
local ncmpcpp = createScratch("ncmpcpp", 800, 500, 'z')

View File

@ -0,0 +1,83 @@
-- documenting my shit because someone thought i write good code
local awful = require("awful")
local helpers = require("helpers")
local dontSuckMe = {} -- this is for classes that you dont want to be swallowed
-- eg local dontSuckMe = {"nemo", "firefox"}
local checkForSucc = function(child, parent)
local canSuc = false
if not helpers.inTable(dontSuckMe, child) and parent == "org.wezfurlong.wezterm" and child ~= "org.wezfurlong.wezterm" then -- write the class of your terminal here
canSuc = true
end
return canSuc
end
-- get the terminal window that executed the command maybe
local getDaddy = function(child, cb)
awful.spawn.easy_async(string.format("pstree -p %s", child), function(output, _, _, _)
cb(nil, output)
end)
end
-- this function was straight out ripped from bling
-- from what i understand this basically makes the window focused and on top
function on(c)
local current_tag = c.screen.selected_tag
ctags = { current_tag }
for k, tag in pairs(c:tags()) do
if tag ~= current_tag then
table.insert(ctags, tag)
end
end
c:tags(ctags)
c:raise()
client.focus = c
end
-- move the parent with the child
local sync = function(c, p)
if not c.valid or not p.valid then
return
end
if p.modal then
return
end
c.floating = p.floating
c.maximized = p.maximized
c.above = p.above
c.below = p.below
c:geometry(p:geometry())
end
-- this does the opposite off on() and you guessed it, also copied from bling
function off(c)
current_tag = c.screen.selected_tag
local ctags = {}
for k, tag in pairs(c:tags()) do
if tag ~= current_tag then
table.insert(ctags, tag)
end
end
c:tags(ctags)
c.sticky = false
end
-- the main implementation
local handle = function(c)
local daddy = awful.client.focus.history.get(c.screen, 1) -- read the history to get the parent terminal
if not daddy or daddy.type == "dialog" or daddy.type == "splash" then return end
getDaddy(c.pid, function(e, pid)
if (tostring(pid):find("(" .. tostring(daddy.pid) .. ")")) and checkForSucc(c.class, daddy.class) then -- check if the parent exists and the window can be swallowed
c:connect_signal("unmanage", function()
if daddy then
on(daddy)
sync(c, daddy)
end
end)
sync(c, daddy)
off(daddy)
end
end)
end
client.connect_signal("manage", handle) -- executing it

View File

@ -0,0 +1,5 @@
local awful = require "awful"
screen.connect_signal("request::desktop_decoration", function(s)
awful.tag({ "1", "2", "3", " " }, s, awful.layout.layouts[1])
end)

View File

@ -0,0 +1,17 @@
local gears = require "gears"
local beautiful = require "beautiful"
local helpeers = require "helpers"
local function set_wall(s)
local d = helpeers.readJson(gears.filesystem.get_cache_dir() .. 'json/settings.json')
if d.wallpaper == "colorful" then
gears.wallpaper.maximized(beautiful.wallpaper, s, beautiful.mbg)
else
gears.wallpaper.set(beautiful.bg3)
end
end
screen.connect_signal("request::wallpaper", function(s)
set_wall(s)
end)

View File

@ -0,0 +1,285 @@
-- Copyleft © 2022 Saimoomedits
--most stuff copied from guy above
local naughty = require("naughty")
local beautiful = require("beautiful")
local wibox = require("wibox")
local awful = require("awful")
local dpi = beautiful.xresources.apply_dpi
local helpers = require("helpers")
local ruled = require("ruled")
local menubar = require("menubar")
local animation = require("mods.animation")
local gears = require("gears")
naughty.connect_signal("request::icon", function(n, context, hints)
if context ~= "app_icon" then return end
local path = menubar.utils.lookup_icon(hints.app_icon) or menubar.utils.lookup_icon(hints.app_icon:lower())
if path then n.icon = path end
end)
-- naughty config
naughty.config.defaults.ontop = true
naughty.config.defaults.screen = awful.screen.focused()
naughty.config.defaults.timeout = 10
naughty.config.defaults.title = "Ding!"
naughty.config.defaults.position = "top_right"
-- Timeouts
naughty.config.presets.low.timeout = 10
naughty.config.presets.critical.timeout = 0
-- ruled notification
ruled.notification.connect_signal("request::rules", function()
ruled.notification.append_rule {
rule = {},
properties = { screen = awful.screen.preferred, implicit_timeout = 6 }
}
end)
-- connect to each display
--------------------------
naughty.connect_signal("request::display", function(n)
-- action widget
local action_widget = {
{
{
id = "text_role",
align = "center",
valign = "center",
font = beautiful.sans .. " 10",
widget = wibox.widget.textbox
},
left = dpi(6),
right = dpi(6),
widget = wibox.container.margin
},
bg = beautiful.mbg,
forced_height = dpi(30),
shape = helpers.rrect(2),
widget = wibox.container.background
}
-- actions
local actions = wibox.widget {
notification = n,
base_layout = wibox.widget {
spacing = dpi(8),
layout = wibox.layout.flex.horizontal
},
widget_template = action_widget,
style = { underline_normal = false, underline_selected = true },
widget = naughty.list.actions
}
-- image
local image_n = wibox.widget {
{
{
opacity = 0.9,
image = n.icon and helpers.cropSurface(1, gears.surface.load_uncached(n.icon)) or
gears.filesystem.get_configuration_dir() .. "theme/assets/" .. "bell.png",
resize = true,
halign = "center",
valign = "center",
clip_shape = helpers.rrect(50),
widget = wibox.widget.imagebox,
},
strategy = "exact",
height = dpi(50),
width = dpi(50),
widget = wibox.container.constraint,
},
id = "arc",
widget = wibox.container.arcchart,
max_value = 100,
min_value = 0,
value = 100,
rounded_edge = true,
thickness = dpi(4),
start_angle = 4.71238898,
bg = beautiful.blue,
colors = { beautiful.fg },
forced_width = dpi(80),
forced_height = dpi(80)
}
local anim = animation:new {
duration = 6,
target = 100,
reset_on_stop = false,
easing = animation.easing.linear,
update = function(_, pos)
image_n:get_children_by_id('arc')[1].value = pos
end,
}
anim:connect_signal("ended", function()
n:destroy()
end)
-- title
local title_n = wibox.widget {
{
{
markup = n.title,
font = beautiful.sans .. " 12",
align = "right",
valign = "center",
widget = wibox.widget.textbox
},
forced_width = dpi(240),
widget = wibox.container.scroll.horizontal,
step_function = wibox.container.scroll.step_functions.waiting_nonlinear_back_and_forth,
speed = 50
},
margins = { right = 15 },
widget = wibox.container.margin
}
local message_n = wibox.widget {
{
{
markup = helpers.colorizeText("<span weight='normal'>" .. n.message .. "</span>", beautiful.fg .. "BF"),
font = beautiful.sans .. " 12",
align = "left",
valign = "center",
wrap = "char",
widget = wibox.widget.textbox
},
forced_width = dpi(240),
layout = wibox.layout.fixed.horizontal
},
margins = { right = 15 },
widget = wibox.container.margin
}
-- app name
local aname = ''
if n.app_name ~= '' then
aname = n.app_name
else
aname = 'naughty'
end
local app_name_n = wibox.widget {
markup = helpers.colorizeText(aname, beautiful.fg .. "BF"),
font = beautiful.sans .. " 10",
align = "left",
valign = "center",
widget = wibox.widget.textbox
}
local time_n = wibox.widget {
{
markup = helpers.colorizeText("now", beautiful.fg .. "BF"),
font = beautiful.sans .. " 10",
align = "right",
valign = "center",
widget = wibox.widget.textbox
},
margins = { right = 20 },
widget = wibox.container.margin
}
local close = wibox.widget {
markup = helpers.colorizeText('󰝥', beautiful.red),
font = beautiful.icon .. " 12",
align = "ceneter",
valign = "center",
widget = wibox.widget.textbox
}
close:buttons(gears.table.join(
awful.button({}, 1, function() n:destroy(naughty.notification_closed_reason.dismissed_by_user) end)))
-- extra info
local notif_info = wibox.widget {
app_name_n,
{
widget = wibox.widget.separator,
shape = gears.shape.circle,
forced_height = dpi(4),
forced_width = dpi(4),
color = beautiful.fg .. "BF"
},
time_n,
layout = wibox.layout.fixed.horizontal,
spacing = dpi(7)
}
local widget = naughty.layout.box {
notification = n,
bg = beautiful.bg,
shape = helpers.rrect(8),
widget_template = {
{
{
-- top bit
{
{
{
close,
nil,
notif_info,
layout = wibox.layout.align.horizontal,
expand = "none"
},
margins = { left = dpi(15), right = dpi(15), top = dpi(10), bottom = dpi(10) },
widget = wibox.container.margin
},
widget = wibox.container.background,
bg = beautiful.mbg,
},
layout = wibox.layout.fixed.vertical
},
{
-- body
{
{
title_n,
message_n,
layout = wibox.layout.fixed.vertical,
spacing = dpi(3)
},
nil,
image_n,
layout = wibox.layout.align.horizontal,
expand = "none"
},
margins = { left = dpi(15), top = dpi(10), right = dpi(10) },
widget = wibox.container.margin
},
{
-- foot
actions,
margins = dpi(10),
widget = wibox.container.margin
},
layout = wibox.layout.fixed.vertical,
spacing = dpi(10)
},
widget = wibox.container.background,
shape = helpers.rrect(8),
bg = beautiful.bg,
}
}
widget.buttons = {}
anim:start()
end)

View File

@ -0,0 +1 @@
require("misc.dings.base")

View File

@ -0,0 +1,10 @@
local naughty = require("naughty")
local bling = require("mods.playerctl")
local playerctl = bling.lib()
playerctl:connect_signal("metadata",
function(_, title, artist, album_path, album, new, player_name)
if new == true then
naughty.notify({ title = 'New Song', text = title .. " by " .. artist, image = album_path })
end
end)

View File

@ -0,0 +1,3 @@
require "misc.titlebar"
require "misc.music"
require "misc.dings"

View File

@ -0,0 +1,304 @@
local awful = require 'awful'
require 'awful.autofocus'
local wibox = require 'wibox'
local gears = require 'gears'
local beautiful = require("beautiful")
local ruled = require("ruled")
local helpers = require("helpers")
local playerctl = require("mods.playerctl").lib()
local dpi = beautiful.xresources.apply_dpi
local art = wibox.widget {
image = helpers.cropSurface(1, gears.surface.load_uncached(beautiful.songdefpicture)),
clip_shape = helpers.rrect(10),
opacity = 0.75,
resize = true,
forced_height = dpi(60),
forced_width = dpi(60),
valign = 'center',
widget = wibox.widget.imagebox
}
local leftart = wibox.widget {
image = beautiful.songdefpicture,
clip_shape = helpers.rrect(10),
opacity = 0.75,
resize = true,
forced_height = dpi(250),
forced_width = dpi(250),
valign = 'center',
widget = wibox.widget.imagebox
}
local prev = wibox.widget {
align = 'center',
font = beautiful.icon .. " 24",
markup = helpers.colorizeText('󰒮', beautiful.fg),
widget = wibox.widget.textbox,
buttons = {
awful.button({}, 1, function()
playerctl:previous()
end)
},
}
local next = wibox.widget {
align = 'center',
font = beautiful.icon .. " 24",
markup = helpers.colorizeText('󰒭', beautiful.fg),
widget = wibox.widget.textbox,
buttons = {
awful.button({}, 1, function()
playerctl:next()
end)
},
}
local play = wibox.widget {
align = 'center',
font = beautiful.icon .. " 24",
markup = helpers.colorizeText('󰐊', beautiful.blue),
widget = wibox.widget.textbox,
buttons = {
awful.button({}, 1, function()
playerctl:play_pause()
end)
},
}
local shufflebtn = wibox.widget {
align = 'center',
font = beautiful.icon .. " 13",
markup = helpers.colorizeText('󰒝', beautiful.fg),
widget = wibox.widget.textbox,
buttons = {
awful.button({}, 1, function()
playerctl:cycle_shuffle()
end)
}
}
playerctl:connect_signal("shuffle", function(_, shuffle)
shufflebtn.markup = shuffle and helpers.colorizeText('󰒝', beautiful.blue) or helpers.colorizeText('󰒝',
beautiful.fg)
end)
local repeatt = wibox.widget {
align = 'center',
font = beautiful.icon .. " 13",
markup = helpers.colorizeText('󰑖', beautiful.fg),
widget = wibox.widget.textbox,
buttons = {
awful.button({}, 1, function()
playerctl:cycle_loop_status()
end)
}
}
playerctl:connect_signal("loop_status", function(_, loop_status)
if loop_status:match('none') then
repeatt.markup = helpers.colorizeText('󰑖', beautiful.fg)
elseif loop_status:match('track') then
repeatt.markup = helpers.colorizeText('󰑘', beautiful.magenta)
else
repeatt.markup = helpers.colorizeText('󰑖', beautiful.magenta)
end
end)
local createHandle = function(width, height, tl, tr, br, bl, radius)
return function(cr)
gears.shape.partially_rounded_rect(cr, width, height, tl, tr, br, bl, radius)
end
end
local slider = wibox.widget {
bar_shape = helpers.rrect(0),
bar_height = 3,
handle_color = beautiful.blue,
bar_color = beautiful.blue .. '33',
bar_active_color = beautiful.blue,
handle_shape = createHandle(18, 3, false, false, false, false, 0),
handle_margins = { top = 3 },
handle_width = 18,
forced_height = 10,
maximum = 100,
widget = wibox.widget.slider,
}
local songname = wibox.widget {
markup = helpers.colorizeText('Nothing Playing', beautiful.fg),
align = 'left',
valign = 'center',
forced_width = dpi(40),
font = beautiful.sans .. " 12",
widget = wibox.widget.textbox
}
local leftname = wibox.widget {
markup = helpers.colorizeText('Nothing Playing', beautiful.fg),
valign = 'center',
align = 'center',
font = beautiful.sans .. " 16",
widget = wibox.widget.textbox
}
local artistname = wibox.widget {
markup = helpers.colorizeText('None', beautiful.fg),
align = 'left',
valign = 'center',
forced_height = dpi(20),
font = beautiful.sans .. " 11",
widget = wibox.widget.textbox
}
local leftartist = wibox.widget {
markup = helpers.colorizeText('None', beautiful.fg),
align = 'center',
valign = 'center',
forced_height = dpi(20),
font = beautiful.sans .. " 11",
widget = wibox.widget.textbox
}
local is_prog_hovered = false
slider:connect_signal('mouse::enter', function()
is_prog_hovered = true
end)
slider:connect_signal('mouse::leave', function()
is_prog_hovered = false
end)
slider:connect_signal('property::value', function(_, value)
if is_prog_hovered then
playerctl:set_position(value)
end
end)
playerctl:connect_signal("position", function(_, interval_sec, length_sec)
slider.maximum = length_sec or 100
slider.value = interval_sec or 0
end)
playerctl:connect_signal("metadata", function(_, title, artist, album_path, album, new, player_name)
if player_name == "mpd" then
if album_path == "" then
album_path = beautiful.songdefpicture
end
if string.len(title) > 30 then
title = string.sub(title, 0, 30) .. "..."
end
if string.len(artist) > 22 then
artist = string.sub(artist, 0, 22) .. "..."
end
songname:set_markup_silently(helpers.colorizeText(title or "NO", beautiful.fg))
leftname:set_markup_silently(helpers.colorizeText(title or "NO", beautiful.fg))
leftartist:set_markup_silently(helpers.colorizeText(' ' .. artist or "WT" .. ' ', beautiful.fg))
artistname:set_markup_silently(helpers.colorizeText(artist or "HM", beautiful.fg))
art:set_image(gears.surface.load_uncached(album_path))
leftart:set_image(gears.surface.load_uncached(album_path))
end
end)
playerctl:connect_signal("playback_status", function(_, playing)
play.markup = playing and helpers.colorizeText("󰏤", beautiful.blue) or helpers.colorizeText("󰐊", beautiful.blue)
end)
local createTopButton = function(c, icon, click, color)
local widget = wibox.widget {
{
{
markup = helpers.colorizeText(icon, color),
valign = 'center',
forced_height = dpi(20),
font = beautiful.icon .. " 18",
widget = wibox.widget.textbox
},
margins = {
left = 8,
right = 8
},
widget = wibox.container.margin,
},
buttons = awful.button({}, 1, function()
helpers.clickKey(c, click)
end),
bg = beautiful.mbg,
widget = wibox.container.background
}
return widget
end
local bottom = function(c)
local playtab = createTopButton(c, '󰲸', '1', beautiful.blue)
local vistab = createTopButton(c, '󰐰', '8', beautiful.blue)
vistab:add_button(awful.button({}, 3, function()
helpers.clickKey(c, '8 ')
end))
awful.titlebar(c, { position = "bottom", size = dpi(100), bg = beautiful.mbg }):setup {
slider,
{
{
{
{
art,
{
{
songname,
artistname,
forced_width = 400,
layout = wibox.layout.fixed.vertical,
},
align = 'center',
widget = wibox.container.place
},
spacing = 13,
layout = wibox.layout.fixed.horizontal,
},
margins = {
top = 15,
bottom = 15,
left = 10,
right = 10,
},
widget = wibox.container.margin,
},
{
{
shufflebtn,
prev,
{
{
play,
margins = 4,
widget = wibox.container.margin
},
shape = helpers.rrect(3),
bg = beautiful.blue .. '11',
widget = wibox.container.background
},
next,
repeatt,
spacing = 15,
layout = wibox.layout.fixed.horizontal,
},
align = 'center',
widget = wibox.container.place,
},
{
playtab,
vistab,
spacing = 10,
layout = wibox.layout.fixed.horizontal,
},
expand = 'none',
layout = wibox.layout.align.horizontal,
},
widget = wibox.container.margin,
left = 15,
right = 15
},
layout = wibox.layout.fixed.vertical,
}
end
local final = function(c)
bottom(c)
end
ruled.client.connect_signal("request::rules", function()
ruled.client.append_rule {
id = "music",
rule_any = {
class = { "ncmpcpppad" },
role = { "pop-up" },
},
callback = final
}
end)

View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
STATUS="$(rfkill list | sed -n 2p | awk '{print $3}')"
toggle() {
if [[ $STATUS == "no" ]]; then
getroot 'pkexec rfkill block all'
notify-send --urgency=normal "Airplane Mode" "Airplane mode has been turned on!"
else
getroot 'pkexec rfkill unblock all'
notify-send --urgency=normal "Airplane Mode" "Airplane mode has been turned off!"
fi
}
if [[ $1 == "--toggle" ]]; then
toggle
fi

View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
toggle() {
STATUS="$(bluetoothctl show | grep Powered | awk '{print $2}')"
if [ $STATUS == "yes" ]; then
bluetoothctl power off
notify-send -a "Bluetooth" --urgency=normal "Bluetooth" "Bluetooth has been turned off."
else
bluetoothctl power on
notify-send -a "Bluetooth" --urgency=normal "Bluetooth" "Bluetooth has been turned on."
fi
}
if [[ $1 == "--toggle" ]]; then
toggle
fi

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
toggle(){
if [[ ! `pidof picom` ]]; then
picom &
else
pkill -9 picom
fi
}
if [[ $1 == "--toggle" ]]; then
toggle
fi

View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
is_active=$(cat ~/.cache/redshift)
toggle() {
if [[ $is_active == *"true"* ]]; then
redshift -x && echo false > ~/.cache/redshift
else
redshift -O 4000 && echo true > ~/.cache/redshift
fi
}
if [[ $1 == "--toggle" ]]; then
toggle
fi

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
STATUS=$(nmcli | grep wlan0 | awk 'FNR == 1 {print $2}')
SSID=$(iwgetid -r)
STRENGTH=$(awk 'NR==3 {printf("%.0f",$3*10/7)}' /proc/net/wireless)
toggle() {
if [[ $STATUS == "connected" ]]; then
nmcli radio wifi off
notify-send -a "wifi" --urgency=normal "Wi-Fi" "Wi-Fi has been turned off!"
else
nmcli radio wifi on
notify-send -a "wifi" --urgency=normal "Wi-Fi" "Wi-Fi has been turned on, you are back online!"
fi
}
if [[ $1 == "--toggle" ]]; then
toggle
fi

View File

@ -0,0 +1,103 @@
local awful = require "awful"
local gears = require "gears"
local wibox = require "wibox"
local beautiful = require "beautiful"
local helpers = require "helpers"
local getIcon = require "mods.getIcon"
local dpi = beautiful.xresources.apply_dpi
----- Titlebar
local get_titlebar = function(c)
-- Button
local buttons = gears.table.join({
awful.button({}, 1, function()
c:activate { context = "titlebar", action = "mouse_move" }
end),
awful.button({}, 3, function()
c:activate { context = "titlebar", action = "mouse_resize" }
end)
})
-- Titlebar's decorations
local left = wibox.widget {
{
{
awful.titlebar.widget.closebutton(c),
awful.titlebar.widget.maximizedbutton(c),
awful.titlebar.widget.minimizebutton(c),
spacing = dpi(5),
layout = wibox.layout.fixed.horizontal,
},
widget = wibox.container.margin,
margins = 8
},
shape = helpers.rrect(5),
widget = wibox.container.background,
bg = beautiful.mbg
}
local middle = wibox.widget {
buttons = buttons,
layout = wibox.layout.fixed.horizontal,
}
local right = wibox.widget {
{
{
{
widget = wibox.widget.imagebox,
image = getIcon(c, c.class, c.class),
forced_width = 30,
clip_shape = helpers.rrect(100),
resize = true,
},
widget = wibox.container.place,
halign = "center",
},
margins = dpi(5),
widget = wibox.container.margin
},
bg = beautiful.mbg,
shape = helpers.rrect(5),
widget = wibox.container.background
}
local container = wibox.widget {
bg = beautiful.bar,
shape = function(cr, w, h) gears.shape.partially_rounded_rect(cr, w, h, true, true, false, false, 0) end,
widget = wibox.container.background,
}
c:connect_signal("focus", function() container.bg = beautiful.bg end)
c:connect_signal("unfocus", function() container.bg = beautiful.bg end)
return wibox.widget {
{
{
left,
middle,
right,
layout = wibox.layout.align.horizontal,
},
margins = { top = dpi(5), bottom = dpi(5), left = dpi(5), right = dpi(5) },
widget = wibox.container.margin,
},
widget = container,
}
end
local function top(c)
local titlebar = awful.titlebar(c, {
position = 'top',
size = dpi(50),
bg = beautiful.transparent
})
titlebar:setup {
widget = get_titlebar(c)
}
end
client.connect_signal("request::titlebars", function(c)
top(c)
end)

View File

@ -0,0 +1,239 @@
-------------------------------------------
-- @author https://github.com/Kasper24
-- @copyright 2021-2022 Kasper24
-------------------------------------------
local GLib = require("lgi").GLib
local gobject = require("gears.object")
local gtable = require("gears.table")
local subscribable = require("mods.animation.subscribable")
local tween = require("mods.animation.tween")
local ipairs = ipairs
local table = table
local pairs = pairs
local animation_manager = {}
animation_manager.easing =
{
linear = "linear",
inQuad = "inQuad",
outQuad = "outQuad",
inOutQuad = "inOutQuad",
outInQuad = "outInQuad",
inCubic = "inCubic",
outCubic = "outCubic",
inOutCubic = "inOutCubic",
outInCubic = "outInCubic",
inQuart = "inQuart",
outQuart = "outQuart",
inOutQuart = "inOutQuart",
outInQuart = "outInQuart",
inQuint = "inQuint",
outQuint = "outQuint",
inOutQuint = "inOutQuint",
outInQuint = "outInQuint",
inSine = "inSine",
outSine = "outSine",
inOutSine = "inOutSine",
outInSine = "outInSine",
inExpo = "inExpo",
outExpo = "outExpo",
inOutExpo = "inOutExpo",
outInExpo = "outInExpo",
inCirc = "inCirc",
outCirc = "outCirc",
inOutCirc = "inOutCirc",
outInCirc = "outInCirc",
inElastic = "inElastic",
outElastic = "outElastic",
inOutElastic = "inOutElastic",
outInElastic = "outInElastic",
inBack = "inBack",
outBack = "outBack",
inOutBack = "inOutBack",
outInBack = "outInBack",
inBounce = "inBounce",
outBounce = "outBounce",
inOutBounce = "inOutBounce",
outInBounce = "outInBounce"
}
local animation = {}
local instance = nil
local ANIMATION_FRAME_DELAY = 5
local function micro_to_milli(micro)
return micro / 1000
end
local function second_to_micro(sec)
return sec * 1000000
end
local function second_to_milli(sec)
return sec * 1000
end
function animation:start(args)
args = args or {}
-- Awestoer/Rubbto compatibility
-- I'd rather this always be a table, but Awestoer/Rubbto
-- except the :set() method to have 1 number value parameter
-- used to set the target
local is_table = type(args) == "table"
local initial = is_table and (args.pos or self.pos) or self.pos
local subject = is_table and (args.subject or self.subject) or self.subject
local target = is_table and (args.target or self.target) or args
local duration = is_table and (args.duration or self.duration) or self.duration
local easing = is_table and (args.easing or self.easing) or self.easing
duration = self._private.anim_manager._private.instant == true and 0.01 or duration
if self.tween == nil or self.reset_on_stop == true then
self.tween = tween.new
{
initial = initial,
subject = subject,
target = target,
duration = second_to_micro(duration),
easing = easing
}
end
if self._private.anim_manager._private.animations[self.index] == nil then
table.insert(self._private.anim_manager._private.animations, self)
end
self.state = true
self.last_elapsed = GLib.get_monotonic_time()
self.started:fire()
self:emit_signal("started")
end
function animation:set(args)
self:start(args)
self:emit_signal("set")
end
function animation:stop()
self.state = false
self:emit_signal("stopped")
end
function animation:abort(reset)
animation:stop(reset)
self:emit_signal("aborted")
end
function animation:initial()
return self._private.initial
end
function animation_manager:set_instant(value)
self._private.instant = value
end
function animation_manager:new(args)
args = args or {}
args.pos = args.pos or 0
args.subject = args.subject or nil
args.target = args.target or nil
args.duration = args.duration or 0
args.easing = args.easing or nil
args.loop = args.loop or false
args.signals = args.signals or {}
args.update = args.update or nil
args.reset_on_stop = args.reset_on_stop == nil and true or args.reset_on_stop
-- Awestoer/Rubbto compatibility
args.subscribed = args.subscribed or nil
local ret = subscribable()
ret.started = subscribable()
ret.ended = subscribable()
if args.subscribed ~= nil then
ret:subscribe(args.subscribed)
end
for sig, sigfun in pairs(args.signals) do
ret:connect_signal(sig, sigfun)
end
if args.update ~= nil then
ret:connect_signal("update", args.update)
end
gtable.crush(ret, args, true)
gtable.crush(ret, animation, true)
ret._private = {}
ret._private.anim_manager = self
ret._private.initial = args.pos
return ret
end
local function new()
local ret = gobject {}
gtable.crush(ret, animation_manager, true)
ret._private = {}
ret._private.animations = {}
ret._private.instant = false
GLib.timeout_add
(
GLib.PRIORITY_DEFAULT,
ANIMATION_FRAME_DELAY,
function()
for index, animation in ipairs(ret._private.animations) do
if animation.state == true then
-- compute delta time
local time = GLib.get_monotonic_time()
local delta = time - animation.last_elapsed
animation.last_elapsed = time
-- If pos is true, the animation has ended
local pos = animation.tween:update(delta)
if pos == true then
-- Loop the animation, don't end it.
-- Useful for widgets like the spinning cicle
if animation.loop == true then
animation.tween:reset()
else
-- Snap to end
animation.pos = animation.tween.target
animation:fire(animation.pos)
animation:emit_signal("update", animation.pos)
animation.state = false
animation.ended:fire(pos)
table.remove(ret._private.animations, index)
animation:emit_signal("ended", animation.pos)
end
-- Animation in process, keep updating
else
animation.pos = pos
animation:fire(animation.pos)
animation:emit_signal("update", animation.pos)
end
else
table.remove(ret._private.animations, index)
end
end
-- call again the function after cooldown
return true
end
)
return ret
end
if not instance then
instance = new()
end
return instance

View File

@ -0,0 +1,41 @@
-------------------------------------------
-- @author https://github.com/Kasper24
-- @copyright 2021-2022 Kasper24
-- Adopted from rubato
-------------------------------------------
local gobject = require("gears.object")
-- Kidna copying awesotre's stores on a surface level for added compatibility
local function subscribable(args)
local ret = gobject {}
local subscribed = {}
-- Subscrubes a function to the object so that it's called when `fire` is
-- Calls subscribe_callback if it exists as well
function ret:subscribe(func)
local id = tostring(func):gsub("function: ", "")
subscribed[id] = func
if self.subscribe_callback then self.subscribe_callback(func) end
end
-- Unsubscribes a function and calls unsubscribe_callback if it exists
function ret:unsubscribe(func)
if not func then
subscribed = {}
else
local id = tostring(func):gsub("function: ", "")
subscribed[id] = nil
end
if self.unsubscribe_callback then self.unsubscribe_callback(func) end
end
function ret:fire(...) for _, func in pairs(subscribed) do func(...) end end
return ret
end
return subscribable

View File

@ -0,0 +1,527 @@
-------------------------------------------
-- @author https://github.com/Kasper24
-- @copyright 2021-2022 Kasper24
-------------------------------------------
-- easing
-- Adapted from https://github.com/EmmanuelOga/easing. See LICENSE.txt for credits.
-- For all easing functions:
-- t = time == how much time has to pass for the tweening to complete
-- b = begin == starting property value
-- c = change == ending - beginning
-- d = duration == running time. How much time has passed *right now*
local gobject = require("gears.object")
local gtable = require("gears.table")
local tween = {
_VERSION = 'tween 2.1.1',
_DESCRIPTION = 'tweening for lua',
_URL = 'https://github.com/kikito/tween.lua',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
local pow, sin, cos, pi, sqrt, abs, asin = math.pow, math.sin, math.cos, math.pi, math.sqrt, math.abs, math.asin
-- linear
local function linear(t, b, c, d)
return c * t / d + b
end
-- quad
local function inQuad(t, b, c, d)
return c * pow(t / d, 2) + b
end
local function outQuad(t, b, c, d)
t = t / d
return -c * t * (t - 2) + b
end
local function inOutQuad(t, b, c, d)
t = t / d * 2
if t < 1 then
return c / 2 * pow(t, 2) + b
end
return -c / 2 * ((t - 1) * (t - 3) - 1) + b
end
local function outInQuad(t, b, c, d)
if t < d / 2 then
return outQuad(t * 2, b, c / 2, d)
end
return inQuad((t * 2) - d, b + c / 2, c / 2, d)
end
-- cubic
local function inCubic(t, b, c, d)
return c * pow(t / d, 3) + b
end
local function outCubic(t, b, c, d)
return c * (pow(t / d - 1, 3) + 1) + b
end
local function inOutCubic(t, b, c, d)
t = t / d * 2
if t < 1 then
return c / 2 * t * t * t + b
end
t = t - 2
return c / 2 * (t * t * t + 2) + b
end
local function outInCubic(t, b, c, d)
if t < d / 2 then
return outCubic(t * 2, b, c / 2, d)
end
return inCubic((t * 2) - d, b + c / 2, c / 2, d)
end
-- quart
local function inQuart(t, b, c, d)
return c * pow(t / d, 4) + b
end
local function outQuart(t, b, c, d)
return -c * (pow(t / d - 1, 4) - 1) + b
end
local function inOutQuart(t, b, c, d)
t = t / d * 2
if t < 1 then
return c / 2 * pow(t, 4) + b
end
return -c / 2 * (pow(t - 2, 4) - 2) + b
end
local function outInQuart(t, b, c, d)
if t < d / 2 then
return outQuart(t * 2, b, c / 2, d)
end
return inQuart((t * 2) - d, b + c / 2, c / 2, d)
end
-- quint
local function inQuint(t, b, c, d)
return c * pow(t / d, 5) + b
end
local function outQuint(t, b, c, d)
return c * (pow(t / d - 1, 5) + 1) + b
end
local function inOutQuint(t, b, c, d)
t = t / d * 2
if t < 1 then
return c / 2 * pow(t, 5) + b
end
return c / 2 * (pow(t - 2, 5) + 2) + b
end
local function outInQuint(t, b, c, d)
if t < d / 2 then
return outQuint(t * 2, b, c / 2, d)
end
return inQuint((t * 2) - d, b + c / 2, c / 2, d)
end
-- sine
local function inSine(t, b, c, d)
return -c * cos(t / d * (pi / 2)) + c + b
end
local function outSine(t, b, c, d)
return c * sin(t / d * (pi / 2)) + b
end
local function inOutSine(t, b, c, d)
return -c / 2 * (cos(pi * t / d) - 1) + b
end
local function outInSine(t, b, c, d)
if t < d / 2 then
return outSine(t * 2, b, c / 2, d)
end
return inSine((t * 2) - d, b + c / 2, c / 2, d)
end
-- expo
local function inExpo(t, b, c, d)
if t == 0 then
return b
end
return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001
end
local function outExpo(t, b, c, d)
if t == d then
return b + c
end
return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b
end
local function inOutExpo(t, b, c, d)
if t == 0 then
return b
end
if t == d then
return b + c
end
t = t / d * 2
if t < 1 then
return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005
end
return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b
end
local function outInExpo(t, b, c, d)
if t < d / 2 then
return outExpo(t * 2, b, c / 2, d)
end
return inExpo((t * 2) - d, b + c / 2, c / 2, d)
end
-- circ
local function inCirc(t, b, c, d)
return (-c * (sqrt(1 - pow(t / d, 2)) - 1) + b)
end
local function outCirc(t, b, c, d)
return (c * sqrt(1 - pow(t / d - 1, 2)) + b)
end
local function inOutCirc(t, b, c, d)
t = t / d * 2
if t < 1 then
return -c / 2 * (sqrt(1 - t * t) - 1) + b
end
t = t - 2
return c / 2 * (sqrt(1 - t * t) + 1) + b
end
local function outInCirc(t, b, c, d)
if t < d / 2 then
return outCirc(t * 2, b, c / 2, d)
end
return inCirc((t * 2) - d, b + c / 2, c / 2, d)
end
-- elastic
local function calculatePAS(p, a, c, d)
p, a = p or d * 0.3, a or 0
if a < abs(c) then
return p, c, p / 4
end -- p, a, s
return p, a, p / (2 * pi) * asin(c / a) -- p,a,s
end
local function inElastic(t, b, c, d, a, p)
local s
if t == 0 then
return b
end
t = t / d
if t == 1 then
return b + c
end
p, a, s = calculatePAS(p, a, c, d)
t = t - 1
return -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
end
local function outElastic(t, b, c, d, a, p)
local s
if t == 0 then
return b
end
t = t / d
if t == 1 then
return b + c
end
p, a, s = calculatePAS(p, a, c, d)
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
end
local function inOutElastic(t, b, c, d, a, p)
local s
if t == 0 then
return b
end
t = t / d * 2
if t == 2 then return b + c end
p, a, s = calculatePAS(p, a, c, d)
t = t - 1
if t < 0 then
return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
end
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) * 0.5 + c + b
end
local function outInElastic(t, b, c, d, a, p)
if t < d / 2 then
return outElastic(t * 2, b, c / 2, d, a, p)
end
return inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p)
end
-- back
local function inBack(t, b, c, d, s)
s = s or 1.70158
t = t / d
return c * t * t * ((s + 1) * t - s) + b
end
local function outBack(t, b, c, d, s)
s = s or 1.70158
t = t / d - 1
return c * (t * t * ((s + 1) * t + s) + 1) + b
end
local function inOutBack(t, b, c, d, s)
s = (s or 1.70158) * 1.525
t = t / d * 2
if t < 1 then
return c / 2 * (t * t * ((s + 1) * t - s)) + b
end
t = t - 2
return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b
end
local function outInBack(t, b, c, d, s)
if t < d / 2 then
return outBack(t * 2, b, c / 2, d, s)
end
return inBack((t * 2) - d, b + c / 2, c / 2, d, s)
end
-- bounce
local function outBounce(t, b, c, d)
t = t / d
if t < 1 / 2.75 then
return c * (7.5625 * t * t) + b
end
if t < 2 / 2.75 then
t = t - (1.5 / 2.75)
return c * (7.5625 * t * t + 0.75) + b
elseif t < 2.5 / 2.75 then
t = t - (2.25 / 2.75)
return c * (7.5625 * t * t + 0.9375) + b
end
t = t - (2.625 / 2.75)
return c * (7.5625 * t * t + 0.984375) + b
end
local function inBounce(t, b, c, d)
return c - outBounce(d - t, 0, c, d) + b
end
local function inOutBounce(t, b, c, d)
if t < d / 2 then
return inBounce(t * 2, 0, c, d) * 0.5 + b
end
return outBounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b
end
local function outInBounce(t, b, c, d)
if t < d / 2 then
return outBounce(t * 2, b, c / 2, d)
end
return inBounce((t * 2) - d, b + c / 2, c / 2, d)
end
tween.easing =
{
linear = linear,
inQuad = inQuad, outQuad = outQuad, inOutQuad = inOutQuad, outInQuad = outInQuad,
inCubic = inCubic, outCubic = outCubic, inOutCubic = inOutCubic, outInCubic = outInCubic,
inQuart = inQuart, outQuart = outQuart, inOutQuart = inOutQuart, outInQuart = outInQuart,
inQuint = inQuint, outQuint = outQuint, inOutQuint = inOutQuint, outInQuint = outInQuint,
inSine = inSine, outSine = outSine, inOutSine = inOutSine, outInSine = outInSine,
inExpo = inExpo, outExpo = outExpo, inOutExpo = inOutExpo, outInExpo = outInExpo,
inCirc = inCirc, outCirc = outCirc, inOutCirc = inOutCirc, outInCirc = outInCirc,
inElastic = inElastic, outElastic = outElastic, inOutElastic = inOutElastic, outInElastic = outInElastic,
inBack = inBack, outBack = outBack, inOutBack = inOutBack, outInBack = outInBack,
inBounce = inBounce, outBounce = outBounce, inOutBounce = inOutBounce, outInBounce = outInBounce
}
-- Private interface
local function copyTables(destination, keysTable, valuesTable)
valuesTable = valuesTable or keysTable
local mt = getmetatable(keysTable)
if mt and getmetatable(destination) == nil then
setmetatable(destination, mt)
end
for k, v in pairs(keysTable) do
if type(v) == 'table' then
destination[k] = copyTables({}, v, valuesTable[k])
else
destination[k] = valuesTable[k]
end
end
return destination
end
local function checkSubjectAndTargetRecursively(subject, target, path)
path = path or {}
local targetType, newPath
for k, targetValue in pairs(target) do
targetType, newPath = type(targetValue), copyTables({}, path)
table.insert(newPath, tostring(k))
if targetType == 'number' then
assert(type(subject[k]) == 'number',
"Parameter '" .. table.concat(newPath, '/') .. "' is missing from subject or isn't a number")
elseif targetType == 'table' then
checkSubjectAndTargetRecursively(subject[k], targetValue, newPath)
else
assert(targetType == 'number',
"Parameter '" .. table.concat(newPath, '/') .. "' must be a number or table of numbers")
end
end
end
local function checkNewParams(initial, duration, subject, target, easing)
-- assert(type(initial) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
-- assert(type(duration) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
assert(type(easing) == 'function', "easing must be a function. Was " .. tostring(easing))
if subject and target then
local tsubject = type(subject)
assert(tsubject == 'table' or tsubject == 'userdata',
"subject must be a table or userdata. Was " .. tostring(subject))
assert(type(target) == 'table', "target must be a table. Was " .. tostring(target))
checkSubjectAndTargetRecursively(subject, target)
end
end
local function getEasingFunction(easing)
easing = easing or "linear"
if type(easing) == 'string' then
local name = easing
easing = tween.easing[name]
if type(easing) ~= 'function' then
error("The easing function name '" .. name .. "' is invalid")
end
end
return easing
end
local function performEasingOnSubject(subject, target, initial, clock, duration, easing)
local t, b, c, d
for k, v in pairs(target) do
if type(v) == 'table' then
performEasingOnSubject(subject[k], v, initial[k], clock, duration, easing)
else
t, b, c, d = clock, initial[k], v - initial[k], duration
subject[k] = easing(t, b, c, d)
end
end
end
local function performEasing(table, initial, target, clock, duration, easing)
if type(target) == "table" then
local t, b, c, d
for k, v in pairs(target) do
if type(v) == 'table' then
table[k] = {}
performEasing(table[k], initial[k], v, clock, duration, easing)
else
t, b, c, d = clock, initial[k], v - initial[k], duration
table[k] = easing(t, b, c, d)
end
end
return table
else
local t, b, c, d = clock, initial, target - initial, duration
return easing(t, b, c, d)
end
end
-- Public interface
local Tween = {}
function Tween:set(clock)
assert(type(clock) == 'number', "clock must be a positive number or 0")
if self.subject and self.initial == 0 then
self.initial = copyTables({}, self.target, self.subject)
end
self.clock = clock
if self.clock <= 0 then
self.clock = 0
if self.subject then
copyTables(self.subject, self.initial)
end
elseif self.clock >= self.duration then -- the tween has expired
self.clock = self.duration
if self.subject then
copyTables(self.subject, self.target)
end
else
if self.subject then
performEasingOnSubject(self.subject, self.target, self.initial, self.clock, self.duration, self.easing)
else
local pos = {}
return performEasing(pos, self.initial, self.target, self.clock, self.duration, self.easing)
end
end
return self.clock >= self.duration
end
function Tween:update(dt)
assert(type(dt) == 'number', "dt must be a number")
return self:set(self.clock + dt)
end
function Tween:reset()
return self:set(0)
end
function tween.new(args)
args = args or {}
args.initial = args.initial or 0
args.subject = args.subject or nil
args.target = args.target or nil
args.duration = args.duration or 0
args.easing = args.easing or nil
args.easing = getEasingFunction(args.easing)
checkNewParams(args.initial, args.duration, args.subject, args.target, args.easing)
local ret = gobject {}
ret.clock = 0
gtable.crush(ret, args, true)
gtable.crush(ret, Tween, true)
return ret
end
return tween

View File

@ -0,0 +1,103 @@
local gfs = require("gears.filesystem")
local gears = require("gears")
local theme_path = gfs.get_configuration_dir() .. "/theme/"
local icon_cache = {}
local helpers = require("helpers")
local t = helpers.readJson(gears.filesystem.get_cache_dir() .. "json/settings.json").iconTheme
local custom = {
{
name = "clearpad",
to = "terminal"
},
{
name = "ncmpcpppad",
to = "deepin-music-player"
},
}
local function hasValue(str)
local f = false
local ind = 0
for i, j in ipairs(custom) do
if j.name == str then
f = true
ind = i
break
end
end
return f, ind
end
local function Get_icon(client, program_string, class_string)
client = client or nil
program_string = program_string or nil
class_string = class_string or nil
if (client or program_string or class_string) then
local clientName
local isCustom, pos = hasValue(class_string)
if isCustom == true then
clientName = custom[pos].to .. ".svg"
elseif client then
if client.class then
clientName = string.lower(client.class:gsub(" ", "")) .. ".svg"
elseif client.name then
clientName = string.lower(client.name:gsub(" ", "")) .. ".svg"
else
if client.icon then
return client.icon
else
return t .. "/apps/default-application.svg"
end
end
else
if program_string then
clientName = program_string .. ".svg"
else
clientName = class_string .. ".svg"
end
end
for index, icon in ipairs(icon_cache) do
if icon:match(clientName) then
return icon
end
end
local iconDir = t .. "/apps/"
local ioStream = io.open(iconDir .. clientName, "r")
if ioStream ~= nil then
icon_cache[#icon_cache + 1] = iconDir .. clientName
return iconDir .. clientName
else
clientName = clientName:gsub("^%l", string.upper)
iconDir = t .. "/apps//"
ioStream = io.open(iconDir .. clientName, "r")
if ioStream ~= nil then
icon_cache[#icon_cache + 1] = iconDir .. clientName
return iconDir .. clientName
elseif not class_string then
return t .. "/apps/default-application.svg"
else
clientName = class_string .. ".svg"
iconDir = t .. "/apps/"
ioStream = io.open(iconDir .. clientName, "r")
if ioStream ~= nil then
icon_cache[#icon_cache + 1] = iconDir .. clientName
return iconDir .. clientName
else
return t .. "/apps/default-application.svg"
end
end
end
end
if client then
return t .. "/apps/default-application.svg"
end
end
return Get_icon

View File

@ -0,0 +1,344 @@
local inspect = {
_VERSION = 'inspect.lua 3.1.0',
_URL = 'http://github.com/kikito/inspect.lua',
_DESCRIPTION = 'human-readable representations of tables',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2013 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
local tostring = tostring
inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end })
inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end })
local function rawpairs(t)
return next, t, nil
end
-- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string
local function smartQuote(str)
if str:match('"') and not str:match("'") then
return "'" .. str .. "'"
end
return '"' .. str:gsub('"', '\\"') .. '"'
end
-- \a => '\\a', \0 => nil
local shortControlCharEscapes = {
["\a"] = "\\a",
["\b"] = "\\b",
["\f"] = "\\f",
["\n"] = "\\n",
["\r"] = "\\r",
["\t"] = "\\t",
["\v"] = "\\v",
["\127"] = "\\127",
}
local longControlCharEscapes = { ["\127"] = "\127" } -- \a => nil, \0 => \000, 31 => \031
for i = 0, 31 do
local ch = string.char(i)
if not shortControlCharEscapes[ch] then
shortControlCharEscapes[ch] = "\\" .. i
longControlCharEscapes[ch] = string.format("\\%03d", i)
end
end
--longControlCharEscapes["\127"]="\\127"
local function escape(str)
return (str:gsub("\\", "\\\\")
:gsub("(%c)%f[0-9]", longControlCharEscapes)
:gsub("%c", shortControlCharEscapes))
end
local function isIdentifier(str)
return type(str) == 'string' and str:match("^[_%a][_%a%d]*$")
end
local function isSequenceKey(k, sequenceLength)
return type(k) == 'number'
and 1 <= k
and k <= sequenceLength
and math.floor(k) == k
end
local defaultTypeOrders = {
['number'] = 1,
['boolean'] = 2,
['string'] = 3,
['table'] = 4,
['function'] = 5,
['userdata'] = 6,
['thread'] = 7
}
local function sortKeys(a, b)
local ta, tb = type(a), type(b)
-- strings and numbers are sorted numerically/alphabetically
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
-- Two default types are compared according to the defaultTypeOrders table
if dta and dtb then
return defaultTypeOrders[ta] < defaultTypeOrders[tb]
elseif dta then
return true -- default types before custom ones
elseif dtb then
return false -- custom types after default ones
end
-- custom types are sorted out alphabetically
return ta < tb
end
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
-- tables aren't pure sequences. So we implement our own # operator.
local function getSequenceLength(t)
local len = 1
local v = rawget(t, len)
while v ~= nil do
len = len + 1
v = rawget(t, len)
end
return len - 1
end
local function getNonSequentialKeys(t)
local keys, keysLength = {}, 0
local sequenceLength = getSequenceLength(t)
for k, _ in rawpairs(t) do
if not isSequenceKey(k, sequenceLength) then
keysLength = keysLength + 1
keys[keysLength] = k
end
end
table.sort(keys, sortKeys)
return keys, keysLength, sequenceLength
end
local function countTableAppearances(t, tableAppearances)
tableAppearances = tableAppearances or {}
if type(t) == 'table' then
if not tableAppearances[t] then
tableAppearances[t] = 1
for k, v in rawpairs(t) do
countTableAppearances(k, tableAppearances)
countTableAppearances(v, tableAppearances)
end
countTableAppearances(getmetatable(t), tableAppearances)
else
tableAppearances[t] = tableAppearances[t] + 1
end
end
return tableAppearances
end
local copySequence = function(s)
local copy, len = {}, #s
for i = 1, len do copy[i] = s[i] end
return copy, len
end
local function makePath(path, ...)
local keys = { ... }
local newPath, len = copySequence(path)
for i = 1, #keys do
newPath[len + i] = keys[i]
end
return newPath
end
local function processRecursive(process, item, path, visited)
if item == nil then return nil end
if visited[item] then return visited[item] end
local processed = process(item, path)
if type(processed) == 'table' then
local processedCopy = {}
visited[item] = processedCopy
local processedKey
for k, v in rawpairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end
end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field
setmetatable(processedCopy, mt)
processed = processedCopy
end
return processed
end
-------------------------------------------------------------------
local Inspector = {}
local Inspector_mt = { __index = Inspector }
function Inspector:puts(...)
local args = { ... }
local buffer = self.buffer
local len = #buffer
for i = 1, #args do
len = len + 1
buffer[len] = args[i]
end
end
function Inspector:down(f)
self.level = self.level + 1
f()
self.level = self.level - 1
end
function Inspector:tabify()
self:puts(self.newline, string.rep(self.indent, self.level))
end
function Inspector:alreadyVisited(v)
return self.ids[v] ~= nil
end
function Inspector:getId(v)
local id = self.ids[v]
if not id then
local tv = type(v)
id = (self.maxIds[tv] or 0) + 1
self.maxIds[tv] = id
self.ids[v] = id
end
return tostring(id)
end
function Inspector:putKey(k)
if isIdentifier(k) then return self:puts(k) end
self:puts("[")
self:putValue(k)
self:puts("]")
end
function Inspector:putTable(t)
if t == inspect.KEY or t == inspect.METATABLE then
self:puts(tostring(t))
elseif self:alreadyVisited(t) then
self:puts('<table ', self:getId(t), '>')
elseif self.level >= self.depth then
self:puts('{...}')
else
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t)
self:puts('{')
self:down(function()
local count = 0
for i = 1, sequenceLength do
if count > 0 then self:puts(',') end
self:puts(' ')
self:putValue(t[i])
count = count + 1
end
for i = 1, nonSequentialKeysLength do
local k = nonSequentialKeys[i]
if count > 0 then self:puts(',') end
self:tabify()
self:putKey(k)
self:puts(' = ')
self:putValue(t[k])
count = count + 1
end
if type(mt) == 'table' then
if count > 0 then self:puts(',') end
self:tabify()
self:puts('<metatable> = ')
self:putValue(mt)
end
end)
if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
self:tabify()
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
self:puts(' ')
end
self:puts('}')
end
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
tv == 'cdata' or tv == 'ctype' then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else
self:puts('<', tv, ' ', self:getId(v), '>')
end
end
-------------------------------------------------------------------
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
local newline = options.newline or '\n'
local indent = options.indent or ' '
local process = options.process
if process then
root = processRecursive(process, root, {}, {})
end
local inspector = setmetatable({
depth = depth,
level = 0,
buffer = {},
ids = {},
maxIds = {},
newline = newline,
indent = indent,
tableAppearances = countTableAppearances(root)
}, Inspector_mt)
inspector:putValue(root)
return table.concat(inspector.buffer)
end
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
return inspect

View File

@ -0,0 +1,383 @@
--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
["\\"] = "\\",
["\""] = "\"",
["\b"] = "b",
["\f"] = "f",
["\n"] = "n",
["\r"] = "r",
["\t"] = "t",
}
local escape_char_map_inv = { ["/"] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
["nil"] = encode_nil,
["table"] = encode_table,
["string"] = encode_string,
["number"] = encode_number,
["boolean"] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return (encode(val))
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[select(i, ...)] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
["true"] = true,
["false"] = false,
["null"] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error(string.format("%s at line %d col %d", msg, line_count, col_count))
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error(string.format("invalid unicode codepoint '%x'", n))
end
local function parse_unicode_escape(s)
local n1 = tonumber(s:sub(1, 4), 16)
local n2 = tonumber(s:sub(7, 10), 16)
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
['"'] = parse_string,
["0"] = parse_number,
["1"] = parse_number,
["2"] = parse_number,
["3"] = parse_number,
["4"] = parse_number,
["5"] = parse_number,
["6"] = parse_number,
["7"] = parse_number,
["8"] = parse_number,
["9"] = parse_number,
["-"] = parse_number,
["t"] = parse_literal,
["f"] = parse_literal,
["n"] = parse_literal,
["["] = parse_array,
["{"] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json

View File

@ -0,0 +1,342 @@
local awful = require("awful")
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local wibox = require("wibox")
local beautiful = require("beautiful")
local helpers = require("helpers")
local dpi = beautiful.xresources.apply_dpi
local setmetatable = setmetatable
local ipairs = ipairs
local capi = { awesome = awesome, mouse = mouse, tag = tag }
local menu = { mt = {} }
function menu:set_pos(args)
args = args or {}
local coords = args.coords
local wibox = args.wibox
local widget = args.widget
local offset = args.offset or { x = 0, y = 0 }
if offset.x == nil then
offset.x = 0
end
if offset.y == nil then
offset.y = 0
end
local screen_workarea = awful.screen.focused().workarea
local screen_w = screen_workarea.x + screen_workarea.width
local screen_h = screen_workarea.y + screen_workarea.height
if not coords and wibox and widget then
coords = helpers.get_widget_geometry(wibox, widget)
else
coords = args.coords or capi.mouse.coords()
end
if coords.x + self.width > screen_w then
if self.parent_menu ~= nil then
self.x = coords.x - (self.width * 2) - offset.x
else
self.x = coords.x - self.width + offset.x
end
else
self.x = coords.x + offset.x
end
if coords.y + self.height > screen_h then
self.y = screen_h - self.height + offset.y
else
self.y = coords.y + offset.y
end
end
function menu:hide_parents_menus()
if self.parent_menu ~= nil then
self.parent_menu:hide(true)
end
end
function menu:hide_children_menus()
if self.widget then
for _, button in ipairs(self.widget.children) do
if button.sub_menu ~= nil then
button.sub_menu:hide()
end
end
end
end
function menu:hide(hide_parents)
if self.visible == false then
return
end
-- Hide self
self.visible = false
-- Hides all child menus
self:hide_children_menus()
if hide_parents == true then
self:hide_parents_menus()
end
end
function menu:show(args)
if self.visible == true then
return
end
self.can_hide = false
gtimer({
timeout = 0.1,
autostart = true,
call_now = false,
single_shot = true,
callback = function()
self.can_hide = true
end,
})
-- Hide sub menus belonging to the menu of self
if self.parent_menu ~= nil then
for _, button in ipairs(self.parent_menu.widget.children) do
if button.sub_menu ~= nil and button.sub_menu ~= self then
button.sub_menu:hide()
end
end
end
self:set_pos(args)
self.visible = true
capi.awesome.emit_signal("menu::toggled_on", self)
end
function menu:toggle(args)
if self.visible == true then
self:hide()
else
self:show(args)
end
end
function menu:add(widget)
if widget.sub_menu then
widget.sub_menu.parent_menu = self
end
widget.menu = self
self.widget:add(widget)
end
function menu:remove(widget)
self.widget:remove(widget)
end
function menu:reset()
self.widget:reset()
end
function menu.menu(widgets, width)
local widget = awful.popup({
x = 32500,
type = "menu",
visible = false,
ontop = true,
minimum_width = width or dpi(300),
maximum_width = width or dpi(300),
shape = helpers.rrect(9),
bg = beautiful.main_menu_bg,
widget = wibox.layout.fixed.vertical,
})
gtable.crush(widget, menu, true)
awful.mouse.append_client_mousebinding(awful.button({ "Any" }, 1, function(c)
if widget.can_hide == true then
widget:hide(true)
end
end))
awful.mouse.append_client_mousebinding(awful.button({ "Any" }, 3, function(c)
if widget.can_hide == true then
widget:hide(true)
end
end))
awful.mouse.append_global_mousebinding(awful.button({ "Any" }, 1, function(c)
if widget.can_hide == true then
widget:hide(true)
end
end))
awful.mouse.append_global_mousebinding(awful.button({ "Any" }, 3, function(c)
if widget.can_hide == true then
widget:hide(true)
end
end))
capi.tag.connect_signal("property::selected", function(t)
widget:hide(true)
end)
capi.awesome.connect_signal("menu::toggled_on", function(menu)
if menu ~= widget and menu.parent_menu == nil then
widget:hide(true)
end
end)
for _, menu_widget in ipairs(widgets) do
widget:add(menu_widget)
end
return widget
end
function menu.sub_menu_button(args)
args = args or {}
args.icon = args.icon or nil
args.icon_size = args.icon_size or 16
args.text = args.text or ""
args.text_size = args.text_size or 12
args.sub_menu = args.sub_menu or nil
local icon = args.icon ~= nil
and wibox.widget {
font = args.icon.font .. " " .. args.icon_size,
markup = helpers.colorizeText(args.icon.icon, helpers.randomColor()),
widget = wibox.widget.textbox,
halign = "start",
forced_width = 40,
} or nil
local widget = wibox.widget {
{
{
layout = wibox.layout.align.horizontal,
forced_width = dpi(270),
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(10),
icon,
{
font = beautiful.sans .. " " .. args.text_size,
markup = args.text,
widget = wibox.widget.textbox,
halign = "start"
},
},
nil,
{
font = beautiful.icon .. " " .. "18",
markup = "󰅂",
widget = wibox.widget.textbox,
halign = "start"
},
},
widget = wibox.container.margin,
margins = 10
},
bg = beautiful.bg,
forced_height = 48,
shape = helpers.rrect(9),
widget = wibox.container.background,
}
widget:connect_signal("mouse::enter", function(self)
local coords = helpers.get_widget_geometry(self.menu, self)
coords.x = coords.x + self.menu.x + self.menu.width
coords.y = coords.y + self.menu.y
args.sub_menu:show({ coords = coords, offset = { x = -5 } })
end)
widget.sub_menu = args.sub_menu
return widget
end
function menu.button(args)
args = args or {}
args.icon = args.icon or nil
args.icon_size = args.icon_size or 16
args.image = args.image
args.text = args.text or ""
args.text_size = args.text_size or 12
args.on_press = args.on_press or nil
local icon = nil
if args.icon ~= nil then
icon = wibox.widget {
font = args.icon.font .. " " .. args.icon_size,
markup = helpers.colorizeText(args.icon.icon, helpers.randomColor()),
widget = wibox.widget.textbox,
halign = "start"
}
elseif args.image ~= nil then
icon = wibox.widget({
widget = wibox.widget.imagebox,
image = args.image,
})
end
local text_widget = wibox.widget {
font = beautiful.sans .. " " .. args.text_size,
markup = args.text,
widget = wibox.widget.textbox,
halign = "start"
}
local widget = wibox.widget {
{
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(15),
icon,
text_widget,
},
widget = wibox.container.margin,
margins = 10
},
bg = beautiful.bg,
forced_height = 48,
shape = helpers.rrect(9),
buttons = {
awful.button({}, 1, function()
args.on_press(menu, text_widget)
menu:hide(true)
end)
},
widget = wibox.container.background,
}
widget:connect_signal("mouse::enter", function(self)
if self.menu.widget then self.menu:hide_children_menus() end
end)
return widget
end
function menu.separator()
return wibox.widget({
widget = wibox.container.margin,
top = 10,
bottom = 10,
left = 40,
right = 40,
{
widget = wibox.widget.separator,
forced_height = dpi(2),
orientation = "horizontal",
thickness = dpi(1),
color = beautiful.fg .. "29",
},
})
end
function menu.mt:__call(...)
return menu.menu(...)
end
return setmetatable(menu, menu.mt)

View File

@ -0,0 +1,534 @@
-------------------------------------------
-- @author https://github.com/Kasper24
-- @copyright 2021-2022 Kasper24
-------------------------------------------
---------------------------------------------------------------------------
-- 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
-- @supermodule wibox.layout.fixed
---------------------------------------------------------------------------
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 beautiful = require('beautiful')
local dpi = beautiful.xresources.apply_dpi
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 ipairs(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_max = math.max(used_max, h)
used_in_dir = used_in_dir + w
end
end
local spacing = self._private.spacing * (num_widgets - 1)
used_in_dir = used_in_dir + spacing
local need_scrollbar = scrollbar_enabled and used_in_dir > avail_in_dir
-- Even if `used_max == orig_(width|height)` already, `base.fit_widget`
-- will clamp return values, so we can "overextend" here.
if need_scrollbar 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_max = math.max(used_max, h)
used_in_dir = used_in_dir + w
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.scroll_factor
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.scroll_factor
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 ipairs(widgets) do
local content_x, content_y
local content_w, content_h = base.fit_widget(self, context, w,
need_scrollbar and width - self._private.scrollbar_spacing or 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(need_scrollbar and content_w - self._private.scrollbar_spacing or 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.
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.
--
-- The amount of units scrolled is affected by `step`.
--
-- @method overflow:scroll
-- @tparam number amount The amount to scroll by.
-- @emits property::overflow::scroll_factor
-- @emitstparam property::overflow::scroll_factor number scroll_factor The new
-- scroll factor.
-- @emits widget::layout_changed
-- @emits widget::redraw_needed
function overflow:scroll(amount)
if amount == 0 then
return
end
local interval = self._private.used_in_dir
local delta = self._private.step / interval
local factor = self._private.scroll_factor + (delta * amount)
self:set_scroll_factor(factor)
end
--- The scroll factor.
--
-- The scroll factor represents how far the layout's content is currently
-- scrolled. It is represented as a fraction from `0` to `1`, where `0` is the
-- start of the content and `1` is the end.
--
-- @property scroll_factor
-- @tparam number scroll_factor The scroll factor.
-- @propemits true false
function overflow:set_scroll_factor(factor)
local current = self._private.scroll_factor
local interval = self._private.used_in_dir - self._private.avail_in_dir
if current == factor -- the content takes less space than what is available, i.e. everything
-- is already visible
or interval <= 0 -- the scroll factor is out of range
or (current <= 0 and factor < 0) or (current >= 1 and factor > 1) then
return
end
self._private.scroll_factor = math.min(1, math.max(factor, 0))
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scroll_factor", factor)
end
function overflow:get_scroll_factor()
return self._private.scroll_factor
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
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 `"right"`/`"bottom"`.
--
-- @DOC_wibox_layout_overflow_scrollbar_position_EXAMPLE@
--
-- @property scrollbar_position
-- @tparam string scrollbar_position The scrollbar position.
-- @propemits true false
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
function overflow:get_scrollbar_position()
return self._private.scrollbar_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
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
function overflow:get_scrollbar_enabled()
return self._private.scrollbar_enabled
end
-- Wraps a callback function for `mousegrabber` that is capable of
-- updating the scroll factor.
local function build_grabber(container, initial_x, initial_y, geo)
local is_y = container._private.dir == "y"
local bar_interval = container._private.avail_in_dir - container._private.bar_length
local start_pos = container._private.scroll_factor * bar_interval
local start = is_y and initial_y or initial_x
-- Calculate a matrix transforming from screen coordinates into widget
-- coordinates.
-- This is required for mouse movement to work when the widget has been
-- transformed by something like `wibox.container.rotate`.
local matrix_from_device = geo.hierarchy:get_matrix_from_device()
local wgeo = geo.drawable.drawable:geometry()
local matrix = matrix_from_device:translate( -wgeo.x, -wgeo.y)
return function(mouse)
if not mouse.buttons[1] then
return false
end
local x, y = matrix:transform_point(mouse.x, mouse.y)
local pos = is_y and y or x
container:set_scroll_factor((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(_, x, y, button_id, _, geo)
if button_id ~= 1 then
return
end
mousegrabber.run(build_grabber(container, x, y, geo), "fleur")
end)
end
--- The scrollbar widget.
-- This widget is rendered as the scrollbar element.
--
-- The default is `wibox.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
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
function overflow:get_scrollbar_widget()
return self._private.scrollbar_widget
end
function overflow:set_scrollbar_spacing(spacing)
self._private.scrollbar_spacing = spacing
self:emit_signal("widget::layout_changed")
self:emit_signal("property::scrollbar_spacing", spacing)
end
function overflow:get_scrollbar_spacing()
return self._private.scrollbar_spacing
end
local function new(dir, ...)
local ret = fixed[dir](...)
gtable.crush(ret, overflow, true)
ret.widget_name = gobject.modulename(2)
-- Tell the widget system to prevent clicks outside the layout's extends
-- to register with child widgets, even if they actually extend that far.
-- This prevents triggering button presses on hidden/clipped widgets.
ret.clip_child_extends = true
-- Manually set the scroll factor here. We don't know the bounding size yet.
ret._private.scroll_factor = 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"
ret._private.scrollbar_spacing = dpi(15)
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
self:scroll( -1)
elseif button == 5 then
self:scroll(1)
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.overflow.horizontal
function overflow.vertical(...)
return new("vertical", ...)
end
return setmetatable(overflow, overflow.mt)

View File

@ -0,0 +1,46 @@
local awful = require("awful")
local gtimer = require("gears.timer")
local beautiful = require("beautiful")
local naughty = require("naughty")
-- Use CLI backend as default as it is supported on most if not all systems
local backend_config = beautiful.playerctl_backend or "playerctl_cli"
local backends = {
playerctl_cli = require(... .. ".playerctl_cli"),
playerctl_lib = require(... .. ".playerctl_lib"),
}
local backend = nil
local function enable_wrapper(args)
local open = naughty.action { name = "Open" }
open:connect_signal("invoked", function()
awful.spawn("xdg-open https://blingcorp.github.io/bling/#/signals/pctl")
end)
gtimer.delayed_call(function()
naughty.notify({
title = "Bling Error",
text = "Global signals are deprecated! Please take a look at the playerctl documentation.",
app_name = "Bling Error",
app_icon = "system-error",
actions = { open }
})
end)
backend_config = (args and args.backend) or backend_config
backend = backends[backend_config](args)
return backend
end
local function disable_wrapper()
backend:disable()
end
return {
lib = backends.playerctl_lib,
cli = backends.playerctl_cli,
enable = enable_wrapper,
disable = disable_wrapper
}

View File

@ -0,0 +1,355 @@
-- Playerctl signals
--
-- Provides:
-- metadata
-- title (string)
-- artist (string)
-- album_path (string)
-- album (string)
-- player_name (string)
-- position
-- interval_sec (number)
-- length_sec (number)
-- playback_status
-- playing (boolean)
-- volume
-- volume (number)
-- loop_status
-- loop_status (string)
-- shuffle
-- shuffle (bool)
-- no_players
-- (No parameters)
local awful = require("awful")
local gobject = require("gears.object")
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local gstring = require("gears.string")
local beautiful = require("beautiful")
local setmetatable = setmetatable
local tonumber = tonumber
local ipairs = ipairs
local type = type
local capi = { awesome = awesome }
local playerctl = { mt = {} }
local function save_image_async_curl(url, filepath, callback)
awful.spawn.with_line_callback(string.format("curl -L -s %s -o %s", url, filepath),
{
exit = callback
})
end
function playerctl:disable()
self._private.metadata_timer:stop()
self._private.metadata_timer = nil
awful.spawn.with_shell("killall playerctl")
end
function playerctl:pause(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " pause")
else
awful.spawn.with_shell(self._private.cmd .. "pause")
end
end
function playerctl:play(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " play")
else
awful.spawn.with_shell(self._private.cmd .. "play")
end
end
function playerctl:stop(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " stop")
else
awful.spawn.with_shell(self._private.cmd .. "stop")
end
end
function playerctl:play_pause(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " play-pause")
else
awful.spawn.with_shell(self._private.cmd .. "play-pause")
end
end
function playerctl:previous(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " previous")
else
awful.spawn.with_shell(self._private.cmd .. "previous")
end
end
function playerctl:next(player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " next")
else
awful.spawn.with_shell(self._private.cmd .. "next")
end
end
function playerctl:set_loop_status(loop_status, player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " loop " .. loop_status)
else
awful.spawn.with_shell(self._private.cmd .. "loop " .. loop_status)
end
end
function playerctl:cycle_loop_status(player)
local function set_loop_status(loop_status)
if loop_status == "None" then
self:set_loop_status("Track")
elseif loop_status == "Track" then
self:set_loop_status("Playlist")
elseif loop_status == "Playlist" then
self:set_loop_status("None")
end
end
if player ~= nil then
awful.spawn.easy_async_with_shell("playerctl --player=" .. player .. " loop", function(stdout)
set_loop_status(stdout)
end)
else
set_loop_status(self._private.loop_status)
end
end
function playerctl:set_position(position, player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " position " .. position)
else
awful.spawn.with_shell(self._private.cmd .. "position " .. position)
end
end
function playerctl:set_shuffle(shuffle, player)
shuffle = shuffle and "on" or "off"
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " shuffle " .. shuffle)
else
awful.spawn.with_shell(self._private.cmd .. "shuffle " .. shuffle)
end
end
function playerctl:cycle_shuffle(player)
if player ~= nil then
awful.spawn.easy_async_with_shell("playerctl --player=" .. player .. " shuffle", function(stdout)
local shuffle = stdout == "on" and true or false
self:set_shuffle(not self._private.shuffle)
end)
else
self:set_shuffle(not self._private.shuffle)
end
end
function playerctl:set_volume(volume, player)
if player ~= nil then
awful.spawn.with_shell("playerctl --player=" .. player .. " volume " .. volume)
else
awful.spawn.with_shell(self._private.cmd .. "volume " .. volume)
end
end
local function emit_player_metadata(self)
local metadata_cmd = self._private.cmd ..
"metadata --format 'title_{{title}}artist_{{artist}}art_url_{{mpris:artUrl}}player_name_{{playerName}}album_{{album}}' -F"
awful.spawn.with_line_callback(metadata_cmd, {
stdout = function(line)
local title = gstring.xml_escape(line:match('title_(.*)artist_')) or ""
local artist = gstring.xml_escape(line:match('artist_(.*)art_url_')) or ""
local art_url = line:match('art_url_(.*)player_name_') or ""
local player_name = line:match('player_name_(.*)album_') or ""
local album = gstring.xml_escape(line:match('album_(.*)')) or ""
art_url = art_url:gsub('%\n', '')
if player_name == "spotify" then
art_url = art_url:gsub("open.spotify.com", "i.scdn.co")
end
if self._private.metadata_timer
and self._private.metadata_timer.started
then
self._private.metadata_timer:stop()
end
self._private.metadata_timer = gtimer {
timeout = self.debounce_delay,
autostart = true,
single_shot = true,
callback = function()
if title and title ~= "" then
if art_url ~= "" then
local art_path = os.tmpname()
save_image_async_curl(art_url, art_path, function()
self:emit_signal("metadata", title, artist, art_path, album, player_name)
capi.awesome.emit_signal("bling::playerctl::title_artist_album", title, artist, art_path)
end)
else
self:emit_signal("metadata", title, artist, "", album, player_name)
capi.awesome.emit_signal("bling::playerctl::title_artist_album", title, artist, "")
end
else
self:emit_signal("no_players")
capi.awesome.emit_signal("bling::playerctl::no_players")
end
end
}
collectgarbage("collect")
end,
})
end
local function emit_player_position(self)
local position_cmd = self._private.cmd .. "position"
local length_cmd = self._private.cmd .. "metadata mpris:length"
awful.widget.watch(position_cmd, self.interval, function(_, interval)
awful.spawn.easy_async_with_shell(length_cmd, function(length)
local length_sec = tonumber(length) -- in microseconds
local interval_sec = tonumber(interval) -- in seconds
if length_sec and interval_sec then
if interval_sec >= 0 and length_sec > 0 then
self:emit_signal("position", interval_sec, length_sec / 1000000)
capi.awesome.emit_signal("bling::playerctl::position", interval_sec, length_sec / 1000000)
end
end
end)
collectgarbage("collect")
end)
end
local function emit_player_playback_status(self)
local status_cmd = self._private.cmd .. "status -F"
awful.spawn.with_line_callback(status_cmd, {
stdout = function(line)
if line:find("Playing") then
self:emit_signal("playback_status", true)
capi.awesome.emit_signal("bling::playerctl::status", true)
else
self:emit_signal("playback_status", false)
capi.awesome.emit_signal("bling::playerctl::status", false)
end
end,
})
end
local function emit_player_volume(self)
local volume_cmd = self._private.cmd .. "volume -F"
awful.spawn.with_line_callback(volume_cmd, {
stdout = function(line)
self:emit_signal("volume", tonumber(line))
end,
})
end
local function emit_player_loop_status(self)
local loop_status_cmd = self._private.cmd .. "loop -F"
awful.spawn.with_line_callback(loop_status_cmd, {
stdout = function(line)
self._private.loop_status = line
self:emit_signal("loop_status", line:lower())
end,
})
end
local function emit_player_shuffle(self)
local shuffle_cmd = self._private.cmd .. "shuffle -F"
awful.spawn.with_line_callback(shuffle_cmd, {
stdout = function(line)
if line:find("On") then
self._private.shuffle = true
self:emit_signal("shuffle", true)
else
self._private.shuffle = false
self:emit_signal("shuffle", false)
end
end,
})
end
local function parse_args(self, args)
if args.player then
self._private.cmd = self._private.cmd .. "--player="
if type(args.player) == "string" then
self._private.cmd = self._private.cmd .. args.player .. " "
elseif type(args.player) == "table" then
for index, player in ipairs(args.player) do
self._private.cmd = self._private.cmd .. player
if index < #args.player then
self._private.cmd = self._private.cmd .. ","
else
self._private.cmd = self._private.cmd .. " "
end
end
end
end
if args.ignore then
self._private.cmd = self._private.cmd .. "--ignore-player="
if type(args.ignore) == "string" then
self._private.cmd = self._private.cmd .. args.ignore .. " "
elseif type(args.ignore) == "table" then
for index, player in ipairs(args.ignore) do
self._private.cmd = self._private.cmd .. player
if index < #args.ignore then
self._private.cmd = self._private.cmd .. ","
else
self._private.cmd = self._private.cmd .. " "
end
end
end
end
end
local function new(args)
args = args or {}
local ret = gobject {}
gtable.crush(ret, playerctl, true)
ret.interval = args.interval or beautiful.playerctl_position_update_interval or 1
ret.debounce_delay = args.debounce_delay or beautiful.playerctl_debounce_delay or 0.35
ret._private = {}
ret._private.metadata_timer = nil
ret._private.cmd = "playerctl "
parse_args(ret, args)
emit_player_metadata(ret)
emit_player_position(ret)
emit_player_playback_status(ret)
emit_player_volume(ret)
emit_player_loop_status(ret)
emit_player_shuffle(ret)
return ret
end
function playerctl.mt:__call(...)
return new(...)
end
-- On startup instead of on playerctl object init to make it
-- possible to have more than one of these running
awful.spawn.with_shell("killall playerctl")
return setmetatable(playerctl, playerctl.mt)

View File

@ -0,0 +1,569 @@
-- Playerctl signals
--
-- Provides:
-- metadata
-- title (string)
-- artist (string)
-- album_path (string)
-- album (string)
-- new (bool)
-- player_name (string)
-- position
-- interval_sec (number)
-- length_sec (number)
-- player_name (string)
-- playback_status
-- playing (boolean)
-- player_name (string)
-- seeked
-- position (number)
-- player_name (string)
-- volume
-- volume (number)
-- player_name (string)
-- loop_status
-- loop_status (string)
-- player_name (string)
-- shuffle
-- shuffle (boolean)
-- player_name (string)
-- exit
-- player_name (string)
-- no_players
-- (No parameters)
local awful = require("awful")
local gobject = require("gears.object")
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local gstring = require("gears.string")
local beautiful = require("beautiful")
local setmetatable = setmetatable
local ipairs = ipairs
local pairs = pairs
local type = type
local capi = { awesome = awesome }
local playerctl = { mt = {} }
local function save_image_async_curl(url, filepath, callback)
awful.spawn.with_line_callback(string.format("curl -L -s %s -o %s", url, filepath),
{
exit = callback
})
end
function playerctl:disable()
-- Restore default settings
self.ignore = {}
self.priority = {}
self.update_on_activity = true
self.interval = 1
self.debounce_delay = 0.35
-- Reset timers
self._private.manager = nil
self._private.metadata_timer:stop()
self._private.metadata_timer = nil
self._private.position_timer:stop()
self._private.position_timer = nil
-- Reset default values
self._private.last_position = -1
self._private.last_length = -1
self._private.last_player = nil
self._private.last_title = ""
self._private.last_artist = ""
self._private.last_artUrl = ""
end
function playerctl:pause(player)
player = player or self._private.manager.players[1]
if player then
player:pause()
end
end
function playerctl:play(player)
player = player or self._private.manager.players[1]
if player then
player:play()
end
end
function playerctl:stop(player)
player = player or self._private.manager.players[1]
if player then
player:stop()
end
end
function playerctl:play_pause(player)
player = player or self._private.manager.players[1]
if player then
player:play_pause()
end
end
function playerctl:previous(player)
player = player or self._private.manager.players[1]
if player then
player:previous()
end
end
function playerctl:next(player)
player = player or self._private.manager.players[1]
if player then
player:next()
end
end
function playerctl:set_loop_status(loop_status, player)
player = player or self._private.manager.players[1]
if player then
player:set_loop_status(loop_status)
end
end
function playerctl:cycle_loop_status(player)
player = player or self._private.manager.players[1]
if player then
if player.loop_status == "NONE" then
player:set_loop_status("TRACK")
elseif player.loop_status == "TRACK" then
player:set_loop_status("PLAYLIST")
elseif player.loop_status == "PLAYLIST" then
player:set_loop_status("NONE")
end
end
end
function playerctl:set_position(position, player)
player = player or self._private.manager.players[1]
if player then
player:set_position(position * 1000000)
end
end
function playerctl:set_shuffle(shuffle, player)
player = player or self._private.manager.players[1]
if player then
player:set_shuffle(shuffle)
end
end
function playerctl:cycle_shuffle(player)
player = player or self._private.manager.players[1]
if player then
player:set_shuffle(not player.shuffle)
end
end
function playerctl:set_volume(volume, player)
player = player or self._private.manager.players[1]
if player then
player:set_volume(volume)
end
end
function playerctl:get_manager()
return self._private.manager
end
function playerctl:get_active_player()
return self._private.manager.players[1]
end
function playerctl:get_player_of_name(name)
for _, player in ipairs(self._private.manager.players) do
if player.player_name == name then
return player
end
end
return nil
end
local function emit_metadata_signal(self, title, artist, artUrl, album, new, player_name)
title = gstring.xml_escape(title)
artist = gstring.xml_escape(artist)
album = gstring.xml_escape(album)
-- Spotify client doesn't report its art URL's correctly...
if player_name == "spotify" then
artUrl = artUrl:gsub("open.spotify.com", "i.scdn.co")
end
if artUrl ~= "" then
local art_path = os.tmpname()
save_image_async_curl(artUrl, art_path, function()
self:emit_signal("metadata", title, artist, art_path, album, new, player_name)
capi.awesome.emit_signal("bling::playerctl::title_artist_album", title, artist, art_path, player_name)
end)
else
capi.awesome.emit_signal("bling::playerctl::title_artist_album", title, artist, "", player_name)
self:emit_signal("metadata", title, artist, "", album, new, player_name)
end
end
local function metadata_cb(self, player, metadata)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
local data = metadata.value
local title = data["xesam:title"] or ""
local artist = data["xesam:artist"][1] or ""
for i = 2, #data["xesam:artist"] do
artist = artist .. ", " .. data["xesam:artist"][i]
end
local artUrl = data["mpris:artUrl"] or ""
local album = data["xesam:album"] or ""
if player == self._private.manager.players[1] then
self._private.active_player = player
-- Callback can be called even though values we care about haven't
-- changed, so check to see if they have
if
player ~= self._private.last_player
or title ~= self._private.last_title
or artist ~= self._private.last_artist
or artUrl ~= self._private.last_artUrl
then
if (title == "" and artist == "" and artUrl == "") then return end
if self._private.metadata_timer ~= nil and self._private.metadata_timer.started then
self._private.metadata_timer:stop()
end
self._private.metadata_timer = gtimer {
timeout = self.debounce_delay,
autostart = true,
single_shot = true,
callback = function()
emit_metadata_signal(self, title, artist, artUrl, album, true, player.player_name)
end
}
-- Re-sync with position timer when track changes
self._private.position_timer:again()
self._private.last_player = player
self._private.last_title = title
self._private.last_artist = artist
self._private.last_artUrl = artUrl
end
end
end
local function position_cb(self)
local player = self._private.manager.players[1]
if player then
local position = player:get_position() / 1000000
local length = (player.metadata.value["mpris:length"] or 0) / 1000000
if position ~= self._private.last_position or length ~= self._private.last_length then
capi.awesome.emit_signal("bling::playerctl::position", position, length, player.player_name)
self:emit_signal("position", position, length, player.player_name)
self._private.last_position = position
self._private.last_length = length
end
end
end
local function playback_status_cb(self, player, status)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
if player == self._private.manager.players[1] then
self._private.active_player = player
-- Reported as PLAYING, PAUSED, or STOPPED
if status == "PLAYING" then
self:emit_signal("playback_status", true, player.player_name)
capi.awesome.emit_signal("bling::playerctl::status", true, player.player_name)
else
self:emit_signal("playback_status", false, player.player_name)
capi.awesome.emit_signal("bling::playerctl::status", false, player.player_name)
end
end
end
local function seeked_cb(self, player, position)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
if player == self._private.manager.players[1] then
self._private.active_player = player
self:emit_signal("seeked", position / 1000000, player.player_name)
end
end
local function volume_cb(self, player, volume)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
if player == self._private.manager.players[1] then
self._private.active_player = player
self:emit_signal("volume", volume, player.player_name)
end
end
local function loop_status_cb(self, player, loop_status)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
if player == self._private.manager.players[1] then
self._private.active_player = player
self:emit_signal("loop_status", loop_status:lower(), player.player_name)
end
end
local function shuffle_cb(self, player, shuffle)
if self.update_on_activity then
self._private.manager:move_player_to_top(player)
end
if player == self._private.manager.players[1] then
self._private.active_player = player
self:emit_signal("shuffle", shuffle, player.player_name)
end
end
local function exit_cb(self, player)
if player == self._private.manager.players[1] then
self:emit_signal("exit", player.player_name)
end
end
-- Determine if player should be managed
local function name_is_selected(self, name)
if self.ignore[name.name] then
return false
end
if #self.priority > 0 then
for _, arg in pairs(self.priority) do
if arg == name.name or arg == "%any" then
return true
end
end
return false
end
return true
end
-- Create new player and connect it to callbacks
local function init_player(self, name)
if name_is_selected(self, name) then
local player = self._private.lgi_Playerctl.Player.new_from_name(name)
self._private.manager:manage_player(player)
player.on_metadata = function(player, metadata)
metadata_cb(self, player, metadata)
end
player.on_playback_status = function(player, playback_status)
playback_status_cb(self, player, playback_status)
end
player.on_seeked = function(player, position)
seeked_cb(self, player, position)
end
player.on_volume = function(player, volume)
volume_cb(self, player, volume)
end
player.on_loop_status = function(player, loop_status)
loop_status_cb(self, player, loop_status)
end
player.on_shuffle = function(player, shuffle_status)
shuffle_cb(self, player, shuffle_status)
end
player.on_exit = function(player, shuffle_status)
exit_cb(self, player)
end
-- Start position timer if its not already running
if not self._private.position_timer.started then
self._private.position_timer:again()
end
end
end
-- Determine if a player name comes before or after another according to the
-- priority order
local function player_compare_name(self, name_a, name_b)
local any_index = math.huge
local a_match_index = nil
local b_match_index = nil
if name_a == name_b then
return 0
end
for index, name in ipairs(self.priority) do
if name == "%any" then
any_index = (any_index == math.huge) and index or any_index
elseif name == name_a then
a_match_index = a_match_index or index
elseif name == name_b then
b_match_index = b_match_index or index
end
end
if not a_match_index and not b_match_index then
return 0
elseif not a_match_index then
return (b_match_index < any_index) and 1 or -1
elseif not b_match_index then
return (a_match_index < any_index) and -1 or 1
elseif a_match_index == b_match_index then
return 0
else
return (a_match_index < b_match_index) and -1 or 1
end
end
-- Sorting function used by manager if a priority order is specified
local function player_compare(self, a, b)
local player_a = self._private.lgi_Playerctl.Player(a)
local player_b = self._private.lgi_Playerctl.Player(b)
return player_compare_name(self, player_a.player_name, player_b.player_name)
end
local function get_current_player_info(self, player)
local title = player:get_title() or ""
local artist = player:get_artist() or ""
local artUrl = player:print_metadata_prop("mpris:artUrl") or ""
local album = player:get_album() or ""
emit_metadata_signal(self, title, artist, artUrl, album, false, player.player_name)
playback_status_cb(self, player, player.playback_status)
volume_cb(self, player, player.volume)
loop_status_cb(self, player, player.loop_status)
shuffle_cb(self, player, player.shuffle)
end
local function start_manager(self)
self._private.manager = self._private.lgi_Playerctl.PlayerManager()
if #self.priority > 0 then
self._private.manager:set_sort_func(function(a, b)
return player_compare(self, a, b)
end)
end
-- Timer to update track position at specified interval
self._private.position_timer = gtimer {
timeout = self.interval,
callback = function()
position_cb(self)
end,
}
-- Manage existing players on startup
for _, name in ipairs(self._private.manager.player_names) do
init_player(self, name)
end
if self._private.manager.players[1] then
get_current_player_info(self, self._private.manager.players[1])
end
local _self = self
-- Callback to manage new players
function self._private.manager:on_name_appeared(name)
init_player(_self, name)
end
function self._private.manager:on_player_appeared(player)
if player == self.players[1] then
_self._private.active_player = player
end
end
function self._private.manager:on_player_vanished(player)
if #self.players == 0 then
_self._private.metadata_timer:stop()
_self._private.position_timer:stop()
_self:emit_signal("no_players")
capi.awesome.emit_signal("bling::playerctl::no_players")
elseif player == _self._private.active_player then
_self._private.active_player = self.players[1]
get_current_player_info(_self, self.players[1])
end
end
end
local function parse_args(self, args)
self.ignore = {}
if type(args.ignore) == "string" then
self.ignore[args.ignore] = true
elseif type(args.ignore) == "table" then
for _, name in pairs(args.ignore) do
self.ignore[name] = true
end
end
self.priority = {}
if type(args.player) == "string" then
self.priority[1] = args.player
elseif type(args.player) == "table" then
self.priority = args.player
end
end
local function new(args)
args = args or {}
local ret = gobject {}
gtable.crush(ret, playerctl, true)
-- Grab settings from beautiful variables if not set explicitly
args.ignore = args.ignore or beautiful.playerctl_ignore
args.player = args.player or beautiful.playerctl_player
if args.update_on_activity ~= nil then
ret.update_on_activity = args.update_on_activity
else
ret.update_on_activity = beautiful.playerctl_update_on_activity ~= false
end
ret.interval = args.interval or beautiful.playerctl_position_update_interval or 1
ret.debounce_delay = args.debounce_delay or beautiful.playerctl_debounce_delay or 0.35
parse_args(ret, args)
ret._private = {}
-- Metadata callback for title, artist, and album art
ret._private.last_player = nil
ret._private.last_title = ""
ret._private.last_artist = ""
ret._private.last_artUrl = ""
-- Track position callback
ret._private.last_position = -1
ret._private.last_length = -1
-- Grab playerctl library
ret._private.lgi_Playerctl = require("lgi").Playerctl
ret._private.manager = nil
ret._private.metadata_timer = nil
ret._private.position_timer = nil
-- Ensure main event loop has started before starting player manager
gtimer.delayed_call(function()
start_manager(ret)
end)
return ret
end
function playerctl.mt:__call(...)
return new(...)
end
return setmetatable(playerctl, playerctl.mt)

View File

@ -0,0 +1,29 @@
local awful = require "awful"
local gears = require "gears"
local beautiful = require "beautiful"
awful.spawn.with_shell("bash ~/.config/awesome/main/autorun.sh")
require "setup":generate()
beautiful.init(gears.filesystem.get_configuration_dir() .. "theme/init.lua")
require "main"
require "awful.autofocus"
-- init widget
require "misc"
require "ui"
require "signal"
gears.timer {
timeout = 5,
autostart = true,
call_now = true,
callback = function()
collectgarbage "collect"
end,
}
collectgarbage("setpause", 110)
collectgarbage("setstepmul", 1000)

View File

@ -0,0 +1,38 @@
local json = require("mods.json")
local helpers = require("helpers")
local gfs = require("gears.filesystem")
local M = {}
M.defaultData = {
colorscheme = "cat",
gaps = 10,
iconTheme = "~/.local/share/icons/hicolor/",
openWeatherApi = "KEY_HERE",
showDesktopIcons = true,
pfp = "/home/" .. string.gsub(os.getenv('USER'), '^%l', string.lower) .. "/.config/awesome/theme/assets/pfp.png",
wallpaper = "colorful",
}
M.path = gfs.get_cache_dir() .. "json/settings.json"
function M:generate()
if not helpers.file_exists(self.path) then
local w = assert(io.open(self.path, "w"))
w:write(json.encode(self.defaultData, nil, { pretty = true, indent = " ", align_keys = false, array_newline = true }))
w:close()
M.settings = self.defaultData
else
local r = assert(io.open(self.path, "rb"))
local t = r:read("*all")
r:close()
local settings = json.decode(t)
M.settings = settings
end
if not helpers.file_exists(gfs.get_cache_dir() .. "lock/lock.jpg") then
os.execute("mkdir -p ~/.cache/awesome/lock")
end
end
return M

View File

@ -0,0 +1,20 @@
local awful = require('awful')
local gears = require('gears')
local naughty = require("naughty")
local function emit_airplane_status()
awful.spawn.easy_async_with_shell(
"bash -c \"rfkill list | sed -n 2p | awk '{print $3}'\" ", function(stdout)
local status = stdout:match("yes") -- boolean
awesome.emit_signal('signal::airplane', status)
end)
end
gears.timer {
timeout = 2,
call_now = true,
autostart = true,
callback = function()
emit_airplane_status()
end
}

View File

@ -0,0 +1,21 @@
local awful = require('awful')
local gears = require('gears')
local function emit_bluetooth_status()
awful.spawn.easy_async_with_shell(
"bash -c 'bluetoothctl show | grep -i powered:'", function(stdout)
local status = stdout:match("yes") -- boolean
awesome.emit_signal('signal::bluetooth', status)
end)
end
-- Refreshing
-------------
gears.timer {
timeout = 2,
call_now = true,
autostart = true,
callback = function()
emit_bluetooth_status()
end
}

View File

@ -0,0 +1,3 @@
require("signal.connection.wifi")
require("signal.connection.bluetooth")
require("signal.connection.airplane")

View File

@ -0,0 +1,23 @@
local awful = require('awful')
local gears = require('gears')
-- Network Fetching and Signal Emitting
---------------------------------------
local function emit_network_status()
awful.spawn.easy_async_with_shell(
"bash -c 'nmcli networking connectivity check'", function(stdout)
local status = not stdout:match("none") -- boolean
awesome.emit_signal('signal::network', status)
end)
end
-- Refreshing
-------------
gears.timer {
timeout = 2,
call_now = true,
autostart = true,
callback = function()
emit_network_status()
end
}

View File

@ -0,0 +1,3 @@
require("signal.system")
require("signal.connection")
require("signal.stats")

View File

@ -0,0 +1,20 @@
local awful = require('awful')
local gears = require('gears')
local function emit_cpu_status()
awful.spawn.easy_async_with_shell(
"bash -c \"roundvalue $(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage}')\""
,
function(stdout)
stdout = tonumber(stdout)
awesome.emit_signal('signal::cpu', stdout)
end)
end
gears.timer {
timeout = 60,
call_now = true,
autostart = true,
callback = function()
emit_cpu_status()
end
}

View File

@ -0,0 +1,21 @@
local awful = require('awful')
local gears = require('gears')
local function emit_disk_status()
awful.spawn.easy_async_with_shell(
"bash -c \"df --output=pcent / | sed '1d;s/^ //;s/%//'\""
,
function(stdout)
stdout = stdout:gsub("%s+", "")
stdout = tonumber(stdout)
awesome.emit_signal('signal::disk', stdout)
end)
end
gears.timer {
timeout = 600,
call_now = true,
autostart = true,
callback = function()
emit_disk_status()
end
}

View File

@ -0,0 +1,5 @@
require("signal.stats.weather")
require("signal.stats.uptime")
require("signal.stats.cpu")
require("signal.stats.disk")
require("signal.stats.memory")

View File

@ -0,0 +1,20 @@
local awful = require('awful')
local gears = require('gears')
local function emit_mem_status()
awful.spawn.easy_async_with_shell(
"bash -c \"roundvalue $(free | grep Mem | awk '{print $3/$2 * 100.0}')\""
,
function(stdout)
stdout = tonumber(stdout)
awesome.emit_signal('signal::memory', stdout)
end)
end
gears.timer {
timeout = 60,
call_now = true,
autostart = true,
callback = function()
emit_mem_status()
end
}

View File

@ -0,0 +1,20 @@
local awful = require('awful')
local gears = require('gears')
local function emit_uptime_status()
awful.spawn.easy_async_with_shell(
"bash -c \"uptime --pretty | sed 's/up\\s*//g' | sed 's/\\s*days/d/g' | sed 's/\\s*hours/h/g' | sed 's/\\s*minutes/m/g'\""
,
function(stdout)
stdout = stdout:gsub("%s+", "")
awesome.emit_signal('signal::uptime', stdout)
end)
end
gears.timer {
timeout = 60,
call_now = true,
autostart = true,
callback = function()
emit_uptime_status()
end
}

View File

@ -0,0 +1,107 @@
local awful = require("awful")
local gears = require("gears")
local filesystem = gears.filesystem
local json = require("mods.json")
local helpers = require("helpers")
local icon_dir = filesystem.get_configuration_dir() .. "theme/assets/weather/icons/"
local thumb_dir = filesystem.get_configuration_dir() .. "theme/assets/weather/images/"
local GET_FORECAST_CMD = [[bash -c "curl -s --show-error -X GET '%s'"]]
local icon_map = {
["01d"] = "weather-clear-sky",
["02d"] = "weather-few-clouds",
["04d"] = "weather-few-clouds",
["03d"] = "weather-clouds",
["09d"] = "weather-showers-scattered",
["09n"] = "weather-showers-scattered",
["10d"] = "weather-showers",
["11d"] = "weather-strom",
["13d"] = "weather-snow",
["50d"] = "weather-fog",
["01n"] = "weather-clear-night",
["02n"] = "weather-few-clouds-night",
["03n"] = "weather-clouds-night",
["04n"] = "weather-clouds-night",
["10n"] = "weather-showers",
["11n"] = "weather-strom",
["13n"] = "weather-snow",
["50n"] = "weather-fog",
}
local image_map = {
["01d"] = "weather-clear-sky",
["02d"] = "weather-clouds",
["04d"] = "weather-clouds",
["03d"] = "weather-clouds",
["09d"] = "weather-showers-scattered",
["09n"] = "weather-showers-scattered",
["10d"] = "weather-showers",
["11d"] = "weather-strom",
["13d"] = "weather-snow",
["50d"] = "weather-fog",
["01n"] = "weather-clear-night",
["02n"] = "weather-clouds-night",
["03n"] = "weather-clouds-night",
["04n"] = "weather-clouds-night",
["10n"] = "weather-showers",
["11n"] = "weather-strom",
["13n"] = "weather-snow",
["50n"] = "weather-fog",
}
local api_key = helpers.readJson(gears.filesystem.get_cache_dir() .. "json/settings.json").openWeatherApi
local coordinates = { "28.6446772", "77.320955" }
local show_hourly_forecast = true
local show_daily_forecast = true
local units = "metric"
local url = (
"https://api.openweathermap.org/data/2.5/onecall"
.. "?lat="
.. coordinates[1]
.. "&lon="
.. coordinates[2]
.. "&appid="
.. api_key
.. "&units="
.. units
.. "&exclude=minutely"
.. (show_hourly_forecast == false and ",hourly" or "")
.. (show_daily_forecast == false and ",daily" or "")
)
awful.widget.watch(string.format(GET_FORECAST_CMD, url), 600, function(_, stdout, stderr)
local result = json.decode(stdout)
-- Current weather setup
local out = {
desc = result.current.weather[1].description:gsub("^%l", string.upper),
humidity = result.current.humidity,
temp = math.floor(result.current.temp),
feelsLike = math.floor(result.current.feels_like),
image = icon_dir .. icon_map[result.current.weather[1].icon] .. ".svg",
thumb = thumb_dir .. image_map[result.current.weather[1].icon] .. ".jpg",
hourly = {
result.hourly[1],
result.hourly[2],
result.hourly[3],
result.hourly[4],
result.hourly[5],
result.hourly[6],
},
daily = {
result.daily[1],
result.daily[2],
result.daily[3],
result.daily[4],
result.daily[5],
result.daily[6],
}
}
awesome.emit_signal("signal::weather", out)
end)

View File

@ -0,0 +1,34 @@
local awful = require('awful')
local gears = require('gears')
local gfs = gears.filesystem
-- Battery Fetching and Signal Emitting
---------------------------------------
-- Battery information script
local battery_script =
"bash -c 'echo $(cat /sys/class/power_supply/BAT0/capacity) echo $(cat /sys/class/power_supply/BAT0/status)'"
local function battery_emit()
awful.spawn.easy_async_with_shell(
battery_script, function(stdout)
-- The battery level and status are saved as a string. Then the level
-- is stored separately as a string, then converted to int. The status
-- is stored as a bool, and also as an int for registering changes in
-- battery status.
local level = string.match(stdout:match('(%d+)'), '(%d+)')
local level_int = tonumber(level) -- integer
local power = not stdout:match('Discharging') -- boolean
awesome.emit_signal('signal::battery', level_int, power)
end)
end
-- Refreshing
-------------
gears.timer {
timeout = 20,
call_now = true,
autostart = true,
callback = function()
battery_emit()
end
}

View File

@ -0,0 +1,24 @@
local awful = require('awful')
local gears = require('gears')
local brightness_script =
"bash -c 'echo $(($(cat /sys/class/backlight/*/brightness) * 100 / $(cat /sys/class/backlight/*/max_brightness)))'"
local function emit_brightness()
awful.spawn.easy_async_with_shell(
brightness_script, function(stdout)
local level_cur = tonumber(stdout)
awesome.emit_signal('signal::brightness', level_cur)
end)
end
-- Refreshing
-------------
gears.timer {
timeout = 1,
call_now = true,
autostart = true,
callback = function()
emit_brightness()
end
}

View File

@ -0,0 +1,19 @@
local gears = require('gears')
local naughty = require("naughty")
-- Network Fetching and Signal Emitting
---------------------------------------
local function emit_dnd_status()
local status = naughty.is_suspended()
awesome.emit_signal('signal::dnd', status)
end
-- Refreshing
-------------
gears.timer {
timeout = 2,
call_now = true,
autostart = true,
callback = function()
emit_dnd_status()
end
}

View File

@ -0,0 +1,5 @@
require("signal.system.dnd")
require("signal.system.brightness")
require("signal.system.volume")
require("signal.system.battery")
require("signal.system.redshift")

View File

@ -0,0 +1,21 @@
local awful = require('awful')
local gears = require('gears')
local function mic_emit()
awful.spawn.easy_async_with_shell(
"bash -c 'pamixer --source 1 --get-mute'", function(value)
local stringtoboolean = { ["true"] = false, ["false"] = true }
value = value:gsub("%s+", "")
value = stringtoboolean[value]
awesome.emit_signal('signal::mic', value) -- integer
end)
end
gears.timer {
timeout = 1,
call_now = true,
autostart = true,
callback = function()
mic_emit()
end
}

View File

@ -0,0 +1,22 @@
local awful = require('awful')
local gears = require('gears')
local function light_emit()
awful.spawn.easy_async_with_shell(
"bash -c 'cat ~/.cache/redshift'", function(stdout)
local status = stdout:match("true") -- boolean
awesome.emit_signal('signal::redshift', status)
end)
end
-- Microphone Fetching and Signal Emitting
-- Refreshing
-------------
gears.timer {
timeout = 2,
call_now = true,
autostart = true,
callback = function()
light_emit()
end
}

View File

@ -0,0 +1,22 @@
local awful = require('awful')
local gears = require('gears')
local function volume_emit()
awful.spawn.easy_async_with_shell(
"bash -c 'pamixer --get-volume'", function(stdout)
local volume_int = tonumber(stdout) -- integer
awesome.emit_signal('signal::volume', volume_int) -- integer
end)
end
-- Microphone Fetching and Signal Emitting
-- Refreshing
-------------
gears.timer {
timeout = 1,
call_now = true,
autostart = true,
callback = function()
volume_emit()
end
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
width="800px"
height="800px"
viewBox="0 0 24 24"
role="img"
version="1.1"
id="svg67"
sodipodi:docname="awesomewm-svgrepo-com.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs71" />
<sodipodi:namedview
id="namedview69"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="0.76976952"
inkscape:cx="387.12886"
inkscape:cy="419.60612"
inkscape:window-width="1904"
inkscape:window-height="970"
inkscape:window-x="8"
inkscape:window-y="35"
inkscape:window-maximized="0"
inkscape:current-layer="svg67" />
<path
d="M0 24V8.25h16.5V7.5H0V0h24v24h-7.5v-8.25h-9v.75h8.25V24z"
id="path65"
style="fill:#ffffff" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

View File

@ -0,0 +1,513 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="141.5919mm"
height="122.80626mm"
viewBox="0 0 501.70361 435.14028"
id="svg2"
version="1.1"
inkscape:version="0.92.0 r15299"
sodipodi:docname="nix-snowflake.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient5562">
<stop
style="stop-color:#699ad7;stop-opacity:1"
offset="0"
id="stop5564" />
<stop
id="stop5566"
offset="0.24345198"
style="stop-color:#7eb1dd;stop-opacity:1" />
<stop
style="stop-color:#7ebae4;stop-opacity:1"
offset="1"
id="stop5568" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient5053">
<stop
style="stop-color:#415e9a;stop-opacity:1"
offset="0"
id="stop5055" />
<stop
id="stop5057"
offset="0.23168644"
style="stop-color:#4a6baf;stop-opacity:1" />
<stop
style="stop-color:#5277c3;stop-opacity:1"
offset="1"
id="stop5059" />
</linearGradient>
<linearGradient
id="linearGradient5960"
inkscape:collect="always">
<stop
id="stop5962"
offset="0"
style="stop-color:#637ddf;stop-opacity:1" />
<stop
style="stop-color:#649afa;stop-opacity:1"
offset="0.23168644"
id="stop5964" />
<stop
id="stop5966"
offset="1"
style="stop-color:#719efa;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient5867">
<stop
style="stop-color:#7363df;stop-opacity:1"
offset="0"
id="stop5869" />
<stop
id="stop5871"
offset="0.23168644"
style="stop-color:#6478fa;stop-opacity:1" />
<stop
style="stop-color:#719efa;stop-opacity:1"
offset="1"
id="stop5873" />
</linearGradient>
<linearGradient
y2="515.97058"
x2="282.26105"
y1="338.62445"
x1="213.95642"
gradientTransform="translate(983.36076,601.38885)"
gradientUnits="userSpaceOnUse"
id="linearGradient5855"
xlink:href="#linearGradient5960"
inkscape:collect="always" />
<linearGradient
y2="515.97058"
x2="282.26105"
y1="338.62445"
x1="213.95642"
gradientTransform="translate(-197.75174,-337.1451)"
gradientUnits="userSpaceOnUse"
id="linearGradient5855-8"
xlink:href="#linearGradient5867"
inkscape:collect="always" />
<linearGradient
y2="247.58188"
x2="-702.75317"
y1="102.74675"
x1="-775.20807"
gradientTransform="translate(983.36076,601.38885)"
gradientUnits="userSpaceOnUse"
id="linearGradient4544"
xlink:href="#linearGradient5960"
inkscape:collect="always" />
<clipPath
id="clipPath4501"
clipPathUnits="userSpaceOnUse">
<circle
r="241.06563"
cy="686.09473"
cx="335.13995"
id="circle4503"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#adadad;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</clipPath>
<clipPath
id="clipPath5410"
clipPathUnits="userSpaceOnUse">
<circle
r="241.13741"
cy="340.98975"
cx="335.98114"
id="circle5412"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5053"
id="linearGradient5137"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(864.55062,-2197.497)"
x1="-584.19934"
y1="782.33563"
x2="-496.29703"
y2="937.71399" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5053"
id="linearGradient5147"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(864.55062,-2197.497)"
x1="-584.19934"
y1="782.33563"
x2="-496.29703"
y2="937.71399" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5562"
id="linearGradient5162"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(70.505061,-1761.3076)"
x1="200.59668"
y1="351.41116"
x2="290.08701"
y2="506.18814" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5562"
id="linearGradient5172"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(70.505061,-1761.3076)"
x1="200.59668"
y1="351.41116"
x2="290.08701"
y2="506.18814" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5562"
id="linearGradient5182"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(70.505061,-1761.3076)"
x1="200.59668"
y1="351.41116"
x2="290.08701"
y2="506.18814" />
<linearGradient
y2="506.18814"
x2="290.08701"
y1="351.41116"
x1="200.59668"
gradientTransform="translate(70.505061,-1761.3076)"
gradientUnits="userSpaceOnUse"
id="linearGradient5201"
xlink:href="#linearGradient5562"
inkscape:collect="always" />
<linearGradient
y2="937.71399"
x2="-496.29703"
y1="782.33563"
x1="-584.19934"
gradientTransform="translate(864.55062,-2197.497)"
gradientUnits="userSpaceOnUse"
id="linearGradient5205"
xlink:href="#linearGradient5053"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5562"
id="linearGradient4328"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(70.650339,-1055.1511)"
x1="200.59668"
y1="351.41116"
x2="290.08701"
y2="506.18814" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5053"
id="linearGradient4330"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(864.69589,-1491.3405)"
x1="-584.19934"
y1="782.33563"
x2="-496.29703"
y2="937.71399" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98318225"
inkscape:cx="113.58176"
inkscape:cy="-45.193301"
inkscape:document-units="px"
inkscape:current-layer="layer3"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1577"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer7"
inkscape:label="bg"
style="display:none"
transform="translate(-23.75651,-24.84972)">
<rect
transform="translate(-132.5822,958.04022)"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5389"
width="1543.4283"
height="483.7439"
x="132.5822"
y="-957.77832" />
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="logo-guide"
style="display:none"
transform="translate(-156.33871,933.1905)">
<rect
y="-958.02759"
x="132.65129"
height="484.30399"
width="550.41602"
id="rect5379"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5c201e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:export-filename="/home/tim/dev/nix/homepage/logo/nix-wiki.png"
inkscape:export-xdpi="22.07"
inkscape:export-ydpi="22.07" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c24a46;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5372"
width="501.94415"
height="434.30405"
x="156.12303"
y="-933.02759"
inkscape:export-filename="/home/tim/dev/nix/homepage/logo/nixos-logo-only-hires-print.png"
inkscape:export-xdpi="212.2"
inkscape:export-ydpi="212.2" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d98d8a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5381"
width="24.939611"
height="24.939611"
x="658.02826"
y="-958.04022" />
</g>
<g
inkscape:label="print-logo"
inkscape:groupmode="layer"
id="layer1"
style="display:inline"
transform="translate(-156.33871,933.1905)"
sodipodi:insensitive="true">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 309.40365,-710.2521 122.19683,211.6751 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4902 -33.22946,-57.8256 z"
id="path4861"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 353.50926,-797.4433 -122.21756,211.6631 -28.53477,-48.37 32.93839,-56.6875 -65.41521,-0.1719 -13.9414,-24.1698 14.23637,-24.721 93.11177,0.2939 33.46371,-57.6903 z"
id="use4863"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 362.88537,-628.243 244.41439,0.012 -27.62229,48.8968 -65.56199,-0.1817 32.55876,56.7371 -13.96098,24.1585 -28.52722,0.032 -46.3013,-80.7841 -66.69317,-0.1353 z"
id="use4865"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 505.14318,-720.9886 -122.19683,-211.6751 56.15706,-0.5268 32.6236,56.8692 32.85645,-56.5653 27.90237,0.011 14.29086,24.6896 -46.81047,80.4902 33.22946,57.8256 z"
id="use4867"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="path4873"
d="m 309.40365,-710.2521 122.19683,211.6751 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4902 -33.22946,-57.8256 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="use4875"
d="m 451.3364,-803.53264 -244.4144,-0.012 27.62229,-48.89685 65.56199,0.18175 -32.55875,-56.73717 13.96097,-24.15851 28.52722,-0.0315 46.3013,80.78414 66.69317,0.13524 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="use4877"
d="m 460.87178,-633.8425 122.21757,-211.66304 28.53477,48.37003 -32.93839,56.68751 65.4152,0.1718 13.9414,24.1698 -14.23636,24.7211 -93.11177,-0.294 -33.46371,57.6904 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
id="layer2"
inkscape:label="guides"
style="display:none"
transform="translate(72.039038,-1799.4476)">
<path
d="M 460.60629,594.72881 209.74183,594.7288 84.309616,377.4738 209.74185,160.21882 l 250.86446,1e-5 125.43222,217.255 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="1.5707963"
sodipodi:arg1="1.0471976"
sodipodi:r2="217.25499"
sodipodi:r1="250.86446"
sodipodi:cy="377.47382"
sodipodi:cx="335.17407"
sodipodi:sides="6"
id="path6032"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.23600003;fill:#4e4d52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
sodipodi:type="star" />
<path
transform="translate(0,-308.26772)"
sodipodi:type="star"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#4e4d52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="path5875"
sodipodi:sides="6"
sodipodi:cx="335.17407"
sodipodi:cy="685.74158"
sodipodi:r1="100.83495"
sodipodi:r2="87.32563"
sodipodi:arg1="1.0471976"
sodipodi:arg2="1.5707963"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 385.59154,773.06721 -100.83495,0 -50.41747,-87.32564 50.41748,-87.32563 100.83495,10e-6 50.41748,87.32563 z" />
<path
transform="translate(0,-308.26772)"
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path5851"
d="m 1216.5591,938.53395 123.0545,228.14035 -42.6807,-1.2616 -43.4823,-79.7725 -39.6506,80.3267 -32.6875,-19.7984 53.4737,-100.2848 -37.1157,-73.88955 z"
style="fill:url(#linearGradient5855);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.41499999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c53a3a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5884"
width="48.834862"
height="226.22897"
x="-34.74221"
y="446.17056"
transform="rotate(-30)" />
<path
transform="translate(0,-308.26772)"
sodipodi:type="star"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.50899999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path3428"
sodipodi:sides="6"
sodipodi:cx="223.93674"
sodipodi:cy="878.63831"
sodipodi:r1="28.048939"
sodipodi:r2="24.291094"
sodipodi:arg1="0"
sodipodi:arg2="0.52359878"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 251.98568,878.63831 -14.02447,24.29109 h -28.04894 l -14.02447,-24.29109 14.02447,-24.2911 h 28.04894 z" />
<use
x="0"
y="0"
xlink:href="#rect5884"
id="use4252"
transform="rotate(60,268.29786,489.4515)"
width="100%"
height="100%" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.6507937;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4254"
width="5.3947482"
height="115.12564"
x="545.71014"
y="467.07007"
transform="rotate(30,575.23539,-154.13386)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="gradient-logo"
style="display:inline;opacity:1"
sodipodi:insensitive="true"
transform="translate(-156.33871,933.1905)">
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="path3336-6"
d="m 309.54892,-710.38827 122.19683,211.67512 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4901 -33.22946,-57.8257 z"
style="opacity:1;fill:url(#linearGradient4328);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<use
height="100%"
width="100%"
transform="rotate(60,407.11155,-715.78724)"
id="use3439-6"
inkscape:transform-center-y="151.59082"
inkscape:transform-center-x="124.43045"
xlink:href="#path3336-6"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="rotate(-60,407.31177,-715.70016)"
id="use3445-0"
inkscape:transform-center-y="75.573958"
inkscape:transform-center-x="-168.20651"
xlink:href="#path3336-6"
y="0"
x="0" />
<use
height="100%"
width="100%"
transform="rotate(180,407.41868,-715.7565)"
id="use3449-5"
inkscape:transform-center-y="-139.94592"
inkscape:transform-center-x="59.669705"
xlink:href="#path3336-6"
y="0"
x="0" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4330);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 309.54892,-710.38827 122.19683,211.67512 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4901 -33.22946,-57.8256 z"
id="path4260-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<use
height="100%"
width="100%"
transform="rotate(120,407.33916,-716.08356)"
id="use4354-5"
xlink:href="#path4260-0"
y="0"
x="0"
style="display:inline" />
<use
height="100%"
width="100%"
transform="rotate(-120,407.28823,-715.86995)"
id="use4362-2"
xlink:href="#path4260-0"
y="0"
x="0"
style="display:inline" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg height="16" width="16"><path d="M4.003 4h1 .031a1.04 1.04 0 0 1 .687.312l2.28 2.281 2.312-2.281c.266-.23.446-.305.687-.312h1v1c0 .286-.034.551-.25.75l-2.28 2.281 2.249 2.25c.188.188.281.453.281.719v1h-1c-.265 0-.53-.093-.718-.281l-2.28-2.281-2.28 2.281c-.188.188-.453.281-.718.281h-1v-1c0-.265.093-.531.281-.719l2.28-2.25-2.28-2.281c-.211-.195-.303-.469-.281-.75z" fill="#363636"/></svg>

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg height="16" width="16"><path d="M4 7v3h8V7z" fill="#363636"/></svg>

After

Width:  |  Height:  |  Size: 73 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 1,8 C 1,11.866 4.134,15 8,15 9.9252,15 11.68,14.117 13,12.715 12.482,12.847 12.034,13 11.5,13 7.9101,13 5,10.09 5,6.5 5,4.267 6.1294,2.19 8,1 4.1145,1 1,4.134 1,8 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 286 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 6.9999991,-6.4999999e-8 V 2.085937 a 6,6 0 0 1 1,-0.085937 6,6 0 0 1 1,0.08984 V -6.4999999e-8 Z M 3.0507801,1.6367189 1.6367181,3.050781 3.1132801,4.527344 a 6,6 0 0 1 1.416016,-1.41211 z m 9.8984379,0 -1.476563,1.4765621 a 6,6 0 0 1 1.41211,1.416016 L 14.36328,3.050781 Z M 7.9999991,3 a 5,5 0 0 0 -5,5 5,5 0 0 0 5,5 A 5,5 0 0 0 12.999999,8 5,5 0 0 0 7.9999991,3 Z m -8,4 v 2 h 2.085937 a 6,6 0 0 1 -0.08594,-1 6,6 0 0 1 0.08984,-1 z M 13.914061,7 a 6,6 0 0 1 0.08594,1 6,6 0 0 1 -0.08984,1 h 2.08984 V 7 Z m -10.7988279,4.470703 -1.478515,1.478516 1.414062,1.414062 1.476563,-1.476562 a 6,6 0 0 1 -1.41211,-1.416016 z m 9.7714849,0.002 a 6,6 0 0 1 -1.416016,1.41211 l 1.478516,1.478515 1.414062,-1.414062 z M 6.9999991,13.910156 V 16 h 2 v -2.085938 a 6,6 0 0 1 -1,0.08594 6,6 0 0 1 -1,-0.08984 z"/>
</svg>

After

Width:  |  Height:  |  Size: 921 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 7.736,0.9962 C 4.9732,1.0977 2.4273,2.8008 1.4235,5.5587 0.89934,6.999 0.87974,8.501 1.2653,9.875 1.669,8.557 2.7497,7.542 4.1032,7.192 4.2732,6.9013 4.4747,6.6319 4.693,6.3791 4.7035,5.6688 4.8234,4.9505 5.0797,4.2462 5.5939,2.8336 6.5542,1.7379 7.736,0.9962 Z M 8.086,5.7502 C 6.5323,5.7502 5.2096,6.7011 4.6403,8.047 3.1944,8.262 2.0856,9.494 2.0856,11 2.0856,12.657 3.4287,14 5.0856,14 H 11.461 C 12.91,14 14.086,12.825 14.086,11.375 14.086,10.028 13.073,8.924 11.765,8.774 11.424,7.054 9.906,5.7502 8.086,5.7502 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 966 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 7.736,0.9962 C 4.9732,1.0977 2.4273,2.8008 1.4235,5.5587 0.89934,6.999 0.87974,8.501 1.2653,9.875 1.669,8.557 2.7497,7.542 4.1032,7.192 4.2732,6.9013 4.4747,6.6319 4.693,6.3791 4.7035,5.6688 4.8234,4.9505 5.0797,4.2462 5.5939,2.8336 6.5542,1.7379 7.736,0.9962 Z M 8.086,5.7502 C 6.5323,5.7502 5.2096,6.7011 4.6403,8.047 3.1944,8.262 2.0856,9.494 2.0856,11 2.0856,12.657 3.4287,14 5.0856,14 H 11.461 C 12.91,14 14.086,12.825 14.086,11.375 14.086,10.028 13.073,8.924 11.765,8.774 11.424,7.054 9.906,5.7502 8.086,5.7502 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 966 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 13.5,16 C 14.88,16 16,14.88 16,13.5 16,12.23 15.04,11.19 13.81,11.03 13.41,9.86 12.31,9 11,9 9.69,9 8.6,9.86 8.19,11.03 6.96,11.19 6,12.23 6,13.5 6,14.88 7.12,16 8.5,16"/>
<path style="fill:#dfdfdf" d="M 8,1 C 4.1145,0.999 1,4.134 1,8 1,10.841 2.6956,13.28 5.127,14.377 5.0526,14.095 5,13.804 5,13.5 5,12.309 5.6566,11.348 6.5957,10.758 5.6043,9.6168 5,8.1303 5,6.5 5.0014,4.267 6.1294,2.19 8,1 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 519 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 7 0 L 7 2.0859375 A 6 6 0 0 1 8 2 A 6 6 0 0 1 9 2.0898438 L 9 0 L 7 0 z M 3.0507812 1.6367188 L 1.6367188 3.0507812 L 3.1132812 4.5273438 A 6 6 0 0 1 4.5292969 3.1152344 L 3.0507812 1.6367188 z M 12.949219 1.6367188 L 11.472656 3.1132812 A 6 6 0 0 1 12.884766 4.5292969 L 14.363281 3.0507812 L 12.949219 1.6367188 z M 8 3 A 5 5 0 0 0 3 8 A 5 5 0 0 0 5.2949219 12.205078 C 5.713317 11.305716 6.5416242 10.637052 7.5234375 10.322266 C 8.1696152 9.0017204 9.4227843 8 11 8 C 11.732994 8 12.393594 8.2229024 12.958984 8.5878906 A 5 5 0 0 0 13 8 A 5 5 0 0 0 8 3 z M 0 7 L 0 9 L 2.0859375 9 A 6 6 0 0 1 2 8 A 6 6 0 0 1 2.0898438 7 L 0 7 z M 13.914062 7 A 6 6 0 0 1 14 8 A 6 6 0 0 1 13.910156 9 L 16 9 L 16 7 L 13.914062 7 z M 11 9 C 9.69 9 8.5994531 9.8592969 8.1894531 11.029297 C 6.9594531 11.189297 6 12.23 6 13.5 C 6 14.88 7.12 16 8.5 16 L 13.5 16 C 14.88 16 16 14.88 16 13.5 C 16 12.23 15.040547 11.189297 13.810547 11.029297 C 13.410547 9.8592969 12.31 9 11 9 z M 3.1152344 11.470703 L 1.6367188 12.949219 L 3.0507812 14.363281 L 4.5273438 12.886719 A 6 6 0 0 1 3.1152344 11.470703 z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="opacity:0.3;fill:#dfdfdf" d="M 2 1 C 1.446 1 1 1.446 1 2 C 1 2.554 1.446 3 2 3 L 8 3 C 8.554 3 9 2.554 9 2 C 9 1.446 8.554 1 8 1 L 2 1 z M 5 5 C 4.446 5 4 5.446 4 6 C 4 6.554 4.446 7 5 7 L 15 7 C 15.554 7 16 6.554 16 6 C 16 5.446 15.554 5 15 5 L 5 5 z M 1 9 C 0.446 9 0 9.446 0 10 C 0 10.554 0.446 11 1 11 L 12 11 C 12.554 11 13 10.554 13 10 C 13 9.446 12.554 9 12 9 L 1 9 z M 3 13 C 2.446 13 2 13.446 2 14 C 2 14.554 2.446 15 3 15 L 15 15 C 15.554 15 16 14.554 16 14 C 16 13.446 15.554 13 15 13 L 3 13 z"/>
</svg>

After

Width:  |  Height:  |  Size: 607 B

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,0 C 5.929,0 4.165,1.27 3.406,3.07 1.478,3.35 0,5 0,7 0,8.94 1.365,10.54 3.187,10.91 3.951,10.13 4.709,9.35 5.5,8.6 6.073,9.14 6.633,9.7 7.187,10.25 7.43,10.18 7.57,9.41 7.906,9.16 8.76,8.29 9.615,7.43 10.5,6.6 11.166,7.22 11.791,7.86 12.437,8.5 13.035,9.07 13.665,9.71 13.875,10.53 13.891,10.59 13.893,10.64 13.906,10.69 15.141,10.15 16,8.94 16,7.5 16,5.71 14.649,4.23 12.906,4.03 12.451,1.74 10.427,0 8,0 Z M 10.5,9.44 C 10.415,9.52 10.335,9.61 10.25,9.69 9.853,10.11 9.351,10.47 9.125,11 H 11.906 C 11.88,10.94 11.85,10.87 11.812,10.82 11.439,10.3 10.933,9.9 10.5,9.44 Z"/>
<path style="fill:currentColor" class="ColorScheme-Highlight" d="M 10.5,8 10.156,8.34 8.75,9.75 C 8.297,10.2 8,10.81 8,11.5 8,12.87 9.125,14 10.5,14 11.875,14 13,12.87 13,11.5 13,10.81 12.703,10.2 12.25,9.75 L 10.844,8.34 Z M 5.5,10 5.156,10.34 3.75,11.75 C 3.297,12.2 3,12.81 3,13.5 3,14.87 4.125,16 5.5,16 6.875,16 8,14.87 8,13.5 8,12.81 7.703,12.2 7.25,11.75 L 5.844,10.34 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#fcc467" d="M 10,8 C 8.69,8 7.6,8.86 7.19,10.03 5.96,10.19 5,11.23 5,12.5 5,13.88 6.12,15 7.5,15 H 12.5 C 13.88,15 15,13.88 15,12.5 15,11.23 14.04,10.19 12.81,10.03 12.41,8.86 11.31,8 10,8 Z"/>
<path style="fill:#dfdfdf" d="M 8,0 C 5.93,0 4.1702,1.2705 3.4102,3.0605 1.4802,3.3505 0,4.99 0,7 0,9.21 1.79,11 4,11 H 4.3945 C 4.8388,10.204 5.6169,9.6129 6.5234,9.3223 7.1696,8.0017 8.4228,7 10,7 11.573,7 12.83,7.9972 13.473,9.3203 13.983,9.4834 14.453,9.7437 14.848,10.08 15.551,9.4395 16,8.5242 16,7.5 16,5.7 14.65,4.2293 12.91,4.0293 12.45,1.7393 10.43,0 8,0 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 669 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,1 C 5.9289,1 4.1653,2.2679 3.4062,4.0625 1.4784,4.3491 0,5.9924 0,8 0,10.209 1.7909,12 4,12 H 4.4062 C 4.8601,11.199 5.6472,10.573 6.5312,10.313 7.151,8.99 8.506,7.974 10,8 11.908,7.969 13.582,9.485 13.875,11.344 14.018,11.389 14.144,11.435 14.281,11.5 15.312,10.891 16,9.784 16,8.5 16,6.7035 14.649,5.2313 12.906,5.0312 12.452,2.7379 10.427,1 8,1 Z M 10,9 C 8.688,9 7.595,9.858 7.188,11.031 5.9567,11.187 5,12.227 5,13.5 5,14.881 6.1193,16 7.5,16 H 13 C 14.105,16 15,15.105 15,14 15,12.895 14.105,12 13,12 13,10.343 11.657,9 10,9 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 982 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 8,0 C 5.93,0 4.17,1.27 3.41,3.06 1.48,3.35 0,4.99 0,7 0,7.73 0.2,8.41 0.54,9 H 0.52 C 1.08,9.97 2.04,10.68 3.17,10.91 L 5.5,8.58 7.25,10.33 C 7.43,9.84 7.69,9.39 8.04,9.04 L 10.5,6.58 12.96,9.04 C 13.4,9.48 13.73,10.05 13.89,10.69 H 13.91 V 10.69 L 13.92,10.68 H 13.93 L 13.94,10.67 C 15.16,10.12 16,8.92 16,7.5 16,5.7 14.65,4.23 12.91,4.03 12.45,1.74 10.43,0 8,0 Z"/>
<path style="fill:#dfdfdf" d="M 10.5,8 8.75,9.75 C 8.3,10.2 8,10.81 8,11.5 8,12.87 9.13,14 10.5,14 11.87,14 13,12.87 13,11.5 13,10.81 12.7,10.2 12.25,9.75 Z M 5.5,10 3.75,11.75 C 3.3,12.2 3,12.81 3,13.5 3,14.87 4.13,16 5.5,16 6.87,16 8,14.87 8,13.5 8,12.81 7.7,12.2 7.25,11.75 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 770 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 8,0 C 5.93,0 4.17,1.27 3.41,3.06 1.48,3.35 0,4.99 0,7 0,9.21 1.79,11 4,11 H 12.5 C 14.43,11 16,9.43 16,7.5 16,5.7 14.65,4.23 12.91,4.03 12.45,1.74 10.43,0 8,0 Z"/>
<path style="fill:#dfdfdf" d="M 2.9766,11.994 A 0.5,0.5 0 0 0 2.5527,12.277 L 1.5527,14.277 A 0.5,0.5 0 1 0 2.4473,14.723 L 3.4473,12.723 A 0.5,0.5 0 0 0 2.9766,11.994 Z M 5.4766,11.994 A 0.5,0.5 0 0 0 5.0527,12.277 L 4.0527,14.277 A 0.5,0.5 0 1 0 4.9473,14.723 L 5.9473,12.723 A 0.5,0.5 0 0 0 5.4766,11.994 Z M 7.9766,11.994 A 0.5,0.5 0 0 0 7.5527,12.277 L 6.5527,14.277 A 0.5,0.5 0 1 0 7.4473,14.723 L 8.4473,12.723 A 0.5,0.5 0 0 0 7.9766,11.994 Z M 10.477,11.994 A 0.5,0.5 0 0 0 10.053,12.277 L 9.0527,14.277 A 0.5,0.5 0 1 0 9.9473,14.723 L 10.947,12.723 A 0.5,0.5 0 0 0 10.477,11.994 Z M 12.977,11.994 A 0.5,0.5 0 0 0 12.553,12.277 L 11.553,14.277 A 0.5,0.5 0 1 0 12.447,14.723 L 13.447,12.723 A 0.5,0.5 0 0 0 12.977,11.994 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1016 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,0.004 C 5.9289,0.004 4.1653,1.2719 3.4062,3.0665 1.4784,3.3531 0,4.9964 0,7.004 0,9.213 1.7909,11.004 4,11.004 H 12.5 C 14.433,11.004 16,9.437 16,7.504 16,5.7075 14.649,4.2353 12.906,4.0353 12.452,1.7419 10.427,0.004 8,0.004 Z M 3.4785,11.992 A 0.50005,0.50005 0 0 0 3.0527,12.275 L 2.0527,14.275 A 0.50025,0.50025 0 0 0 2.9473,14.723 L 3.9473,12.723 A 0.50005,0.50005 0 0 0 3.4785,11.992 Z M 6.4785,11.994 A 0.50005,0.50005 0 0 0 6.0527,12.277 L 5.0527,14.277 A 0.50025,0.50025 0 1 0 5.9473,14.725 L 6.9473,12.725 A 0.50005,0.50005 0 0 0 6.4785,11.994 Z M 11,12 A 1,1 0 0 0 10,13 1,1 0 0 0 11,14 1,1 0 0 0 12,13 1,1 0 0 0 11,12 Z M 9,14 A 1,1 0 0 0 8,15 1,1 0 0 0 9,16 1,1 0 0 0 10,15 1,1 0 0 0 9,14 Z M 13,14 A 1,1 0 0 0 12,15 1,1 0 0 0 13,16 1,1 0 0 0 14,15 1,1 0 0 0 13,14 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,0 C 5.9289,0 4.1653,1.2679 3.4062,3.0625 1.4784,3.3491 0,4.9924 0,7 0,9.209 1.7909,11 4,11 H 5.1855 C 5.6024,9.842 6.7062,9 8,9 9.294,9 10.398,9.842 10.814,11 H 12.5 C 14.433,11 16,9.433 16,7.5 16,5.7035 14.649,4.2313 12.906,4.0312 12.452,1.7379 10.427,0 8,0 Z M 8,10 A 2,2 0 0 0 6,12 2,2 0 0 0 8,14 2,2 0 0 0 10,12 2,2 0 0 0 8,10 Z M 3,12 A 2,2 0 0 0 1,14 2,2 0 0 0 3,16 2,2 0 0 0 5,14 2,2 0 0 0 3,12 Z M 13,12 A 2,2 0 0 0 11,14 2,2 0 0 0 13,16 2,2 0 0 0 15,14 2,2 0 0 0 13,12 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 929 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,0.004 C 5.9289,0.004 4.1653,1.2719 3.4062,3.0665 1.4784,3.3531 0,4.9964 0,7.004 0,9.213 1.7909,11.004 4,11.004 H 12.5 C 14.433,11.004 16,9.437 16,7.504 16,5.7075 14.649,4.2353 12.906,4.0353 12.452,1.7419 10.427,0.004 8,0.004 Z M 4,12 A 1,1 0 0 0 3,13 1,1 0 0 0 4,14 1,1 0 0 0 5,13 1,1 0 0 0 4,12 Z M 8,12 A 1,1 0 0 0 7,13 1,1 0 0 0 8,14 1,1 0 0 0 9,13 1,1 0 0 0 8,12 Z M 12,12 A 1,1 0 0 0 11,13 1,1 0 0 0 12,14 1,1 0 0 0 13,13 1,1 0 0 0 12,12 Z M 2,14 A 1,1 0 0 0 1,15 1,1 0 0 0 2,16 1,1 0 0 0 3,15 1,1 0 0 0 2,14 Z M 6,14 A 1,1 0 0 0 5,15 1,1 0 0 0 6,16 1,1 0 0 0 7,15 1,1 0 0 0 6,14 Z M 10,14 A 1,1 0 0 0 9,15 1,1 0 0 0 10,16 1,1 0 0 0 11,15 1,1 0 0 0 10,14 Z M 14,14 A 1,1 0 0 0 13,15 1,1 0 0 0 14,16 1,1 0 0 0 15,15 1,1 0 0 0 14,14 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8,0 C 5.93,0 4.17,1.27 3.41,3.07 1.48,3.35 0,5 0,7 0,9.21 1.79,11 4,11 L 6,11 6,8.5 C 6,7.67 6.67,7 7.5,7 8.33,7 9,7.67 9,8.5 l 0,2.5 3.5,0 C 14.43,11 16,9.44 16,7.5 16,5.71 14.65,4.23 12.91,4.03 12.45,1.74 10.43,0 8,0 Z"/>
<path style="fill:currentColor" class="ColorScheme-Highlight" d="m 7.34,8.029287 c -0.2,0.07 -0.35,0.28 -0.34,0.5 l 0,3.78 -0.03,0.09 -0.63,0.63 -0.03,0 -1.81,0 -0.22,0 -0.12,0.16 -1,1 c -0.26,0.15 -0.31,0.56 -0.1,0.78 0.22,0.21 0.63,0.16 0.78,-0.1 l 0.85,-0.84 1.31,0 0,1.4 c 0,0.26 0.24,0.51 0.5,0.51 0.26,0 0.5,-0.25 0.5,-0.51 l 0,-1.71 0.69,-0.69 2.12,0 0.75,0.75 -1.4,1.31 c -0.26,0.15 -0.31,0.56 -0.1,0.78 0.22,0.21 0.63,0.16 0.78,-0.1 l 1.41,-1.3 1.41,1.3 c 0.15,0.26 0.56,0.31 0.78,0.1 0.21,-0.22 0.16,-0.63 -0.1,-0.78 l -3,-2.9 -0.12,-0.16 -0.22,0 -2,0 0,-3.5 c 0,-0.3 -0.3,-0.56 -0.59,-0.5 z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 8,16 C 8,16 7,16 7,15 7,14 8,14 8,14 8,14 9,14 9,13 9,12 8,12 8,12 H 1 C 1,12 0,12 0,11 0,10 1,10 1,10 H 8 C 8,10 11,10 11,13 11,16 8,16 8,16 Z M 13,3 C 13,3 12,3 12,4 12,5 13,5 13,5 13,5 14,5 14,6 14,7 13,7 13,7 H 5 C 5,7 4,7 4,8 4,9 5,9 5,9 H 13 C 13,9 16,9 16,6 16,3 13,3 13,3 Z M 8,0 C 8,0 7,0 7,1 7,2 8,2 8,2 8,2 9,2 9,3 9,4 8,4 8,4 H 1 C 1,4 0,4 0,5 0,6 1,6 1,6 H 8 C 8,6 11,6 11,3 11,0 8,0 8,0 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 524 B

Some files were not shown because too many files have changed in this diff Show More