finished application laucnher and bluetooth widget

This commit is contained in:
Rene Kievits
2022-11-27 10:58:27 +01:00
parent c6341f84e7
commit 10f56a7273
77 changed files with 2379 additions and 4938 deletions

View File

@@ -8,16 +8,15 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local setmetatable = setmetatable local setmetatable = setmetatable
local abutton = require("awful.button")
local beautiful = require("beautiful") local beautiful = require("beautiful")
local gtable = require("gears.table") local gtable = require("gears.table")
local base = require("wibox.widget.base") local base = require("wibox.widget.base")
local gstring = require("gears.string") local gstring = require("gears.string")
local keygrabber = require("awful.keygrabber") local akeygrabber = require("awful.keygrabber")
local wtemplate = require("wibox.template") local akey = require("awful.key")
local textbox = require("wibox.widget.textbox")
local capi = local capi = {
{
selection = selection, selection = selection,
mousegrabber = mousegrabber, mousegrabber = mousegrabber,
mouse = mouse, mouse = mouse,
@@ -31,8 +30,7 @@ local function text_with_cursor(text, cursor_pos, self)
local cursor_fg = beautiful.inputbox_cursor_fg or "#313131" local cursor_fg = beautiful.inputbox_cursor_fg or "#313131"
local cursor_bg = beautiful.inputbox_cursor_bg or "#0dccfc" local cursor_bg = beautiful.inputbox_cursor_bg or "#0dccfc"
local text_color = beautiful.inputbox_fg or "#ffffff" local placeholder_text = self.hint_text or ""
local placeholder_text = beautiful.inputbox_placeholder_text or "Type here..."
local placeholder_fg = beautiful.inputbox_placeholder_fg or "#777777" local placeholder_fg = beautiful.inputbox_placeholder_fg or "#777777"
local highlight_bg = beautiful.inputbox_highlight_bg or "#35ffe4" local highlight_bg = beautiful.inputbox_highlight_bg or "#35ffe4"
local highlight_fg = beautiful.inputbox_highlight_fg or "#000000" local highlight_fg = beautiful.inputbox_highlight_fg or "#000000"
@@ -41,16 +39,17 @@ local function text_with_cursor(text, cursor_pos, self)
return "<span foreground='" .. placeholder_fg .. "'>" .. placeholder_text .. "</span>" return "<span foreground='" .. placeholder_fg .. "'>" .. placeholder_text .. "</span>"
end end
local offset = 0
if text:sub(cursor_pos - 1, cursor_pos - 1) == -1 then
offset = 1
end
if #text < cursor_pos then if #text < cursor_pos then
char = " " char = " "
spacer = "" spacer = ""
text_start = gstring.xml_escape(text) text_start = gstring.xml_escape(text)
text_end = "" text_end = ""
else else
local offset = 0
if #text:sub(cursor_pos, cursor_pos) == -1 then
offset = 1
end
char = gstring.xml_escape(text:sub(cursor_pos, cursor_pos + offset)) char = gstring.xml_escape(text:sub(cursor_pos, cursor_pos + offset))
spacer = " " spacer = " "
text_start = gstring.xml_escape(text:sub(1, cursor_pos - 1)) text_start = gstring.xml_escape(text:sub(1, cursor_pos - 1))
@@ -64,14 +63,12 @@ local function text_with_cursor(text, cursor_pos, self)
self._private.highlight.cur_pos_end)) self._private.highlight.cur_pos_end))
local text_end_highlight = gstring.xml_escape(text:sub(self._private.highlight.cur_pos_end + 1)) local text_end_highlight = gstring.xml_escape(text:sub(self._private.highlight.cur_pos_end + 1))
return "<span foreground='" .. text_color .. "'>" .. text_start_highlight .. "</span>" .. return text_start_highlight ..
"<span foreground='" .. highlight_fg .. "' background='" .. highlight_bg .. "'>" .. "<span foreground='" .. highlight_fg .. "' background='" .. highlight_bg .. "'>" ..
text_highlighted .. text_highlighted .. "</span>" .. text_end_highlight
"</span>" .. "<span foreground='" .. text_color .. "'>" .. text_end_highlight .. "</span>"
else else
return "<span foreground='" .. text_color .. "'>" .. text_start .. "</span>" .. return text_start .. "<span background='" .. cursor_bg .. "' foreground='" .. cursor_fg .. "'>" ..
"<span background='" .. cursor_bg .. "' foreground='" .. cursor_fg .. "'>" .. char .. "</span>" .. text_end .. spacer
char .. "</span>" .. "<span foreground='" .. text_color .. "'>" .. text_end .. spacer .. "</span>"
end end
end end
@@ -91,99 +88,6 @@ end
inputbox.set_widget = base.set_widget_common inputbox.set_widget = base.set_widget_common
function inputbox:set_widget_template(widget_template)
self._private.widget_template = widget_template
self:set_widget(widget_template)
end
function inputbox:get_widget()
return self._private.widget
end
function inputbox:get_children()
return { self._private.widget }
end
function inputbox:set_children(children)
self:set_widget(children[1])
end
function inputbox:reset()
self._private.widget_template = nil
self:set_widget(nil)
end
--- The inputbox border color
--
-- @DOC_awful_widget_inputbox_border_color_EXAMPLE@
--
-- @property border_color
-- @tparam[opt=gears.color] string border_color
-- @see gears.color
-- @propemits true false
-- @propbeautiful
function inputbox:set_border_color(v)
self._private.border_color = v
self:emit_signal("property::border_color", v)
end
--- The inputbox border width
--
-- @DOC_awful_widget_inputbox_border_width_EXAMPLE@
--
-- @property border_width
-- @tparam[opt=0] number|nil border_width
-- @negativeallowed false
-- @propertyunit pixel
-- @propemits true false
-- @propbeautiful
function inputbox:set_border_width(v)
self._private.border_width = v
self:emit_signal("property::border_width", v)
end
--- The inputbox background color
--
-- @DOC_awful_widget_inputbox_bg_EXAMPLE@
--
-- @property bg
-- @tparam[opt=gears.color] string foreground
-- @see gears.color
-- @propemits true false
-- @propbeautiful
function inputbox:set_bg(v)
self._private.bg = v
self:emit_signal("property::bg", v)
end
--- The text foreground color
--
-- @DOC_awful_widget_inputbox_fg_EXAMPLE@
--
-- @property string
-- @tparam[opt=gears.color] string foreground
-- @see gears.color
-- @propemits true false
-- @propbeautiful
function inputbox:set_fg(v)
self._private.fg = v
self:emit_signal("property::fg", v)
end
--- The shape of the inputbox
--
-- @DOC_awful_widget_inputbox_shape_EXAMPLE@
--
-- @property shape
-- @tparam[opt=gears.shape.rectangle] shape|nil shape
-- @see gears.shape
-- @propemits true false
-- @propbeautiful
function inputbox:set_shape(v)
self._private.shape = v
self:emit_signal("property::shape", v)
end
--- Clears the current text --- Clears the current text
function inputbox:clear() function inputbox:clear()
self:set_text("") self:set_text("")
@@ -195,35 +99,23 @@ end
function inputbox:set_text(text) function inputbox:set_text(text)
self._private.text = text self._private.text = text
self.markup = text_with_cursor(self:get_text(), #self:get_text(), self)
self:emit_signal("property::text", text) self:emit_signal("property::text", text)
end end
--- Stop the keygrabber and mousegrabber --- Stop the keygrabber and mousegrabber
function inputbox:stop() function inputbox:stop()
if (not self.akeygrabber) or (not self.akeygrabber.is_running) then return end
self:emit_signal("stopped") self:emit_signal("stopped")
keygrabber.stop() self.akeygrabber.stop()
capi.mousegrabber.stop()
end end
function inputbox:focus() function inputbox:focus()
keygrabber.stop() if (not self.akeygrabber) or (not self.akeygrabber.is_running) then
if not keygrabber.is_running then akeygrabber.stop()
self:run() self:run()
end end
-- Stops the mousegrabber when not clicked on the widget
--[[ capi.mousegrabber.run(
function(m)
if m.buttons[1] then
if capi.mouse.current_wibox ~= self:get_widget().widget then
self:emit_signal("keygrabber::stop", "")
return false
end
end
return true
end, "left_ptr"
) ]]
self:connect_signal("button::press", function() self:connect_signal("button::press", function()
if capi.mouse.current_widget ~= self then if capi.mouse.current_widget ~= self then
self:emit_signal("keygrabber::stop", "") self:emit_signal("keygrabber::stop", "")
@@ -231,61 +123,40 @@ function inputbox:focus()
end) end)
end end
--[[ local function widget_update(text, cursor_pos, widget)
text = text or ""
cursor_pos = cursor_pos or 1
widget:set_text(text)
widget:emit_signal("property::markup", text)
end ]]
--- Init the inputbox and start the keygrabber --- Init the inputbox and start the keygrabber
function inputbox:run() function inputbox:run()
if not self._private.text then self._private.text = "" end if not self._private.text then self._private.text = "" end
-- Init the cursor position, but causes on refocus the cursor to move to the left -- Init the cursor position, but causes on refocus the cursor to move to the left
local cursor_pos = #self:get_text() + 1 local cursor_pos = #self:get_text() + 1
self:emit_signal("started")
-- Init and reset(when refocused) the highlight -- Init and reset(when refocused) the highlight
self._private.highlight = {} self._private.highlight = {}
-- Emitted when the keygrabber is stopped self.akeygrabber = akeygrabber {
self:connect_signal("cancel", function() autostart = true,
self:stop() start_callback = function()
self:emit_signal("stopped") self:emit_signal("started")
end) end,
stop_callback = function(_, stop_key)
-- Emitted when the keygrabber should submit the text if stop_key == "Return" then
self:connect_signal("submit", function(text) self:emit_signal("submit", self:get_text(), stop_key)
self:stop() -- Only reset text on enter as on escape you might want to continue later
self:emit_signal("stopped", text)
end)
self:emit_signal("key_pressed", "B", "A")
keygrabber.run(function(mod, key, event)
local mod_keys = {}
for _, v in ipairs(mod) do
mod_keys[v] = true
end
if not (event == "press") then return end
--Escape cases
-- Just quit and leave the text as is
if (not mod_keys.Control) and (key == "Escape") then
self:emit_signal("cancel")
elseif (not mod_keys.Control and key == "KP_Enter") or (not mod_keys.Control and key == "Return") then
self:emit_signal("submit", self:get_text())
self:set_text("") self:set_text("")
else
self:emit_signal("stopped", stop_key)
end end
end,
-- All shift, control or key cases stop_key = { "Escape", "Return" },
if mod_keys.Shift then keybindings = {
if key == "Left" then --lShift, rShift = #50, #62
--lControl, rControl = #37, #105
akey {
modifiers = { "Shift" },
key = "Left", -- left
on_press = function()
if cursor_pos > 1 then if cursor_pos > 1 then
local offset = (self._private.text:sub(cursor_pos - 1, cursor_pos - 1):wlen() == -1) and 1 or 0
if not self._private.highlight.cur_pos_start then if not self._private.highlight.cur_pos_start then
self._private.highlight.cur_pos_start = cursor_pos - 1 self._private.highlight.cur_pos_start = cursor_pos - 1
end end
@@ -296,12 +167,24 @@ function inputbox:run()
if self._private.highlight.cur_pos_start < cursor_pos then if self._private.highlight.cur_pos_start < cursor_pos then
self._private.highlight.cur_pos_end = self._private.highlight.cur_pos_end - 1 self._private.highlight.cur_pos_end = self._private.highlight.cur_pos_end - 1
else else
self._private.highlight.cur_pos_start = self._private.highlight.cur_pos_start - 1 self._private.highlight.cur_pos_start = self._private.highlight.cur_pos_start
end end
cursor_pos = cursor_pos - 1 cursor_pos = cursor_pos - 1
end end
elseif key == "Right" then if cursor_pos < 1 then
cursor_pos = 1
elseif cursor_pos > #self._private.text + 1 then
cursor_pos = #self._private.text + 1
end
self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", "Shift", "Left")
end
},
akey {
modifiers = { "Shift" },
key = "Right", -- right
on_press = function()
if #self._private.text >= cursor_pos then if #self._private.text >= cursor_pos then
if not self._private.highlight.cur_pos_end then if not self._private.highlight.cur_pos_end then
self._private.highlight.cur_pos_end = cursor_pos - 1 self._private.highlight.cur_pos_end = cursor_pos - 1
@@ -320,23 +203,32 @@ function inputbox:run()
self._private.highlight = {} self._private.highlight = {}
end end
end end
else if cursor_pos < 1 then
if key:wlen() == 1 then cursor_pos = 1
self:set_text(self._private.text:sub(1, cursor_pos - 1) .. elseif cursor_pos > #self._private.text + 1 then
string.upper(key) .. self._private.text:sub(cursor_pos)) cursor_pos = #self._private.text + 1
cursor_pos = cursor_pos + 1
end end
self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", "Shift", "Right")
end end
elseif mod_keys.Control then },
if key == "a" then akey {
modifiers = { "Control" },
key = "a", -- a
on_press = function()
-- Mark the entire text -- Mark the entire text
self._private.highlight = { self._private.highlight = {
cur_pos_start = 1, cur_pos_start = 1,
cur_pos_end = #self._private.text cur_pos_end = #self._private.text
} }
elseif key == "c" then self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
-- TODO: Copy the highlighted text when the selection setter gets implemented self:emit_signal("inputbox::key_pressed", "Control", "a")
elseif key == "v" then end
},
akey {
modifiers = { "Control" },
key = "v", -- v
on_press = function()
local sel = capi.selection() local sel = capi.selection()
if sel then if sel then
sel = sel:gsub("\n", "") sel = sel:gsub("\n", "")
@@ -354,10 +246,29 @@ function inputbox:run()
cursor_pos = cursor_pos + #sel cursor_pos = cursor_pos + #sel
end end
end end
elseif key == "x" then
--TODO: "cut". Copy selected then clear text, this requires to add the c function first. self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self._private.highlight = {} self:emit_signal("inputbox::key_pressed", "Control", "v")
elseif key == "Left" then end
},
akey {
modifiers = { "Control" },
key = "c", -- c
on_press = function()
--TODO
end
},
akey {
modifiers = { "Control" },
key = "x", -- x
on_press = function()
--TODO
end
},
akey {
modifiers = { "Control" },
key = "Left", -- left
on_press = function()
-- Find all spaces -- Find all spaces
local spaces = {} local spaces = {}
local t, i = self._private.text, 0 local t, i = self._private.text, 0
@@ -375,16 +286,39 @@ function inputbox:run()
end end
end end
cursor_pos = cp cursor_pos = cp
elseif key == "Right" then if cursor_pos < 1 then
cursor_pos = 1
elseif cursor_pos > #self._private.text + 1 then
cursor_pos = #self._private.text + 1
end
self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", "Control", "Left")
end
},
akey {
modifiers = { "Control" },
key = "Right", -- right
on_press = function()
local next_space = self._private.text:sub(cursor_pos):find("%s") local next_space = self._private.text:sub(cursor_pos):find("%s")
if next_space then if next_space then
cursor_pos = cursor_pos + next_space cursor_pos = cursor_pos + next_space
else else
cursor_pos = #self._private.text + 1 cursor_pos = #self._private.text + 1
end end
if cursor_pos < 1 then
cursor_pos = 1
elseif cursor_pos > #self._private.text + 1 then
cursor_pos = #self._private.text + 1
end end
else self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
if key == "BackSpace" then self:emit_signal("inputbox::key_pressed", "Control", "Right")
end
},
akey {
modifiers = {},
key = "BackSpace", --BackSpace
on_press = function()
-- If text is highlighted delete that, else just delete the character to the left -- If text is highlighted delete that, else just delete the character to the left
if self._private.highlight and self._private.highlight.cur_pos_start and if self._private.highlight and self._private.highlight.cur_pos_start and
self._private.highlight.cur_pos_end then self._private.highlight.cur_pos_end then
@@ -395,12 +329,21 @@ function inputbox:run()
cursor_pos = #text_start + 1 cursor_pos = #text_start + 1
else else
if cursor_pos > 1 then if cursor_pos > 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 2) .. local offset = (self._private.text:sub(cursor_pos - 1, cursor_pos - 1):wlen() == -1) and 1 or
0
self:set_text(self._private.text:sub(1, cursor_pos - 2 - offset) ..
self._private.text:sub(cursor_pos)) self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos - 1 cursor_pos = cursor_pos - 1 - offset
end end
end end
elseif key == "Delete" then self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", nil, "BackSpace")
end
},
akey {
modifiers = {},
key = "Delete", --delete
on_press = function()
-- If text is highlighted delete that, else just delete the character to the right -- If text is highlighted delete that, else just delete the character to the right
if self._private.highlight and self._private.highlight.cur_pos_start and if self._private.highlight and self._private.highlight.cur_pos_start and
self._private.highlight.cur_pos_end then self._private.highlight.cur_pos_end then
@@ -415,42 +358,58 @@ function inputbox:run()
self._private.text:sub(cursor_pos + 1)) self._private.text:sub(cursor_pos + 1))
end end
end end
elseif key == "Left" then self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", nil, "Delete")
end
},
akey {
modifiers = {},
key = "Left", --left
on_press = function()
-- Move cursor ro the left -- Move cursor ro the left
if cursor_pos > 1 then if cursor_pos > 1 then
cursor_pos = cursor_pos - 1 cursor_pos = cursor_pos - 1
end end
self._private.highlight = {} self._private.highlight = {}
elseif key == "Right" then end
},
akey {
modifiers = {},
key = "Right", --right
on_press = function()
-- Move cursor to the right -- Move cursor to the right
if cursor_pos <= #self._private.text then if cursor_pos <= #self._private.text then
cursor_pos = cursor_pos + 1 cursor_pos = cursor_pos + 1
end end
self._private.highlight = {} self._private.highlight = {}
else end
-- Print every alphanumeric key },
-- It seems like gears.xmlescape doesn't support non alphanumeric characters --self.keybindings
},
keypressed_callback = function(_, modifiers, key)
if modifiers[1] == "Shift" then
if key:wlen() == 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
string.upper(key) .. self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos + #key
end
elseif modifiers[1] == "Mod2" or "" then
if key:wlen() == 1 then if key:wlen() == 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 1) .. self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
key .. self._private.text:sub(cursor_pos)) key .. self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos + 1 cursor_pos = cursor_pos + #key
end end
end end
-- Make sure the cursor cannot go out of bounds
if cursor_pos < 1 then if cursor_pos < 1 then
cursor_pos = 1 cursor_pos = 1
elseif cursor_pos > #self._private.text + 1 then elseif cursor_pos > #self._private.text + 1 then
cursor_pos = #self._private.text + 1 cursor_pos = #self._private.text + 1
end end
self.markup = text_with_cursor(self:get_text(), cursor_pos, self)
self:emit_signal("inputbox::key_pressed", modifiers, key)
end end
-- Update cycle
self:get_widget():update {
text = text_with_cursor(self:get_text(), cursor_pos, self)
} }
-- using self:emit_signal... results in nil tables beeing send
awesome.emit_signal("inputbox::key_pressed", mod_keys, key)
end)
end end
--- Creates a new inputbox widget --- Creates a new inputbox widget
@@ -467,51 +426,16 @@ end
-- @treturn awful.widget.inputbox The inputbox widget. -- @treturn awful.widget.inputbox The inputbox widget.
-- @constructorfct awful.widget.inputbox -- @constructorfct awful.widget.inputbox
function inputbox.new(args) function inputbox.new(args)
-- directly pass a possible default text(this is not meant to be a hint)
local w = textbox()
local w = base.make_widget(nil, nil, { enable_properties = true }) --gtable.crush(w, args)
gtable.crush(w, inputbox, true) gtable.crush(w, inputbox, true)
w:set_widget(wtemplate.make_from_value(args.widget_template)) w.keybindings = args.keybindings or {}
w.hint_text = args.hint_text
w:buttons( w.markup = args.text or text_with_cursor("", 1, w)
gtable.join {
abutton({}, 1, function()
w:focus()
end),
abutton({}, 3, function()
-- TODO: Figure out how to paste with highlighted support
-- Maybe with a signal?
end)
}
)
-- Change the cursor to "xterm" on hover over
local old_cursor, old_wibox
w:connect_signal(
"mouse::enter",
function()
local wid = capi.mouse.current_wibox
if wid then
old_cursor, old_wibox = wid.cursor, wid
wid.cursor = "xterm"
end
end
)
-- Change the cursor back once leaving the widget
w:connect_signal(
"mouse::leave",
function()
old_wibox.cursor = old_cursor
old_wibox = nil
end
)
-- Initialize the text and placeholder with a first update
w:get_widget():update {
text = text_with_cursor("", 1, w)
}
return w return w
end end

View File

@@ -0,0 +1,163 @@
local base = require("wibox.widget.base")
local gtable = require("gears.table")
local gcolor = require("gears.color")
local dpi = require("beautiful").xresources.apply_dpi
local wibox = require("wibox")
local gshape = require("gears.shape")
local rubato = require("src.lib.rubato")
local abutton = require("awful.button")
local toggle_widget = { mt = {} }
function toggle_widget:layout(_, width, height)
if self._private.widget then
return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
end
end
function toggle_widget:fit(context, width, height)
local w, h = 0, 0
if self._private.widget then
w, h = base.fit_widget(self, context, self._private.widget, width, height)
end
return w, h
end
toggle_widget.set_widget = base.set_widget_common
function toggle_widget:get_widget()
return self._private.widget
end
function toggle_widget:set_enabled()
self.active = true
self.toggle_button.border_color = self.color
self.newcolor = self.color
self.rubato_timed.target = 39
end
function toggle_widget:set_disabled()
self.active = not self.active
self.toggle_button.border_color = Theme_config.dnd.border_disabled
self.newcolor = Theme_config.dnd.disabled
self.rubato_timed.target = 5
end
function toggle_widget:toggle_animation(pos, color)
if pos > 39 then return end
return function(_, _, cr, width, height)
cr:set_source(gcolor(Theme_config.dnd.bg))
cr:paint()
cr:set_source(gcolor(color))
cr:move_to(pos, 0)
local x = pos
local y = 5
local newwidth = width / 2 - 10
local newheight = height - 10
local radius = height / 6.0
local degrees = math.pi / 180.0
cr:new_sub_path()
cr:arc(x + newwidth - radius, y + radius, radius, -90 * degrees, 0 * degrees)
cr:arc(x + newwidth - radius, y + newheight - radius, radius, 0 * degrees, 90 * degrees)
cr:arc(x + radius, y + newheight - radius, radius, 90 * degrees, 180 * degrees)
cr:arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
cr:close_path()
cr:fill()
end
end
function toggle_widget.new(args)
args = args or {}
local ret = base.make_widget(nil, nil, {
enable_properties = true,
})
gtable.crush(ret, toggle_widget, true)
ret.newcolor = Theme_config.dnd.disabled
ret.color = args.color
ret.toggle_button = wibox.widget {
{
widget = wibox.widget {
fit = function(_, width, height)
return width, height
end,
draw = ret:toggle_animation(0, ret.newcolor),
},
id = "background",
},
active = false,
widget = wibox.container.background,
bg = Theme_config.dnd.bg,
border_color = Theme_config.dnd.border_disabled,
border_width = dpi(2),
forced_height = args.size,
forced_width = args.size * 2,
shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(10))
end,
}
ret.rubato_timed = rubato.timed {
duration = 0.2,
pos = 5,
subscribed = function(pos)
ret.toggle_button:get_children_by_id("background")[1].draw = ret:toggle_animation(pos, ret.newcolor)
ret.toggle_button:emit_signal("widget::redraw_needed")
end
}
ret:set_widget(wibox.widget {
{
{
args.text and {
text = args.text,
valign = "center",
align = "center",
widget = wibox.widget.textbox,
id = "clearall"
} or nil,
ret.toggle_button,
spacing = args.text and dpi(10) or dpi(0),
layout = wibox.layout.fixed.horizontal,
id = "layout12"
},
id = "background4",
fg = args.fg,
shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(12))
end,
widget = wibox.container.background
},
id = "place",
widget = wibox.container.place,
valign = "bottom",
halign = "right",
})
ret.toggle_button:buttons(
gtable.join(
abutton({}, 1, function()
if ret.active then
ret:set_disabled()
else
ret:set_enabled()
end
ret:emit_signal("dnd::toggle", ret.active)
end
)
)
)
return ret
end
function toggle_widget.mt:__call(...)
return toggle_widget.new(...)
end
return setmetatable(toggle_widget, toggle_widget.mt)

View File

@@ -17,10 +17,9 @@ screen = screen
selection = selection selection = selection
tag = tag tag = tag
-- Do not touch as this is used to share some variables between files -- Do not touch as this is used to share some variable settings files
Global_config = {} Global_config = {}
require("src.theme.user_config") require("src.theme.user_config")
require("src.theme.theme_config") require("src.theme.theme_config")
require("src.tools.gio_icon_lookup") require("src.tools.gio_icon_lookup")
@@ -33,6 +32,4 @@ require("src.core.rules")
require("src.bindings.global_buttons") require("src.bindings.global_buttons")
require("src.bindings.bind_to_tags") require("src.bindings.bind_to_tags")
require("src.modules.init") require("src.modules.init")
require("src.tools.helpers.init")
--require("src.tools.auto_starter")(User_config.autostart) --require("src.tools.auto_starter")(User_config.autostart)
--require("src.tools.dbus.bluetooth_dbus")()

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M2,7V8.5H3V17H4.5V7C3.7,7 2.8,7 2,7M6,7V7L6,16H7V17H14V16H22V7H6M17.5,9A2.5,2.5 0 0,1 20,11.5A2.5,2.5 0 0,1 17.5,14A2.5,2.5 0 0,1 15,11.5A2.5,2.5 0 0,1 17.5,9Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M2,7V8.5H3V17H4.5V7C3.7,7 2.8,7 2,7M6,7V7L6,16H7V17H14V16H22V7H6M17.5,9A2.5,2.5 0 0,1 20,11.5A2.5,2.5 0 0,1 17.5,14A2.5,2.5 0 0,1 15,11.5A2.5,2.5 0 0,1 17.5,9Z" />
</svg>

Before

Width:  |  Height:  |  Size: 454 B

After

Width:  |  Height:  |  Size: 463 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,1C7,1 3,5 3,10V17A3,3 0 0,0 6,20H9V12H5V10A7,7 0 0,1 12,3A7,7 0 0,1 19,10V12H15V20H18A3,3 0 0,0 21,17V10C21,5 16.97,1 12,1Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M12,1C7,1 3,5 3,10V17A3,3 0 0,0 6,20H9V12H5V10A7,7 0 0,1 12,3A7,7 0 0,1 19,10V12H15V20H18A3,3 0 0,0 21,17V10C21,5 16.97,1 12,1Z" />
</svg>

Before

Width:  |  Height:  |  Size: 422 B

After

Width:  |  Height:  |  Size: 431 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,1C7,1 3,5 3,10V17A3,3 0 0,0 6,20H9V12H5V10A7,7 0 0,1 12,3A7,7 0 0,1 19,10V12H15V20H19V21H12V23H18A3,3 0 0,0 21,20V10C21,5 16.97,1 12,1Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M12,1C7,1 3,5 3,10V17A3,3 0 0,0 6,20H9V12H5V10A7,7 0 0,1 12,3A7,7 0 0,1 19,10V12H15V20H19V21H12V23H18A3,3 0 0,0 21,20V10C21,5 16.97,1 12,1Z" />
</svg>

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 443 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,5.83L14.88,7.71L13.28,9.31L14.69,10.72L17.71,7.7L12,2H11V7.03L13,9.03M5.41,4L4,5.41L10.59,12L5,17.59L6.41,19L11,14.41V22H12L16.29,17.71L18.59,20L20,18.59M13,18.17V14.41L14.88,16.29" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M13,5.83L14.88,7.71L13.28,9.31L14.69,10.72L17.71,7.7L12,2H11V7.03L13,9.03M5.41,4L4,5.41L10.59,12L5,17.59L6.41,19L11,14.41V22H12L16.29,17.71L18.59,20L20,18.59M13,18.17V14.41L14.88,16.29" />
</svg>

Before

Width:  |  Height:  |  Size: 479 B

After

Width:  |  Height:  |  Size: 486 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M14.88,16.29L13,18.17V14.41M13,5.83L14.88,7.71L13,9.58M17.71,7.71L12,2H11V9.58L6.41,5L5,6.41L10.59,12L5,17.58L6.41,19L11,14.41V22H12L17.71,16.29L13.41,12L17.71,7.71Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M14.88,16.29L13,18.17V14.41M13,5.83L14.88,7.71L13,9.58M17.71,7.71L12,2H11V9.58L6.41,5L5,6.41L10.59,12L5,17.58L6.41,19L11,14.41V22H12L17.71,16.29L13.41,12L17.71,7.71Z" />
</svg>

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 467 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,5H7L9,3H15L17,5H20A2,2 0 0,1 22,7V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V7A2,2 0 0,1 4,5M13.09,9.45L11.05,12.18L12.6,14.25L11.73,14.91L9.27,11.64L6,16H18L13.09,9.45Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M4,5H7L9,3H15L17,5H20A2,2 0 0,1 22,7V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V7A2,2 0 0,1 4,5M13.09,9.45L11.05,12.18L12.6,14.25L11.73,14.91L9.27,11.64L6,16H18L13.09,9.45Z" />
</svg>

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 469 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z" />
</svg>

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,6H20V16H4M20,18A2,2 0 0,0 22,16V6C22,4.89 21.1,4 20,4H4C2.89,4 2,4.89 2,6V16A2,2 0 0,0 4,18H0V20H24V18H20Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M4,6H20V16H4M20,18A2,2 0 0,0 22,16V6C22,4.89 21.1,4 20,4H4C2.89,4 2,4.89 2,6V16A2,2 0 0,0 4,18H0V20H24V18H20Z" />
</svg>

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 413 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6,19C6,20.1 6.9,21 8,21H16C17.1,21 18,20.1 18,19V7H6V19M8,9H16V19H8V9M15.5,4L14.5,3H9.5L8.5,4H5V6H19V4H15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 188 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.06,9L15,9.94L5.92,19H5V18.08L14.06,9M17.66,3C17.41,3 17.15,3.1 16.96,3.29L15.13,5.12L18.88,8.87L20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18.17,3.09 17.92,3 17.66,3M14.06,6.19L3,17.25V21H6.75L17.81,9.94L14.06,6.19Z" /></svg>

After

Width:  |  Height:  |  Size: 305 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M7.97,16L5,19C4.67,19.3 4.23,19.5 3.75,19.5A1.75,1.75 0 0,1 2,17.75V17.5L3,10.12C3.21,7.81 5.14,6 7.5,6H16.5C18.86,6 20.79,7.81 21,10.12L22,17.5V17.75A1.75,1.75 0 0,1 20.25,19.5C19.77,19.5 19.33,19.3 19,19L16.03,16H7.97M7,8V10H5V11H7V13H8V11H10V10H8V8H7M16.5,8A0.75,0.75 0 0,0 15.75,8.75A0.75,0.75 0 0,0 16.5,9.5A0.75,0.75 0 0,0 17.25,8.75A0.75,0.75 0 0,0 16.5,8M14.75,9.75A0.75,0.75 0 0,0 14,10.5A0.75,0.75 0 0,0 14.75,11.25A0.75,0.75 0 0,0 15.5,10.5A0.75,0.75 0 0,0 14.75,9.75M18.25,9.75A0.75,0.75 0 0,0 17.5,10.5A0.75,0.75 0 0,0 18.25,11.25A0.75,0.75 0 0,0 19,10.5A0.75,0.75 0 0,0 18.25,9.75M16.5,11.5A0.75,0.75 0 0,0 15.75,12.25A0.75,0.75 0 0,0 16.5,13A0.75,0.75 0 0,0 17.25,12.25A0.75,0.75 0 0,0 16.5,11.5Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M7.97,16L5,19C4.67,19.3 4.23,19.5 3.75,19.5A1.75,1.75 0 0,1 2,17.75V17.5L3,10.12C3.21,7.81 5.14,6 7.5,6H16.5C18.86,6 20.79,7.81 21,10.12L22,17.5V17.75A1.75,1.75 0 0,1 20.25,19.5C19.77,19.5 19.33,19.3 19,19L16.03,16H7.97M7,8V10H5V11H7V13H8V11H10V10H8V8H7M16.5,8A0.75,0.75 0 0,0 15.75,8.75A0.75,0.75 0 0,0 16.5,9.5A0.75,0.75 0 0,0 17.25,8.75A0.75,0.75 0 0,0 16.5,8M14.75,9.75A0.75,0.75 0 0,0 14,10.5A0.75,0.75 0 0,0 14.75,11.25A0.75,0.75 0 0,0 15.5,10.5A0.75,0.75 0 0,0 14.75,9.75M18.25,9.75A0.75,0.75 0 0,0 17.5,10.5A0.75,0.75 0 0,0 18.25,11.25A0.75,0.75 0 0,0 19,10.5A0.75,0.75 0 0,0 18.25,9.75M16.5,11.5A0.75,0.75 0 0,0 15.75,12.25A0.75,0.75 0 0,0 16.5,13A0.75,0.75 0 0,0 17.25,12.25A0.75,0.75 0 0,0 16.5,11.5Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1006 B

After

Width:  |  Height:  |  Size: 1015 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,10H17V8H19M19,13H17V11H19M16,10H14V8H16M16,13H14V11H16M16,17H8V15H16M7,10H5V8H7M7,13H5V11H7M8,11H10V13H8M8,8H10V10H8M11,11H13V13H11M11,8H13V10H11M20,5H4C2.89,5 2,5.89 2,7V17A2,2 0 0,0 4,19H20A2,2 0 0,0 22,17V7C22,5.89 21.1,5 20,5Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M19,10H17V8H19M19,13H17V11H19M16,10H14V8H16M16,13H14V11H16M16,17H8V15H16M7,10H5V8H7M7,13H5V11H7M8,11H10V13H8M8,8H10V10H8M11,11H13V13H11M11,8H13V10H11M20,5H4C2.89,5 2,5.89 2,7V17A2,2 0 0,0 4,19H20A2,2 0 0,0 22,17V7C22,5.89 21.1,5 20,5Z" />
</svg>

Before

Width:  |  Height:  |  Size: 529 B

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M11,1.07C7.05,1.56 4,4.92 4,9H11M4,15A8,8 0 0,0 12,23A8,8 0 0,0 20,15V11H4M13,1.07V9H20C20,4.92 16.94,1.56 13,1.07Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M11,1.07C7.05,1.56 4,4.92 4,9H11M4,15A8,8 0 0,0 12,23A8,8 0 0,0 20,15V11H4M13,1.07V9H20C20,4.92 16.94,1.56 13,1.07Z" />
</svg>

Before

Width:  |  Height:  |  Size: 410 B

After

Width:  |  Height:  |  Size: 419 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,18H5V6H19M21,4H3C1.89,4 1,4.89 1,6V18A2,2 0 0,0 3,20H21A2,2 0 0,0 23,18V6C23,4.89 22.1,4 21,4Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M19,18H5V6H19M21,4H3C1.89,4 1,4.89 1,6V18A2,2 0 0,0 3,20H21A2,2 0 0,0 23,18V6C23,4.89 22.1,4 21,4Z" />
</svg>

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 402 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.43 19.12,14.63 17.79,15L19.25,16.44C20.88,15.61 22,13.95 22,12A5,5 0 0,0 17,7M16,11H13.81L15.81,13H16V11M2,4.27L5.11,7.38C3.29,8.12 2,9.91 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12C3.9,10.41 5.11,9.1 6.66,8.93L8.73,11H8V13H10.73L13,15.27V17H14.73L18.74,21L20,19.74L3.27,3L2,4.27Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.43 19.12,14.63 17.79,15L19.25,16.44C20.88,15.61 22,13.95 22,12A5,5 0 0,0 17,7M16,11H13.81L15.81,13H16V11M2,4.27L5.11,7.38C3.29,8.12 2,9.91 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12C3.9,10.41 5.11,9.1 6.66,8.93L8.73,11H8V13H10.73L13,15.27V17H14.73L18.74,21L20,19.74L3.27,3L2,4.27Z" />
</svg>

Before

Width:  |  Height:  |  Size: 642 B

After

Width:  |  Height:  |  Size: 649 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M3.9,12C3.9,10.29 5.29,8.9 7,8.9H11V7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12M8,13H16V11H8V13M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.71 18.71,15.1 17,15.1H13V17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M3.9,12C3.9,10.29 5.29,8.9 7,8.9H11V7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12M8,13H16V11H8V13M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.71 18.71,15.1 17,15.1H13V17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7Z" />
</svg>

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 539 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M7,10L12,15L17,10H7Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M7,10L12,15L17,10H7Z" />
</svg>

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 322 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M7,15L12,10L17,15H7Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M7,15L12,10L17,15H7Z" />
</svg>

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 322 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,2.05V4.05C17.39,4.59 20.5,8.58 19.96,12.97C19.5,16.61 16.64,19.5 13,19.93V21.93C18.5,21.38 22.5,16.5 21.95,11C21.5,6.25 17.73,2.5 13,2.03V2.05M5.67,19.74C7.18,21 9.04,21.79 11,22V20C9.58,19.82 8.23,19.25 7.1,18.37L5.67,19.74M7.1,5.74C8.22,4.84 9.57,4.26 11,4.06V2.06C9.05,2.25 7.19,3 5.67,4.26L7.1,5.74M5.69,7.1L4.26,5.67C3,7.19 2.25,9.04 2.05,11H4.05C4.24,9.58 4.8,8.23 5.69,7.1M4.06,13H2.06C2.26,14.96 3.03,16.81 4.27,18.33L5.69,16.9C4.81,15.77 4.24,14.42 4.06,13M10,16.5L16,12L10,7.5V16.5Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M13,2.05V4.05C17.39,4.59 20.5,8.58 19.96,12.97C19.5,16.61 16.64,19.5 13,19.93V21.93C18.5,21.38 22.5,16.5 21.95,11C21.5,6.25 17.73,2.5 13,2.03V2.05M5.67,19.74C7.18,21 9.04,21.79 11,22V20C9.58,19.82 8.23,19.25 7.1,18.37L5.67,19.74M7.1,5.74C8.22,4.84 9.57,4.26 11,4.06V2.06C9.05,2.25 7.19,3 5.67,4.26L7.1,5.74M5.69,7.1L4.26,5.67C3,7.19 2.25,9.04 2.05,11H4.05C4.24,9.58 4.8,8.23 5.69,7.1M4.06,13H2.06C2.26,14.96 3.03,16.81 4.27,18.33L5.69,16.9C4.81,15.77 4.24,14.42 4.06,13M10,16.5L16,12L10,7.5V16.5Z" />
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 800 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,3C7.79,3 3.7,4.41 0.38,7C4.41,12.06 7.89,16.37 12,21.5C16.08,16.42 20.24,11.24 23.65,7C20.32,4.41 16.22,3 12,3Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M12,3C7.79,3 3.7,4.41 0.38,7C4.41,12.06 7.89,16.37 12,21.5C16.08,16.42 20.24,11.24 23.65,7C20.32,4.41 16.22,3 12,3Z" />
</svg>

Before

Width:  |  Height:  |  Size: 410 B

After

Width:  |  Height:  |  Size: 419 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17,19H7V5H17M17,1H7C5.89,1 5,1.89 5,3V21A2,2 0 0,0 7,23H17A2,2 0 0,0 19,21V3C19,1.89 18.1,1 17,1Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M17,19H7V5H17M17,1H7C5.89,1 5,1.89 5,3V21A2,2 0 0,0 7,23H17A2,2 0 0,0 19,21V3C19,1.89 18.1,1 17,1Z" />
</svg>

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 402 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16.56,5.44L15.11,6.89C16.84,7.94 18,9.83 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12C6,9.83 7.16,7.94 8.88,6.88L7.44,5.44C5.36,6.88 4,9.28 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,9.28 18.64,6.88 16.56,5.44M13,3H11V13H13" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
<path d="M16.56,5.44L15.11,6.89C16.84,7.94 18,9.83 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12C6,9.83 7.16,7.94 8.88,6.88L7.44,5.44C5.36,6.88 4,9.28 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,9.28 18.64,6.88 16.56,5.44M13,3H11V13H13" />
</svg>

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 515 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M18,3H6V7H18M19,12A1,1 0 0,1 18,11A1,1 0 0,1 19,10A1,1 0 0,1 20,11A1,1 0 0,1 19,12M16,19H8V14H16M19,8H5A3,3 0 0,0 2,11V17H6V21H18V17H22V11A3,3 0 0,0 19,8Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M18,3H6V7H18M19,12A1,1 0 0,1 18,11A1,1 0 0,1 19,10A1,1 0 0,1 20,11A1,1 0 0,1 19,12M16,19H8V14H16M19,8H5A3,3 0 0,0 2,11V17H6V21H18V17H22V11A3,3 0 0,0 19,8Z" />
</svg>

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 458 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" /></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" />
</svg>

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4.2,10.7L19.8,5L20.5,6.9L6.4,12H19A2,2 0 0,1 21,14V18A2,2 0 0,1 19,20H5A2,2 0 0,1 3,18V12.5C3,11.7 3.5,10.9 4.2,10.7M17,17H19V15H17V17M5,17H15V15H5V17Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M4.2,10.7L19.8,5L20.5,6.9L6.4,12H19A2,2 0 0,1 21,14V18A2,2 0 0,1 19,20H5A2,2 0 0,1 3,18V12.5C3,11.7 3.5,10.9 4.2,10.7M17,17H19V15H17V17M5,17H15V15H5V17Z" />
</svg>

Before

Width:  |  Height:  |  Size: 447 B

After

Width:  |  Height:  |  Size: 456 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,17H3V5H21M21,3H3A2,2 0 0,0 1,5V17A2,2 0 0,0 3,19H8V21H16V19H21A2,2 0 0,0 23,17V5A2,2 0 0,0 21,3Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M21,17H3V5H21M21,3H3A2,2 0 0,0 1,5V17A2,2 0 0,0 3,19H8V21H16V19H21A2,2 0 0,0 23,17V5A2,2 0 0,0 21,3Z" />
</svg>

Before

Width:  |  Height:  |  Size: 395 B

After

Width:  |  Height:  |  Size: 404 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23,12L20.6,9.2L20.9,5.5L17.3,4.7L15.4,1.5L12,3L8.6,1.5L6.7,4.7L3.1,5.5L3.4,9.2L1,12L3.4,14.8L3.1,18.5L6.7,19.3L8.6,22.5L12,21L15.4,22.5L17.3,19.3L20.9,18.5L20.6,14.8L23,12M18.7,16.9L16,17.5L14.6,19.9L12,18.8L9.4,19.9L8,17.5L5.3,16.9L5.5,14.1L3.7,12L5.5,9.9L5.3,7.1L8,6.5L9.4,4.1L12,5.2L14.6,4.1L16,6.5L18.7,7.1L18.5,9.9L20.3,12L18.5,14.1L18.7,16.9M16.6,7.6L18,9L10,17L6,13L7.4,11.6L10,14.2L16.6,7.6Z" /></svg>

After

Width:  |  Height:  |  Size: 479 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23,12L20.56,14.78L20.9,18.46L17.29,19.28L15.4,22.46L12,21L8.6,22.47L6.71,19.29L3.1,18.47L3.44,14.78L1,12L3.44,9.21L3.1,5.53L6.71,4.72L8.6,1.54L12,3L15.4,1.54L17.29,4.72L20.9,5.54L20.56,9.22L23,12M20.33,12L18.5,9.89L18.74,7.1L16,6.5L14.58,4.07L12,5.18L9.42,4.07L8,6.5L5.26,7.09L5.5,9.88L3.67,12L5.5,14.1L5.26,16.9L8,17.5L9.42,19.93L12,18.81L14.58,19.92L16,17.5L18.74,16.89L18.5,14.1L20.33,12Z" /></svg>

After

Width:  |  Height:  |  Size: 471 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" />
</svg>

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 425 B

View File

@@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,12A6,6 0 0,1 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12M20,12C20,9.45 18.81,7.19 16.95,5.73L16,0H8L7.05,5.73C5.19,7.19 4,9.45 4,12C4,14.54 5.19,16.81 7.05,18.27L8,24H16L16.95,18.27C18.81,16.81 20,14.54 20,12Z" /></svg> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 24 24">
<path d="M6,12A6,6 0 0,1 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12M20,12C20,9.45 18.81,7.19 16.95,5.73L16,0H8L7.05,5.73C5.19,7.19 4,9.45 4,12C4,14.54 5.19,16.81 7.05,18.27L8,24H16L16.95,18.27C18.81,16.81 20,14.54 20,12Z" />
</svg>

Before

Width:  |  Height:  |  Size: 515 B

After

Width:  |  Height:  |  Size: 524 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#00000000">
<path d="M0 0h24v24H0z" />
<path fill="#f5f5f5" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
</svg>

After

Width:  |  Height:  |  Size: 273 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" />
</svg>

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -8,6 +8,7 @@ local gears = require("gears")
local menubar = require('menubar') local menubar = require('menubar')
local naughty = require("naughty") local naughty = require("naughty")
local wibox = require("wibox") local wibox = require("wibox")
local wtemplate = require("wibox.template")
local rubato = require("src.lib.rubato") local rubato = require("src.lib.rubato")
@@ -64,7 +65,7 @@ naughty.connect_signal(
n.message = string.format("<span foreground='%s'>%s</span>", Theme_config.notification.fg_normal_message, n.message = string.format("<span foreground='%s'>%s</span>", Theme_config.notification.fg_normal_message,
n.message) or "" n.message) or ""
n.bg = Theme_config.notification.bg_normal n.bg = Theme_config.notification.bg_normal
n.timeout = n.timeout or Theme_config.notification.timeout n.timeout = n.timeout or Theme_config.notification.timeout or 3
end end
local use_image = false local use_image = false
@@ -91,10 +92,10 @@ naughty.connect_signal(
use_image = true use_image = true
end end
local action_template_widget = {} local action_template_widget
if use_image then if use_image then
action_template_widget = { action_template_widget = wibox.template {
{ {
{ {
{ {
@@ -127,7 +128,7 @@ naughty.connect_signal(
widget = wibox.container.margin widget = wibox.container.margin
} }
else else
action_template_widget = { action_template_widget = wibox.template {
{ {
{ {
{ {
@@ -176,7 +177,8 @@ naughty.connect_signal(
arc_start = 10 arc_start = 10
end end
local w_template = wibox.widget { local w_template = wibox.template {
widget = wibox.widget {
{ {
{ {
{ {
@@ -339,9 +341,13 @@ naughty.connect_signal(
border_width = Theme_config.notification.border_width, border_width = Theme_config.notification.border_width,
shape = Theme_config.notification.shape_inside, shape = Theme_config.notification.shape_inside,
widget = wibox.container.background widget = wibox.container.background
} },
update_callback = function()
local close = w_template:get_children_by_id("background1")[1] end
}
local close = w_template:get_widget().max_size.min_size.widget_layout.arc_app_bg.arc_app_layout.arc_app_layout_2.arc_margin
.const1.background1
local arc = close.arc_chart local arc = close.arc_chart
local timeout = n.timeout local timeout = n.timeout
@@ -359,7 +365,7 @@ naughty.connect_signal(
rubato_timer.target = 0 rubato_timer.target = 0
w_template:connect_signal( w_template:get_widget():connect_signal(
"mouse::enter", "mouse::enter",
function() function()
n.timeout = 99999 n.timeout = 99999
@@ -367,7 +373,7 @@ naughty.connect_signal(
end end
) )
w_template:connect_signal( w_template:get_widget():connect_signal(
"mouse::leave", "mouse::leave",
function() function()
n.timeout = rubato_timer.pos n.timeout = rubato_timer.pos
@@ -379,16 +385,11 @@ naughty.connect_signal(
Hover_signal(close) Hover_signal(close)
close:connect_signal( close:connect_signal("button::press", function()
"button::press",
function()
n:destroy() n:destroy()
end end)
)
w_template:connect_signal( w_template:get_widget():connect_signal("button::press", function(_, _, _, key)
"button::press",
function(_, _, _, key)
if key == 3 then if key == 3 then
n:destroy() n:destroy()
end end
@@ -404,8 +405,7 @@ naughty.connect_signal(
end end
end end
end end
end end)
)
local box = naughty.layout.box { local box = naughty.layout.box {
notification = n, notification = n,

View File

@@ -34,13 +34,6 @@ capi.client.connect_signal(
if capi.awesome.startup and not c.size_hints.user_porition and not c.size_hints.program_position then if capi.awesome.startup and not c.size_hints.user_porition and not c.size_hints.program_position then
awful.placement.no_offscreen(c) awful.placement.no_offscreen(c)
end end
c.shape = function(cr, width, height)
if c.fullscreen or c.maximized then
gears.shape.rectangle(cr, width, height)
else
gears.shape.rounded_rect(cr, width, height, 10)
end
end
if c.class == "Brave-browser" then if c.class == "Brave-browser" then
c.floating = false c.floating = false
end end

View File

@@ -1,135 +0,0 @@
local awful = require("awful")
local gears = require("gears")
local dbus_proxy = require("src.lib.dbus_proxy")
local lgi = require("lgi")
local naughty = require("naughty")
return function()
local function get_device_info(object_path)
if object_path ~= nil and object_path:match("/org/bluez/hci0/dev") then
local device = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.bluez.Device1",
path = object_path
}
local battery = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.bluez.Battery1",
path = object_path
}
local device_properties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.Properties",
path = object_path
}
awesome.emit_signal("bluetooth::scan")
if device.Name ~= nil or device.Alias ~= nil then
device_properties:connect_signal(function()
awesome.emit_signal("bluetooth::device_changed", device, battery)
end, "PropertiesChanged")
awesome.emit_signal("bluetooth::device_changed", device, battery)
end
end
end
awful.spawn.easy_async_with_shell(
"lsusb | grep Bluetooth",
function(stdout)
stdout = stdout:gsub("\n", "")
if stdout ~= "" or stdout == nil then
local ObjectManager = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.ObjectManager",
path = "/"
}
local Adapter = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.bluez.Adapter1",
path = "/org/bluez/hci0"
}
local AdapterProperties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.Properties",
path = "/org/bluez/hci0"
}
ObjectManager:connect_signal(
function(interface)
get_device_info(interface)
end,
"InterfacesAdded"
)
ObjectManager:connect_signal(
function(interface)
awesome.emit_signal("device_removed", interface)
end,
"InterfacesRemoved"
)
Adapter:connect_signal(
function(data)
if data.Powered ~= nil then
awesome.emit_signal("state", data.Powered)
end
end,
"PropertiesChanged"
)
awesome.connect_signal(
"bluetooth::scan",
function()
Adapter:StartDiscovery()
end
)
AdapterProperties:connect_signal(
function(data)
if data.Powered ~= nil then
if data.Powered then
Adapter:StartDiscovery()
end
end
end,
"PropertiesChanged"
)
awesome.connect_signal("toggle_bluetooth",
function()
local is_powered = Adapter.Powered
Adapter:Set(
"org.bluez.Adapter1",
"Powered",
lgi.GLib.Variant("b", not is_powered)
)
Adapter.Powered = { signature = "b", value = not is_powered }
awesome.emit_signal("state", Adapter.Powered)
end)
gears.timer.delayed_call(
function()
local objects = ObjectManager:GetManagedObjects()
for object_path, _ in pairs(objects) do
get_device_info(object_path)
end
awesome.emit_signal("state", Adapter.Powered)
end
)
end
end
)
end

View File

@@ -44,6 +44,47 @@ function application_grid:get_widget()
return self._private.widget return self._private.widget
end end
local function levenshtein_distance(str1, str2)
local len1 = string.len(str1)
local len2 = string.len(str2)
local matrix = {}
local cost = 0
if (len1 == 0) then
return len2
elseif (len2 == 0) then
return len1
elseif (str1 == str2) then
return 0
end
for i = 0, len1, 1 do
matrix[i] = {}
matrix[i][0] = i
end
for j = 0, len2, 1 do
matrix[0][j] = j
end
for i = 1, len1, 1 do
for j = 1, len2, 1 do
if str1:byte(i) == str2:byte(j) then
cost = 0
else
cost = 1
end
matrix[i][j] = math.min(
matrix[i - 1][j] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j - 1] + cost
)
end
end
return matrix[len1][len2]
end
function application_grid:get_applications_from_file() function application_grid:get_applications_from_file()
local list = {} local list = {}
local app_info = Gio.AppInfo local app_info = Gio.AppInfo
@@ -101,6 +142,7 @@ function application_grid:get_applications_from_file()
border_width = Theme_config.application_launcher.application.border_width, border_width = Theme_config.application_launcher.application.border_width,
bg = Theme_config.application_launcher.application.bg, bg = Theme_config.application_launcher.application.bg,
fg = Theme_config.application_launcher.application.fg, fg = Theme_config.application_launcher.application.fg,
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "",
shape = function(cr, width, height) shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8)) gears.shape.rounded_rect(cr, width, height, dpi(8))
end, end,
@@ -256,29 +298,64 @@ function application_grid:set_applications(search_filter)
layout = wibox.layout.grid layout = wibox.layout.grid
} }
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json"
if not gfilesystem.file_readable(dir) then return end
local handler = io.open(dir, "r")
if not handler then return end
local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
local mylist = {}
for _, application in ipairs(self.app_list) do for _, application in ipairs(self.app_list) do
-- Match the filter -- Match the filter
if string.match(string.lower(application.name or ""), string.lower(filter)) or if string.match(string.lower(application.name or ""), string.lower(filter)) or
string.match(string.lower(application.categories or ""), string.lower(filter)) or string.match(string.lower(application.categories or ""), string.lower(filter)) or
string.match(string.lower(application.keywords or ""), string.lower(filter)) then string.match(string.lower(application.keywords or ""), string.lower(filter)) then
grid:add(application)
-- Get the current position in the grid of the application as a table if #dock == 0 then
local pos = grid:get_widget_position(application) application.counter = 0
end
for _, app in ipairs(dock) do
if app.desktop_file == application.desktop_file then
application.counter = app.counter or 0
break;
else
application.counter = 0
end
end
-- Check if the curser is currently at the same position as the application table.insert(mylist, application)
end
end
table.sort(mylist, function(a, b)
return levenshtein_distance(filter, a.name) < levenshtein_distance(filter, b.name)
end)
--sort mytable by counter
table.sort(mylist, function(a, b)
return a.counter > b.counter
end)
for _, app in ipairs(mylist) do
grid:add(app)
-- Get the current position in the grid of the app as a table
local pos = grid:get_widget_position(app)
-- Check if the curser is currently at the same position as the app
capi.awesome.connect_signal( capi.awesome.connect_signal(
"update::selected", "update::selected",
function() function()
if self._private.curser.y == pos.row and self._private.curser.x == pos.col then if self._private.curser.y == pos.row and self._private.curser.x == pos.col then
application.border_color = Theme_config.application_launcher.application.border_color_active app.border_color = Theme_config.application_launcher.application.border_color_active
else else
application.border_color = Theme_config.application_launcher.application.border_color app.border_color = Theme_config.application_launcher.application.border_color
end end
end end
) )
end end
end
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
self:set_widget(grid) self:set_widget(grid)
end end
@@ -292,7 +369,6 @@ function application_grid:move_up()
end end
function application_grid:move_down() function application_grid:move_down()
print(self._private.curser.y)
self._private.curser.y = self._private.curser.y + 1 self._private.curser.y = self._private.curser.y + 1
local grid_rows, _ = self:get_widget():get_dimension() local grid_rows, _ = self:get_widget():get_dimension()
if self._private.curser.y > grid_rows then if self._private.curser.y > grid_rows then
@@ -322,6 +398,35 @@ function application_grid:execute()
local selected_widget = self:get_widget():get_widgets_at(self._private.curser.y, local selected_widget = self:get_widget():get_widgets_at(self._private.curser.y,
self._private.curser.x)[1] self._private.curser.x)[1]
Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0)) Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0))
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json"
if not gfilesystem.file_readable(dir) then return end
local handler = io.open(dir, "r")
if not handler then return end
local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
for _, prog in ipairs(dock) do
if prog.desktop_file:match(selected_widget.desktop_file) then
prog.counter = prog.counter + 1
goto continue
end
end
do
local prog = {
name = selected_widget.name,
desktop_file = selected_widget.desktop_file,
counter = 1
}
table.insert(dock, prog)
end
::continue::
handler:close()
handler = io.open(dir, "w")
if not handler then return end
handler:write(json:encode_pretty(dock))
handler:close()
end end
function application_grid:reset() function application_grid:reset()
@@ -344,10 +449,17 @@ function application_grid.new(args)
y = 1 y = 1
} }
-- Create folder and file if it doesn't exist
local dir = gfilesystem.get_configuration_dir() .. "src/config"
gfilesystem.make_directories(dir)
dir = dir .. "/applications.json"
if not gfilesystem.file_readable(dir) then
os.execute("touch " .. dir)
end
w:get_applications_from_file() w:get_applications_from_file()
w:set_applications() w:set_applications()
return w return w
end end

View File

@@ -10,6 +10,7 @@ local wibox = require("wibox")
local gshape = require("gears.shape") local gshape = require("gears.shape")
local gtable = require("gears.table") local gtable = require("gears.table")
local gobject = require("gears.object") local gobject = require("gears.object")
local abutton = require("awful.button")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
@@ -18,39 +19,6 @@ local capi = {
local application_launcher = { mt = {} } local application_launcher = { mt = {} }
application_launcher.searchbar = awful.widget.inputbox {
widget_template = wibox.template {
widget = wibox.widget {
{
{
{
widget = wibox.widget.textbox,
halign = "left",
valign = "center",
id = "text_role",
},
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = "#212121",
fg = "#F0F0F0",
border_color = "#414141",
border_width = 2,
shape = gshape.rounded_rect,
},
update_callback = function(template_widget, args)
template_widget.widget.const.marg.text_role.markup = args.text
end
}
}
application_launcher.application_grid = require("src.modules.application_launcher.application") {} application_launcher.application_grid = require("src.modules.application_launcher.application") {}
@@ -62,10 +30,58 @@ function application_launcher.new(args)
gtable.crush(ret, application_launcher, true) gtable.crush(ret, application_launcher, true)
local searchbar = awful.widget.inputbox {
hint_text = "Search...",
valign = "center",
halign = "left",
}
searchbar:buttons(
gtable.join {
abutton({}, 1, function()
searchbar:focus()
end)
}
)
local old_cursor, old_wibox
searchbar:connect_signal("mouse::enter", function()
local wid = capi.mouse.current_wibox
if wid then
old_cursor, old_wibox = wid.cursor, wid
wid.cursor = "xterm"
end
end)
searchbar:connect_signal("mouse::leave", function()
old_wibox.cursor = old_cursor
old_wibox = nil
end)
local applicaton_launcher = wibox.widget { local applicaton_launcher = wibox.widget {
{ {
{ {
ret.searchbar, {
{
{
searchbar,
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
shape = gshape.rounded_rect,
id = "searchbar_bg"
},
{ {
ret.application_grid, ret.application_grid,
spacing = dpi(10), spacing = dpi(10),
@@ -101,52 +117,70 @@ function application_launcher.new(args)
border_width = Theme_config.application_launcher.border_width border_width = Theme_config.application_launcher.border_width
} }
local searchbar_bg = applicaton_launcher:get_children_by_id("searchbar_bg")[1]
capi.awesome.connect_signal( capi.awesome.connect_signal(
"application_launcher::show", "application_launcher::show",
function() function()
capi.awesome.emit_signal("update::selected")
if capi.mouse.screen == args.screen then if capi.mouse.screen == args.screen then
ret.application_container.visible = not ret.application_container.visible ret.application_container.visible = not ret.application_container.visible
end end
if ret.application_container.visible then if ret.application_container.visible then
ret.searchbar:focus() searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar:focus()
else else
searchbar:set_text("")
awful.keygrabber.stop() awful.keygrabber.stop()
end end
end end
) )
ret.searchbar:connect_signal( searchbar:connect_signal(
"submit", "submit",
function(text) function(_, text)
ret.application_grid:execute() ret.application_grid:execute()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end
) )
ret.searchbar:connect_signal( searchbar:connect_signal(
"stopped", "stopped",
function() function(_, stop_key)
ret.searchbar:get_widget().widget.border_color = Theme_config.application_launcher.searchbar.border_color if stop_key == "Escape" then
capi.awesome.emit_signal("application_launcher::show")
end
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end
) )
ret.searchbar:connect_signal( searchbar:connect_signal(
"started", "started",
function() function()
ret.searchbar:get_widget().widget.border_color = Theme_config.application_launcher.searchbar.border_active searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
end end
) )
awesome.connect_signal( searchbar:connect_signal(
"inputbox::key_pressed", "inputbox::key_pressed",
function(modkey, key) function(_, modkey, key)
if key == "Escape" then if key == "Escape" then
ret.searchbar:stop() searchbar:stop()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() ret.application_grid:reset()
ret.searchbar:set_text("") searchbar:set_text("")
elseif key == "Down" or key == "Right" then elseif key == "Down" or key == "Right" then
ret.searchbar:stop() if key == "Down" then
ret.application_grid:move_down()
elseif key == "Right" then
ret.application_grid:move_right()
end
searchbar:stop()
awful.keygrabber.run(function(mod, key2, event) awful.keygrabber.run(function(mod, key2, event)
if event == "press" then if event == "press" then
if key2 == "Down" then if key2 == "Down" then
@@ -155,7 +189,7 @@ function application_launcher.new(args)
local old_y = ret.application_grid._private.curser.y local old_y = ret.application_grid._private.curser.y
ret.application_grid:move_up() ret.application_grid:move_up()
if old_y - ret.application_grid._private.curser.y == 0 then if old_y - ret.application_grid._private.curser.y == 0 then
ret.searchbar:focus() searchbar:focus()
end end
elseif key2 == "Left" then elseif key2 == "Left" then
ret.application_grid:move_left() ret.application_grid:move_left()
@@ -166,17 +200,20 @@ function application_launcher.new(args)
ret.application_grid:execute() ret.application_grid:execute()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() ret.application_grid:reset()
ret.searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
elseif key2 == "Escape" then elseif key2 == "Escape" then
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() ret.application_grid:reset()
ret.searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
awful.keygrabber.stop() awful.keygrabber.stop()
end end
end end
end) end)
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end
ret.application_grid:set_applications(ret.searchbar:get_text()) ret.application_grid:set_applications(searchbar:get_text())
end end
) )

View File

@@ -1,252 +0,0 @@
-------------------------------------------------------
-- This is the seachbar for the application launcher --
-------------------------------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local gstring = gears.string
local keygrabber = require("awful.keygrabber")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/application_launcher/searchbar/"
local kgrabber
return function()
local searchbar = wibox.widget {
{
{
{ -- Search icon
{
{
resize = false,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "search.svg",
Theme_config.application_launcher.searchbar.icon_color),
widget = wibox.widget.imagebox
},
bg = Theme_config.application_launcher.searchbar.icon_background,
widget = wibox.container.background
},
strategy = "exact",
width = dpi(30),
widget = wibox.container.constraint
},
{
{
fg = Theme_config.application_launcher.searchbar.fg_hint,
markup = "Search",
valign = "center",
align = "center",
widget = wibox.widget.textbox,
id = "search_hint"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "s_margin"
},
widget = wibox.layout.fixed.horizontal,
id = "s_layout"
},
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
widget = wibox.container.background,
shape = Theme_config.application_launcher.searchbar.shape,
id = "s_background"
},
width = dpi(400),
height = dpi(40),
strategy = "exact",
widget = wibox.container.constraint
}
local old_wibox, old_cursor
local mouse_enter = function()
local w = capi.mouse.current_wibox
if w then
old_cursor, old_wibox = w.cursor, w
w.cursor = "xterm"
end
end
local mouse_leave = function()
old_wibox.cursor = old_cursor
old_wibox = nil
end
searchbar:disconnect_signal("mouse::enter", mouse_enter)
searchbar:disconnect_signal("mouse::leave", mouse_leave)
searchbar:connect_signal("mouse::enter", mouse_enter)
searchbar:connect_signal("mouse::leave", mouse_leave)
local function have_multibyte_char_at(text, position)
return #text:sub(position, position) == -1
end
local search_text = searchbar:get_children_by_id("search_hint")[1]
local function promt_text_with_cursor(text, cursor_pos)
local char, spacer, text_start, text_end
local cursor_color = Theme_config.application_launcher.searchbar.bg_cursor
local text_color = Theme_config.application_launcher.searchbar.fg_cursor
if text == "" then
return "<span foreground='" .. Theme_config.application_launcher.searchbar.fg_hint .. "'>Search</span>"
end
if #text < cursor_pos then
char = " "
spacer = ""
text_start = gstring.xml_escape(text)
text_end = ""
else
local offset = 0
if have_multibyte_char_at(text, cursor_pos) then
offset = 1
end
char = gstring.xml_escape(text:sub(cursor_pos, cursor_pos + offset))
spacer = " "
text_start = gstring.xml_escape(text:sub(1, cursor_pos - 1))
text_end = gstring.xml_escape(text:sub(cursor_pos + offset + 1))
end
return text_start ..
"<span background='" ..
cursor_color .. "' foreground='" .. text_color .. "'>" .. char .. "</span>" .. text_end .. spacer
end
local text_string = ""
---Start a new keygrabber to simulate an input textbox
local function keygrabber_start()
local cur_pos = #text_string + 1
--Draws the string on each keypress
local function update()
search_text:set_markup(promt_text_with_cursor(text_string, cur_pos))
--Send the string over to the application to filter applications
capi.awesome.emit_signal("update::application_list", text_string)
end
update()
kgrabber = keygrabber.run(
function(modifiers, key, event)
capi.awesome.connect_signal("searchbar::stop", function()
keygrabber.stop(kgrabber)
capi.awesome.emit_signal("application_launcher::kgrabber_start")
end)
local mod = {}
for _, v in ipairs(modifiers) do
mod[v] = true
end
if event ~= "press" then
return
end
--Escape cases
if (mod.Control and (key == "c" or key == "g"))
or (not mod.Control and key == "Escape") then
keygrabber.stop(kgrabber)
search_text:set_markup(promt_text_with_cursor("", 1))
text_string = ""
capi.awesome.emit_signal("application_launcher::show")
elseif (not mod.Control and key == "Return") or
(not mod.Control and key == "KP_Enter") then
keygrabber.stop(kgrabber)
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_color
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg_hint
search_text:set_markup(promt_text_with_cursor("", 1))
text_string = ""
capi.awesome.emit_signal("application_launcher::execute")
capi.awesome.emit_signal("application_launcher::show")
end
if mod.Control then
elseif mod.Mod1 or mod.Mod3 then
else
--Delete character to the left and move cursor
if key == "BackSpace" then
if cur_pos > 1 then
local offset = 0
if have_multibyte_char_at(text_string, cur_pos - 1) then
offset = 1
end
text_string = text_string:sub(1, cur_pos - 2 - offset) .. text_string:sub(cur_pos)
cur_pos = cur_pos - 1 - offset
end
update()
--Delete character to the right
elseif key == "Delete" then
text_string = text_string:sub(1, cur_pos - 1) .. text_string:sub(cur_pos + 1)
update()
-- Move cursor to the left
elseif key == "Left" then
--cur_pos = cur_pos - 1
capi.awesome.emit_signal("application::left")
-- Move cursor to the right
elseif key == "Right" then
--cur_pos = cur_pos + 1
capi.awesome.emit_signal("application::right")
elseif key == "Up" then
capi.awesome.emit_signal("application::up")
elseif key == "Down" then
capi.awesome.emit_signal("application::down")
else
--Add key at cursor position
if key:wlen() == 1 then
text_string = text_string:sub(1, cur_pos - 1) .. key .. text_string:sub(cur_pos)
cur_pos = cur_pos + #key
end
update()
end
--Make sure cursor can't leave string bounds
if cur_pos < 1 then
cur_pos = 1
elseif cur_pos > #text_string + 1 then
cur_pos = #text_string + 1
end
end
end
)
end
--Start the keygrabber when the searchbar is left clicked
searchbar:buttons(gears.table.join(
awful.button({}, 1, function()
if not awful.keygrabber.is_running then
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg
search_text:set_markup(promt_text_with_cursor("", 1))
end
end)
))
capi.awesome.connect_signal(
"searchbar::start",
function()
if not awful.keygrabber.is_running then
keygrabber_start()
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg
search_text:set_markup(promt_text_with_cursor("", 1))
end
end
)
return searchbar
end

View File

@@ -5,52 +5,106 @@
-- Awesome Libs -- Awesome Libs
local awful = require("awful") local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local gobject = require("gears").object
local gtable = require("gears").table local gtable = require("gears").table
local gcolor = require("gears").color local gcolor = require("gears").color
local gshape = require("gears").shape local gshape = require("gears").shape
local gfilesystem = require("gears").filesystem local gfilesystem = require("gears").filesystem
local wibox = require("wibox") local wibox = require("wibox")
local base = require("wibox.widget.base")
local lgi = require("lgi")
local dbus_proxy = require("dbus_proxy")
local capi = { local context_menu = require("src.modules.context_menu")
awesome = awesome,
}
local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/" local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/"
local capi = {
awesome = awesome
}
local device = { mt = {} } local device = { mt = {} }
function device:connect() function device:layout(_, width, height)
self.device:Connect() if self._private.widget then
self.widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link.svg", return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
Theme_config.bluetooth_controller.icon_color_dark) end
capi.awesome.emit_signal("bluetooth::disconnect", device)
end end
function device:disconnect() function device:fit(context, width, height)
self.device:Disconnect() local w, h = 0, 0
self.widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link-off.svg", if self._private.widget then
Theme_config.bluetooth_controller.icon_color_dark) w, h = base.fit_widget(self, context, self._private.widget, width, height)
capi.awesome.emit_signal("bluetooth::connect", device) end
return w, h
end
device.set_widget = base.set_widget_common
function device:get_widget()
return self._private.widget
end
function device:toggle_connect()
if not self.device.Connected then
--TODO: Implement device passcode support, I have no idea how to get the
--TODO: Methods from Agent1 implemented
--[[ self._private.AgentManager1 = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
path = "/org/bluez",
interface = "org.bluez.AgentManager1"
}
self._private.Agent1 = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
path = "/org/bluez",
interface = "org.bluez.Agent1",
}
self._private.AgentManager1:RegisterAgent(self._private.Agent1.object_path, "")
self._private.AgentManager1:RequestDefaultAgent(self._private.Agent1.object_path) ]]
self.device:ConnectAsync()
else
self.device:DisconnectAsync()
end
end
function device:toggle_pair()
if self.device.Paired then
self.device:PairAsync()
else
self.device:CancelPairingAsync()
end
end
function device:toggle_trusted()
self.device:Set("org.bluez.Device1", "Trusted", lgi.GLib.Variant("b", not self.device.Trusted))
self.device.Trusted = { signature = "b", value = not self.device.Trusted }
end
function device:rename(newname)
self.device:Set("org.bluez.Device1", "Alias", lgi.GLib.Variant("s", newname))
self.device.Alias = { signature = "s", value = newname }
return self.device:Get("org.bluez.Device1", "Alias")
end end
function device.new(args) function device.new(args)
args = args or {} args = args or {}
args.device = args.device or {} args.device = args.device or {}
args.battery = args.battery or {}
local ret = gobject { enable_properties = true, enable_auto_signals = true }
gtable.crush(ret, device, true)
if args.device then
ret.device = args.device
end
if args.battery then
ret.battery = args.battery
end
local icon = device.Icon or "bluetooth-on" local icon = device.Icon or "bluetooth-on"
local device_widget = wibox.widget {
local inputbox = awful.widget.inputbox {
text = args.device.Alias or args.device.Name,
halign = "left",
valign = "center",
}
local ret = base.make_widget_from_value(wibox.widget {
{ {
{ {
{ {
@@ -75,9 +129,11 @@ function device.new(args)
{ {
{ {
{ {
text = ret.device.Alias or ret.device.Name, inputbox,
id = "alias", widget = wibox.container.constraint,
widget = wibox.widget.textbox strategy = "min",
width = dpi(400),
id = "const"
}, },
{ {
text = "Connecting...", text = "Connecting...",
@@ -150,33 +206,133 @@ function device.new(args)
shape = function(cr, width, height) shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(4)) gshape.rounded_rect(cr, width, height, dpi(4))
end, end,
device = ret.device,
widget = wibox.container.background widget = wibox.container.background
})
gtable.crush(ret, device, true)
if args.device then
ret.device = args.device
end
ret:get_children_by_id("con")[1].image = gcolor.recolor_image(ret.device.Connected and icondir .. "link.svg" or
icondir .. "link-off.svg",
Theme_config.bluetooth_controller.icon_color_dark)
local cm = context_menu {
widget_template = wibox.widget {
{
{
{
{
widget = wibox.widget.imagebox,
resize = true,
valign = "center",
halign = "center",
id = "icon_role",
},
widget = wibox.container.constraint,
stragety = "exact",
width = dpi(24),
height = dpi(24),
id = "const"
},
{
widget = wibox.widget.textbox,
valign = "center",
halign = "left",
id = "text_role"
},
layout = wibox.layout.fixed.horizontal
},
widget = wibox.container.margin
},
widget = wibox.container.background,
}, spacing = dpi(10),
entries = {
{
name = ret.device.Connected and "Disconnect" or "Connect",
icon = gcolor.recolor_image(ret.device.Connected and icondir .. "bluetooth-off.svg" or
icondir .. "bluetooth-on.svg",
Theme_config.bluetooth_controller.icon_color),
callback = function()
ret:toggle_connect()
end,
id = "connected"
},
{
name = "Pair",
icon = gcolor.recolor_image(ret.device.Paired and icondir .. "link-off.svg" or
icondir .. "link.svg",
Theme_config.bluetooth_controller.icon_color),
callback = function()
ret:toggle_pair()
end
},
{
name = ret.device.Trusted and "Untrust" or "Trust",
icon = gcolor.recolor_image(ret.device.Trusted and icondir .. "untrusted.svg" or icondir .. "trusted.svg",
Theme_config.bluetooth_controller.icon_color),
callback = function()
ret:toggle_trusted()
end,
id = "trusted"
},
{
name = "Rename",
icon = gcolor.recolor_image(icondir .. "edit.svg", Theme_config.bluetooth_controller.icon_color),
callback = function()
inputbox:focus()
inputbox:connect_signal("submit", function(text)
text = text:get_text()
inputbox.markup = ret:rename(text)
end)
end
},
{
name = "Remove",
icon = gcolor.recolor_image(icondir .. "delete.svg", Theme_config.bluetooth_controller.icon_color),
callback = function()
args.remove_callback(ret.device)
end
}
}
} }
if ret.device.Connected then ret:buttons(
device_widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link.svg",
Theme_config.bluetooth_controller.icon_color_dark)
else
device_widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link-off.svg",
Theme_config.bluetooth_controller.icon_color_dark)
end
device_widget:buttons(
gtable.join( gtable.join(
awful.button({}, 1, function() awful.button({}, 1, function()
if ret.device.Connected then ret:toggle_connect()
ret:disconnect() end),
else awful.button({}, 3, function()
ret:connect() for _, value in ipairs(cm.widget.children) do
value.id = value.id or ""
if value.id:match("connected") then
value:get_children_by_id("text_role")[1].text = ret.device.Connected and "Disconnect" or "Connect"
value:get_children_by_id("icon_role")[1].image = gcolor.recolor_image(ret.device.Connected and
icondir .. "bluetooth-off.svg" or icondir .. "bluetooth-on.svg",
Theme_config.bluetooth_controller.icon_color)
elseif value.id:match("trusted") then
value:get_children_by_id("text_role")[1].text = ret.device.Trusted and "Untrust" or "Trust"
value:get_children_by_id("icon_role")[1].image = gcolor.recolor_image(ret.device.Trusted and
icondir .. "untrusted.svg" or icondir .. "trusted.svg", Theme_config.bluetooth_controller.icon_color)
elseif value.id:match("paired") then
value:get_children_by_id("icon_role")[1].image = gcolor.recolor_image(ret.device.Paired and
icondir .. "link-off.svg" or icondir .. "link.svg", Theme_config.bluetooth_controller.icon_color)
end end
end
cm:toggle()
end) end)
) )
) )
Hover_signal(device_widget) capi.awesome.connect_signal(ret.device.object_path .. "_updated", function(d)
ret:get_children_by_id("con")[1].image = gcolor.recolor_image(d.Connected and icondir .. "link.svg" or
icondir .. "link-off.svg",
Theme_config.bluetooth_controller.icon_color_dark)
end)
ret.widget = device_widget Hover_signal(ret)
return ret return ret
end end

View File

@@ -5,12 +5,16 @@
-- Awesome Libs -- Awesome Libs
local awful = require("awful") local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local gobject = require("gears").object
local gtable = require("gears").table local gtable = require("gears").table
local gcolor = require("gears").color local gcolor = require("gears").color
local gshape = require("gears").shape local gshape = require("gears").shape
local gfilesystem = require("gears").filesystem local gfilesystem = require("gears").filesystem
local wibox = require("wibox") local wibox = require("wibox")
local base = require("wibox.widget.base")
local dbus_proxy = require("dbus_proxy")
local lgi = require("lgi")
local gtimer = require("gears.timer")
local naughty = require("naughty")
local bt_device = require("src.modules.bluetooth.device") local bt_device = require("src.modules.bluetooth.device")
@@ -18,54 +22,218 @@ local rubato = require("src.lib.rubato")
local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/" local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/"
local dnd_widget = require("awful.widget.toggle_widget")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
mouse = mouse, mouse = mouse,
mousegrabber = mousegrabber, mousegrabber = mousegrabber,
} }
local bluetooth = { mt = {} } local bluetooth = { mt = {} }
bluetooth.devices = { function bluetooth:layout(_, width, height)
paired = { layout = wibox.layout.fixed.vertical }, if self._private.widget then
discovered = { layout = wibox.layout.fixed.vertical } return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
} end
function bluetooth:get_devices()
return self.devices
end end
local function add_device(self, device, battery) function bluetooth:fit(context, width, height)
--Check if the device is already in the list local w, h = 0, 0
for _, status in pairs(self.devices) do if self._private.widget then
for _, dev in ipairs(status) do w, h = base.fit_widget(self, context, self._private.widget, width, height)
if dev.device.Address == device.Address then end
return w, h
end
bluetooth.set_widget = base.set_widget_common
function bluetooth:get_widget()
return self._private.widget
end
function bluetooth:get_paired_devices()
return self:get_children_by_id("connected_device_list")[1].children
end
function bluetooth:get_discovered_devices()
return self:get_children_by_id("discovered_device_list")[1].children
end
function bluetooth:remove_device_information(device)
-- Either disconnect async and have to remove the device "twice"
-- or do it sync but awesome freezes for a second or two
print("bruh?")
device:DisconnectAsync(function(_, _, out, err)
print(out, err)
self._private.Adapter1:RemoveDevice(device.object_path)
end)
end
function bluetooth:add_device(device, object_path)
local plist = self:get_children_by_id("connected_device_list")[1]
local dlist = self:get_children_by_id("discovered_device_list")[1]
for _, value in pairs(dlist.children) do
-- I'm not sure why Connected is in both cases true when its a new connection but eh just take it, it works
if value.device.Address:match(device.Address) and (device.Connected ~= value.device.Connected) then
print("Bad ", value.device.Alias)
return return
elseif value.device.Address:match(device.Address) and (device.Connected == value.device.Connected) then
print("Good ", value.device.Alias)
dlist:remove_widgets(value)
plist:add(plist:add(bt_device {
device = device,
path = object_path,
remove_callback = function()
self:remove_device_information(device)
end,
}))
return;
end end
end end
for _, value in pairs(plist.children) do
if value.device.Address:match(device.Address) then return end
end end
if device.Paired then if device.Paired then
table.insert(self.devices.paired, bt_device.new { device = device, battery = battery }.widget) plist:add(bt_device {
device = device,
path = object_path,
remove_callback = function()
self:remove_device_information(device)
end,
})
else else
table.insert(self.devices.discovered, bt_device.new { device = device, battery = battery }.widget) dlist:add(bt_device {
device = device,
path = object_path,
remove_callback = function()
self:remove_device_information(device)
end,
})
end end
end end
local function remove_device(self, device) function bluetooth:remove_device(object_path)
for i, dev in pairs(self.devices) do local plist = self:get_children_by_id("connected_device_list")[1]
if dev.Address == device.Address then local dlist = self:get_children_by_id("discovered_device_list")[1]
table.remove(self.devices, i) for _, d in ipairs(dlist.children) do
if d.device.object_path == object_path then
dlist:remove_widgets(d)
end end
end end
for _, d in ipairs(plist.children) do
if d.device.object_path == object_path then
plist:remove_widgets(d)
end
end
end
function bluetooth:update_device(new_device, object_path)
for _, device in ipairs(self.devices.paired:get_children()) do
if device.path == object_path then
device.device:update(new_device)
end
end
for _, device in ipairs(self.devices.discovered:get_children()) do
if device.path == object_path then
device.device:update(new_device)
end
end
end
function bluetooth:scan()
self._private.Adapter1:StartDiscovery()
end
function bluetooth:stop_scan()
self._private.Adapter1:StopDiscovery()
end
function bluetooth:toggle()
local powered = self._private.Adapter1.Powered
self._private.Adapter1:Set("org.bluez.Adapter1", "Powered", lgi.GLib.Variant("b", not powered))
self._private.Adapter1.Powered = {
signature = "b",
value = not powered
}
end
function bluetooth:open_settings()
awful.spawn("blueman-manager")
end
function bluetooth:get_device_info(object_path)
if (not object_path) or (not object_path:match("/org/bluez/hci0/dev")) then return end
local Device1 = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.bluez.Device1",
path = object_path
}
local Device1Properties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.Properties",
path = object_path
}
if (not Device1.Name) or (Device1.Name == "") then return end
local just_notified = false
local notify_timer = gtimer {
timeout = 3,
autostart = false,
single_shot = true,
callback = function()
just_notified = false
end
}
Device1Properties:connect_signal(function(_, _, changed_props)
if changed_props["Connected"] ~= nil then
if not just_notified then
naughty.notification({
app_icon = icondir .. "bluetooth-on.svg",
app_name = "Bluetooth",
title = Device1.Name,
icon = gcolor.recolor_image(icondir .. Device1.Icon .. ".svg", Theme_config.bluetooth_controller.icon_color),
timeout = 5,
message = "Device " ..
Device1.Name .. " is now " .. (changed_props["Connected"] and "connected" or "disconnected"),
category = Device1.Connected and "device.added" or "device.removed",
})
just_notified = true
notify_timer:start()
end
end
capi.awesome.emit_signal(object_path .. "_updated", Device1)
end, "PropertiesChanged")
self:add_device(Device1, object_path)
end
local function send_state_notification(powered)
naughty.notification {
app_icon = gcolor.recolor_image(icondir .. "bluetooth-on.svg", Theme_config.bluetooth_controller.icon_color),
app_name = "Bluetooth",
title = "Bluetooth",
message = powered and "Enabled" or "Disabled",
icon = gcolor.recolor_image(powered and icondir .. "bluetooth-on.svg" or icondir .. "bluetooth-off.svg",
Theme_config.bluetooth_controller.icon_color),
category = powered and "device.added" or "device.removed",
}
end end
function bluetooth.new(args) function bluetooth.new(args)
args = args or {} args = args or {}
local ret = gobject { enable_properties = true, enable_auto_signals = true } local ret = base.make_widget_from_value(wibox.widget {
gtable.crush(ret, bluetooth, true)
local bluetooth_container = wibox.widget {
{ {
{ {
{ {
@@ -198,29 +366,15 @@ function bluetooth.new(args)
}, },
{ {
{ -- action buttons { -- action buttons
{ -- turn off
{ {
{ dnd_widget {
image = gcolor.recolor_image(icondir .. "power.svg", color = Theme_config.bluetooth_controller.power_bg,
Theme_config.bluetooth_controller.power_icon_color), size = dpi(40)
resize = false, },
id = "dnd",
widget = wibox.container.place,
valign = "center", valign = "center",
halign = "center", halign = "center"
widget = wibox.widget.imagebox,
id = "icon"
},
widget = wibox.container.margin,
margins = dpi(5),
id = "center"
},
border_width = dpi(2),
border_color = Theme_config.bluetooth_controller.border_color,
shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(4))
end,
bg = Theme_config.bluetooth_controller.power_bg,
widget = wibox.container.background,
id = "power",
}, },
nil, nil,
{ -- refresh { -- refresh
@@ -236,16 +390,16 @@ function bluetooth.new(args)
widget = wibox.container.margin, widget = wibox.container.margin,
margins = dpi(5), margins = dpi(5),
}, },
border_width = dpi(2),
border_color = Theme_config.bluetooth_controller.border_color,
shape = function(cr, width, height) shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(4)) gshape.rounded_rect(cr, width, height, dpi(4))
end, end,
bg = Theme_config.bluetooth_controller.refresh_bg, bg = Theme_config.bluetooth_controller.refresh_bg,
id = "scan",
widget = wibox.container.background widget = wibox.container.background
}, },
layout = wibox.layout.align.horizontal layout = wibox.layout.align.horizontal
}, },
id = "marg_dnd",
widget = wibox.container.margin, widget = wibox.container.margin,
top = dpi(10), top = dpi(10),
}, },
@@ -266,28 +420,91 @@ function bluetooth.new(args)
widget = wibox.container.background widget = wibox.container.background
}, },
width = dpi(400), width = dpi(400),
forced_width = dpi(400),
strategy = "exact", strategy = "exact",
widget = wibox.container.constraint widget = wibox.container.constraint
})
local dnd = ret:get_children_by_id("dnd")[1]:get_widget()
dnd:connect_signal("dnd::toggle", function(enable)
ret:toggle()
end)
gtable.crush(ret, bluetooth, true)
--#region Bluetooth Proxies
-- Create a proxy for the freedesktop ObjectManager
ret._private.ObjectManager = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.ObjectManager",
path = "/"
} }
capi.awesome.connect_signal( -- Create a proxy for the bluez Adapter1 interface
"bluetooth::device_changed", ret._private.Adapter1 = dbus_proxy.Proxy:new {
function(device, battery) bus = dbus_proxy.Bus.SYSTEM,
add_device(ret, device, battery) name = "org.bluez",
remove_device(ret, device) interface = "org.bluez.Adapter1",
bluetooth_container:get_children_by_id("connected_device_list")[1].children = ret:get_devices().paired path = "/org/bluez/hci0"
bluetooth_container:get_children_by_id("discovered_device_list")[1].children = ret:get_devices().discovered }
end
)
local connected_margin = bluetooth_container:get_children_by_id("connected_margin")[1] -- Create a proxy for the bluez Adapter1 Properties interface
local connected_list = bluetooth_container:get_children_by_id("connected_list")[1] ret._private.Adapter1Properties = dbus_proxy.Proxy:new {
local connected = bluetooth_container:get_children_by_id("connected")[1].center bus = dbus_proxy.Bus.SYSTEM,
name = "org.bluez",
interface = "org.freedesktop.DBus.Properties",
path = "/org/bluez/hci0"
}
-- Connect to the ObjectManager's InterfacesAdded signal
ret._private.ObjectManager:connect_signal(function(_, interface)
ret:get_device_info(interface)
end, "InterfacesAdded")
-- Connect to the ObjectManager's InterfacesRemoved signal
ret._private.ObjectManager:connect_signal(function(_, interface)
ret:remove_device(interface)
end, "InterfacesRemoved")
-- Connect to the Adapter1's PropertiesChanged signal
ret._private.Adapter1Properties:connect_signal(function(_, _, data)
if data.Powered ~= nil then
send_state_notification(data.Powered)
if data.Powered then
dnd:set_enabled()
ret:scan()
else
dnd:set_disabled()
end
ret:emit_signal("bluetooth::status", data.Powered)
end
end, "PropertiesChanged")
gtimer.delayed_call(function()
for path, _ in pairs(ret._private.ObjectManager:GetManagedObjects()) do
ret:get_device_info(path)
end
if ret._private.Adapter1.Powered then
dnd:set_enabled()
ret:scan()
else
dnd:set_disabled()
end
ret:emit_signal("bluetooth::status", ret._private.Adapter1.Powered)
send_state_notification(ret._private.Adapter1.Powered)
end)
--#endregion
--#region Dropdown logic
local connected_margin = ret:get_children_by_id("connected_margin")[1]
local connected_list = ret:get_children_by_id("connected_list")[1]
local connected = ret:get_children_by_id("connected")[1].center
connected_margin:connect_signal( connected_margin:connect_signal(
"button::press", "button::press",
function() function()
capi.awesome.emit_signal("bluetooth::scan")
local rubato_timer = rubato.timed { local rubato_timer = rubato.timed {
duration = 0.2, duration = 0.2,
pos = connected_list.forced_height, pos = connected_list.forced_height,
@@ -297,7 +514,7 @@ function bluetooth.new(args)
end end
} }
if connected_list.forced_height == 0 then if connected_list.forced_height == 0 then
local size = (#ret:get_devices().paired * 60) + 1 local size = (#ret:get_paired_devices() * 60) + 1
if size < 210 then if size < 210 then
rubato_timer.target = dpi(size) rubato_timer.target = dpi(size)
end end
@@ -317,16 +534,14 @@ function bluetooth.new(args)
end end
) )
local discovered_margin = bluetooth_container:get_children_by_id("discovered_margin")[1] local discovered_margin = ret:get_children_by_id("discovered_margin")[1]
local discovered_list = bluetooth_container:get_children_by_id("discovered_list")[1] local discovered_list = ret:get_children_by_id("discovered_list")[1]
local discovered_bg = bluetooth_container:get_children_by_id("discovered_bg")[1] local discovered_bg = ret:get_children_by_id("discovered_bg")[1]
local discovered = bluetooth_container:get_children_by_id("discovered")[1].center local discovered = ret:get_children_by_id("discovered")[1].center
discovered_margin:connect_signal( discovered_margin:connect_signal(
"button::press", "button::press",
function() function()
capi.awesome.emit_signal("bluetooth::scan")
local rubato_timer = rubato.timed { local rubato_timer = rubato.timed {
duration = 0.2, duration = 0.2,
pos = discovered_list.forced_height, pos = discovered_list.forced_height,
@@ -337,7 +552,7 @@ function bluetooth.new(args)
} }
if discovered_list.forced_height == 0 then if discovered_list.forced_height == 0 then
local size = (#ret:get_devices().discovered * 60) + 1 local size = (#ret:get_discovered_devices() * 60) + 1
if size > 210 then if size > 210 then
size = 210 size = 210
end end
@@ -357,52 +572,17 @@ function bluetooth.new(args)
end end
end end
) )
--#endregion
ret.widget = awful.popup { ret:get_children_by_id("scan")[1]:buttons({
widget = bluetooth_container, awful.button({}, 1, function()
ontop = true, ret:scan()
bg = Theme_config.bluetooth_controller.container_bg, end)
stretch = false, })
visible = false,
screen = args.screen,
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(360), top = dpi(60) } })
end,
shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(12))
end
}
awesome.connect_signal( Hover_signal(ret:get_children_by_id("scan")[1])
"bluetooth_controller::toggle",
function()
if ret.widget.screen == capi.mouse.screen then
ret.widget.visible = not ret.widget.visible
end
end
)
return ret
ret.widget:connect_signal(
"mouse::leave",
function()
capi.mousegrabber.run(
function()
capi.awesome.emit_signal("bluetooth_controller::toggle", args.screen)
capi.mousegrabber.stop()
return true
end,
"arrow"
)
end
)
ret.widget:connect_signal(
"mouse::enter",
function()
capi.mousegrabber.stop()
end
)
end end
function bluetooth.mt:__call(...) function bluetooth.mt:__call(...)

View File

@@ -1,513 +0,0 @@
--------------------------------------
-- This is the bluetooth controller --
--------------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local rubato = require("src.lib.rubato")
local icondir = awful.util.getdir("config") .. "src/assets/icons/bluetooth/"
return function(s)
local function create_device(device, battery)
local icon = device.Icon or "bluetooth-on"
local device_widget = wibox.widget {
{
{
{
{
{
image = gears.color.recolor_image(
icondir .. icon .. ".svg", Theme_config.bluetooth_controller.icon_color),
id = "icon",
resize = false,
valign = "center",
halign = "center",
forced_width = dpi(24),
forced_height = dpi(24),
widget = wibox.widget.imagebox
},
id = "icon_container",
strategy = "max",
width = dpi(24),
height = dpi(24),
widget = wibox.container.constraint
},
{
{
{
text = device.Alias or device.Name,
id = "alias",
widget = wibox.widget.textbox
},
{
text = "Connecting...",
id = "connecting",
visible = false,
font = User_config.font.specify .. ", regular 10",
widget = wibox.widget.textbox
},
id = "alias_container",
layout = wibox.layout.fixed.horizontal
},
width = dpi(260),
height = dpi(40),
strategy = "max",
widget = wibox.container.constraint
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal
},
{ -- Spacing
forced_width = dpi(10),
widget = wibox.container.background
},
{
{
{
{
{
id = "con",
resize = false,
valign = "center",
halign = "center",
forced_width = dpi(24),
forced_height = dpi(24),
widget = wibox.widget.imagebox
},
id = "place",
strategy = "max",
width = dpi(24),
height = dpi(24),
widget = wibox.container.constraint
},
id = "margin",
margins = dpi(2),
widget = wibox.container.margin
},
id = "backgr",
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end,
bg = Theme_config.bluetooth_controller.con_button_color,
widget = wibox.container.background
},
id = "margin0",
margin = dpi(5),
widget = wibox.container.margin
},
id = "device_layout",
layout = wibox.layout.align.horizontal
},
id = "device_margin",
margins = dpi(5),
widget = wibox.container.margin
},
bg = Theme_config.bluetooth_controller.device_bg,
fg = Theme_config.bluetooth_controller.device_fg,
border_color = Theme_config.bluetooth_controller.device_border_color,
border_width = Theme_config.bluetooth_controller.device_border_width,
id = "background",
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end,
widget = wibox.container.background
}
--! using :Connect freezes awesome, either find a solution or switch to console commands
if device.Connected then
device_widget:get_children_by_id("con")[1].image = gears.color.recolor_image(icondir .. "link-off.svg",
Theme_config.bluetooth_controller.icon_color_dark)
device_widget:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
device:Disconnect()
awesome.emit_signal("bluetooth::connect", device)
end
end
)
else
device_widget:get_children_by_id("con")[1].image = gears.color.recolor_image(icondir .. "link.svg",
Theme_config.bluetooth_controller.icon_color_dark)
device_widget:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
device:Connect()
awesome.emit_signal("bluetooth::disconnect", device)
end
end
)
end
Hover_signal(device_widget)
return device_widget
end
local connected_devices_list = wibox.widget {
{
{
{
step = dpi(50),
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
id = "connected_device_list"
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
id = "connected_device_background",
border_color = Theme_config.bluetooth_controller.con_device_border_color,
border_width = Theme_config.bluetooth_controller.con_device_border_width,
shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, false, false, true, true, dpi(4))
end,
widget = wibox.container.background
}
local discovered_devices_list = wibox.widget {
{
{
{
spacing = dpi(10),
step = dpi(50),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
id = "discovered_device_list"
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
id = "discovered_device_background",
border_color = Theme_config.bluetooth_controller.con_device_border_color,
border_width = Theme_config.bluetooth_controller.con_device_border_width,
shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, false, false, true, true, dpi(4))
end,
widget = wibox.container.background
}
local bluetooth_container = wibox.widget {
{
{
{
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.bluetooth_controller.connected_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon"
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Paired Devices",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "connected",
layout = wibox.layout.fixed.horizontal
},
id = "connected_bg",
bg = Theme_config.bluetooth_controller.connected_bg,
fg = Theme_config.bluetooth_controller.connected_fg,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end,
widget = wibox.container.background
},
id = "connected_margin",
widget = wibox.container.margin
},
{
id = "connected_list",
widget = connected_devices_list,
forced_height = 0
},
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.bluetooth_controller.discovered_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon",
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Nearby Devices",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "discovered",
layout = wibox.layout.fixed.horizontal
},
id = "discovered_bg",
bg = Theme_config.bluetooth_controller.discovered_bg,
fg = Theme_config.bluetooth_controller.discovered_fg,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end,
widget = wibox.container.background
},
id = "discovered_margin",
top = dpi(10),
widget = wibox.container.margin
},
{
id = "discovered_list",
widget = discovered_devices_list,
forced_height = 0
},
id = "layout1",
layout = wibox.layout.fixed.vertical
},
id = "margin",
margins = dpi(15),
widget = wibox.container.margin
},
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
border_color = Theme_config.bluetooth_controller.container_border_color,
border_width = Theme_config.bluetooth_controller.container_border_width,
bg = Theme_config.bluetooth_controller.container_bg,
id = "background",
widget = wibox.container.background
},
width = dpi(400),
strategy = "exact",
widget = wibox.container.constraint
}
-- Main container
local bluetooth_controller_container = awful.popup {
widget = wibox.container.background,
ontop = true,
bg = Theme_config.bluetooth_controller.container_bg,
stretch = false,
visible = false,
screen = s,
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(380), top = dpi(60) } })
end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end
}
local connected_devices, nearby_devices = {}, {}
-- function to check if a device is already in the list
local function is_device_in_list(device)
for i = 1, #connected_devices do
if connected_devices[i].Address == device.Address then
return true
end
end
return false
end
awesome.connect_signal(
"bluetooth::device_changed",
function(device, battery)
if not is_device_in_list(device) then
-- add device and battery to list
if device.Paired then
table.insert(connected_devices, device)
else
table.insert(nearby_devices, device)
end
end
if (#connected_devices + #nearby_devices) > 0 then
local cd_list, dd_list = {}, {}
for _, d in pairs(connected_devices) do
if d.Paired then
table.insert(cd_list, create_device(d))
else
table.insert(dd_list, create_device(d))
end
end
for _, d in pairs(nearby_devices) do
if d.Paired then
table.insert(cd_list, create_device(d, battery))
else
table.insert(dd_list, create_device(d, battery))
end
end
connected_devices_list:get_children_by_id("connected_device_list")[1].children = cd_list
discovered_devices_list:get_children_by_id("discovered_device_list")[1].children = dd_list
end
end
)
-- Variables for easier access and better readability
local connected_margin = bluetooth_container:get_children_by_id("connected_margin")[1]
local connected_list = bluetooth_container:get_children_by_id("connected_list")[1]
local connected_bg = bluetooth_container:get_children_by_id("connected_bg")[1]
local connected = bluetooth_container:get_children_by_id("connected")[1].center
-- Click event for the microphone dropdown
connected_margin:connect_signal(
"button::press",
function()
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = connected_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
connected_list.forced_height = v
end
}
if connected_list.forced_height == 0 then
local size = (#connected_devices * 45) + ((#connected_devices - 1) * 10)
if size < 210 then
rubato_timer.target = dpi(size)
else
rubato_timer.target = dpi(210)
end
connected_margin.connected_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
connected.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.bluetooth_controller.connected_icon_color))
else
rubato_timer.target = 0
connected_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 4)
end
connected.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.bluetooth_controller.connected_icon_color))
end
end
)
-- Variables for easier access and better readability
local discovered_margin = bluetooth_container:get_children_by_id("discovered_margin")[1]
local discovered_list = bluetooth_container:get_children_by_id("discovered_list")[1]
local discovered_bg = bluetooth_container:get_children_by_id("discovered_bg")[1]
local discovered = bluetooth_container:get_children_by_id("discovered")[1].center
-- Click event for the microphone dropdown
discovered_margin:connect_signal(
"button::press",
function()
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = discovered_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
discovered_list.forced_height = v
end
}
if discovered_list.forced_height == 0 then
local size = (#nearby_devices * dpi(45)) + ((#nearby_devices - 1) * dpi(10))
if size < 210 then
rubato_timer.target = dpi(size)
else
rubato_timer.target = dpi(20)
end
discovered_margin.discovered_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
discovered.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.bluetooth_controller.discovered_icon_color))
else
rubato_timer.target = 0
discovered_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 4)
end
discovered.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.bluetooth_controller.discovered_icon_color))
end
end
)
-- When the mouse leaves the popup it stops the mousegrabber and hides the popup.
bluetooth_controller_container:connect_signal(
"mouse::leave",
function()
mousegrabber.run(
function()
awesome.emit_signal("bluetooth_controller::toggle", s)
mousegrabber.stop()
return true
end,
"arrow"
)
end
)
bluetooth_controller_container:connect_signal(
"mouse::enter",
function()
mousegrabber.stop()
end
)
-- Draw the popup
bluetooth_controller_container:setup {
bluetooth_container,
layout = wibox.layout.fixed.horizontal
}
-- Toggle container visibility
awesome.connect_signal(
"bluetooth_controller::toggle",
function(scr)
if scr == s then
bluetooth_controller_container.visible = not bluetooth_controller_container.visible
end
end
)
end

View File

@@ -1,134 +0,0 @@
---------------------------------------
-- This is the brightness_osd module --
---------------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/brightness/"
return function(s)
local brightness_osd_widget = wibox.widget {
{
{
{ -- Brightness Icon
image = gears.color.recolor_image(icondir .. "brightness-high.svg", Theme_config.brightness_osd.icon_color),
valign = "center",
halign = "center",
resize = false,
id = "icon",
widget = wibox.widget.imagebox
},
{ -- Brightness Bar
{
{
id = "progressbar1",
color = Theme_config.brightness_osd.bar_bg_active,
background_color = Theme_config.brightness_osd.bar_bg,
max_value = 100,
value = 0,
forced_height = dpi(6),
shape = function(cr, width, height)
gears.shape.rounded_bar(cr, width, height, dpi(6))
end,
widget = wibox.widget.progressbar
},
id = "progressbar_container2",
halign = "center",
valign = "center",
widget = wibox.container.place
},
id = "progressbar_container",
width = dpi(240),
heigth = dpi(20),
stragety = "max",
widget = wibox.container.constraint
},
id = "layout1",
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
forced_width = dpi(300),
forced_height = dpi(80),
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end,
border_color = Theme_config.brightness_osd.border_color,
border_width = Theme_config.brightness_osd.border_width,
fg = Theme_config.brightness_osd.fg,
bg = Theme_config.brightness_osd.bg,
widget = wibox.container.background
}
capi.awesome.connect_signal(
"brightness::get",
function(brightness)
print(brightness)
brightness_osd_widget:get_children_by_id("progressbar1")[1].value = brightness
local icon = icondir .. "brightness"
if brightness >= 0 and brightness < 34 then
icon = icon .. "-low"
elseif brightness >= 34 and brightness < 67 then
icon = icon .. "-medium"
elseif brightness >= 67 then
icon = icon .. "-high"
end
brightness_osd_widget:get_children_by_id("icon")[1]:set_image(gears.color.recolor_image(icon .. ".svg",
Theme_config.brightness_osd.icon_color))
end
)
local brightness_container = awful.popup {
widget = {},
ontop = true,
stretch = false,
visible = false,
screen = s,
placement = function(c) awful.placement.bottom_left(c, { margins = dpi(20) }) end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(14))
end
}
local hide_brightness_osd = gears.timer {
timeout = 2,
autostart = true,
callback = function()
brightness_container.visible = false
end
}
brightness_container:setup {
brightness_osd_widget,
layout = wibox.layout.fixed.horizontal
}
capi.awesome.connect_signal(
"brightness::rerun",
function()
if capi.mouse.screen == s then
brightness_container.visible = true
if hide_brightness_osd.started then
hide_brightness_osd:again()
else
hide_brightness_osd:start()
end
end
end
)
end

View File

@@ -1,117 +0,0 @@
---------------------------------------
-- This is the brightness_osd module --
---------------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
return function(args)
if not args then
return
end
local function get_entries()
local menu_entries = { layout = wibox.layout.fixed.vertical, spacing = dpi(10) }
if args.entries then
for _, entry in ipairs(args.entries) do
local menu_entry = wibox.widget {
{
{
{
{ -- Icon
widget = wibox.widget.imagebox,
image = gears.color.recolor_image(entry.icon, Theme_config.context_menu.entry.icon_color),
valign = "center",
halign = "center",
resize = true,
icon = entry.icon,
id = "icon"
},
widget = wibox.container.constraint,
stragety = "exact",
width = dpi(24),
height = dpi(24),
id = "const"
},
{ -- Text
widget = wibox.widget.textbox,
text = entry.name,
id = "name"
},
id = "lay",
spacing = dpi(5),
layout = wibox.layout.fixed.horizontal
},
margins = dpi(10),
widget = wibox.container.margin,
id = "mar"
},
bg = Theme_config.context_menu.entry.bg,
fg = Theme_config.context_menu.entry.fg,
shape = Theme_config.context_menu.entry.shape,
border_width = Theme_config.context_menu.entry.border_width,
border_color = Theme_config.context_menu.entry.border_color,
widget = wibox.container.background,
id = "menu_entry"
}
menu_entry:buttons(gears.table.join(
awful.button({
modifiers = {},
button = 1,
on_release = function()
capi.awesome.emit_signal("context_menu::hide")
entry.callback()
end
})
))
Hover_signal(menu_entry, nil, Theme_config.context_menu.entry.hover_fg,
Theme_config.context_menu.entry.hover_border, Theme_config.context_menu.entry.icon_color,
Theme_config.context_menu.entry.icon_color_hover)
table.insert(menu_entries, menu_entry)
end
end
return menu_entries
end
local menu = awful.popup {
widget = {
get_entries(),
margins = dpi(10),
widget = wibox.container.margin
},
bg = Theme_config.context_menu.bg,
fg = Theme_config.context_menu.fg,
border_width = Theme_config.context_menu.border_width,
border_color = Theme_config.context_menu.border_color,
shape = Theme_config.context_menu.shape,
x = capi.mouse.coords().x,
y = capi.mouse.coords().y,
visible = false,
ontop = true,
placement = awful.placement.no_offscreen,
}
menu:connect_signal("mouse::leave", function()
capi.awesome.emit_signal("context_menu::hide")
end)
capi.awesome.connect_signal(
"context_menu::hide",
function()
menu.visible = false
end
)
return menu
end

View File

@@ -52,7 +52,7 @@ function context_menu:make_entries(wtemplate, entries, spacing)
return return
end end
for _, entry in ipairs(entries) do for key, entry in pairs(entries) do
-- TODO: Figure out how to make a new widget from etemplate -- TODO: Figure out how to make a new widget from etemplate
local menu_entry = wibox.widget { local menu_entry = wibox.widget {
{ {
@@ -124,7 +124,8 @@ function context_menu:make_entries(wtemplate, entries, spacing)
if not entry.submenu then if not entry.submenu then
entry.callback() entry.callback()
end end
self.visible = false capi.awesome.emit_signal("submenu::close")
capi.awesome.emit_signal("cm::hide")
end end
}) })
}) })
@@ -169,10 +170,8 @@ function context_menu:make_entries(wtemplate, entries, spacing)
menu_entry.popup.visible = false menu_entry.popup.visible = false
end) end)
end end
menu_entries[key] = menu_entry
table.insert(menu_entries, menu_entry)
end end
return menu_entries return menu_entries
end end
@@ -182,6 +181,8 @@ function context_menu:toggle()
self.visible = not self.visible self.visible = not self.visible
end end
-- This is terribly done but I don't know how to do it better since
-- the awful.popup.widget needs to know itself which I don't think is possible
function context_menu.new(args) function context_menu.new(args)
args = args or {} args = args or {}
@@ -202,6 +203,11 @@ function context_menu.new(args)
y = capi.mouse.coords().y - 10 y = capi.mouse.coords().y - 10
} }
-- I literally have no clue how to do it better, it doesn't really matter anyways
capi.awesome.connect_signal("cm::hide", function()
ret.visible = false
end)
gtable.crush(ret, context_menu, true) gtable.crush(ret, context_menu, true)
return ret return ret

View File

@@ -62,10 +62,7 @@ return function(s, widgets)
bg = Theme_config.center_bar.bg, bg = Theme_config.center_bar.bg,
visible = true, visible = true,
maximum_width = dpi(500), maximum_width = dpi(500),
placement = function(c) awful.placement.top(c, { margins = dpi(10) }) end, placement = function(c) awful.placement.top(c, { margins = dpi(10) }) end
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end
} }
top_center:struts { top_center:struts {

View File

@@ -257,10 +257,7 @@ return function(screen)
screen = screen, screen = screen,
type = "dock", type = "dock",
height = dpi(User_config.dock_icon_size + 10), height = dpi(User_config.dock_icon_size + 10),
placement = function(c) awful.placement.bottom(c, { margins = dpi(10) }) end, placement = function(c) awful.placement.bottom(c, { margins = dpi(10) }) end
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(16))
end
} }
--- A fakedock to send a signal when the mouse is over it --- A fakedock to send a signal when the mouse is over it

View File

@@ -57,10 +57,7 @@ return function(s, w)
bg = Theme_config.left_bar.bg, bg = Theme_config.left_bar.bg,
visible = true, visible = true,
maximum_width = dpi(650), maximum_width = dpi(650),
placement = function(c) awful.placement.top_left(c, { margins = dpi(10) }) end, placement = function(c) awful.placement.top_left(c, { margins = dpi(10) }) end
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end
} }
top_left:struts { top_left:struts {

View File

@@ -56,10 +56,7 @@ return function(s, w)
bg = Theme_config.right_bar.bg, bg = Theme_config.right_bar.bg,
visible = true, visible = true,
screen = s, screen = s,
placement = function(c) awful.placement.top_right(c, { margins = dpi(10) }) end, placement = function(c) awful.placement.top_right(c, { margins = dpi(10) }) end
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end
} }
top_right:struts { top_right:struts {

View File

@@ -31,8 +31,6 @@ function context_menu.new(args)
local ret = gobject {} local ret = gobject {}
gtable.crush(ret, context_menu, true) gtable.crush(ret, context_menu, true)
capi.awesome.connect_signal("context_menu:show", function() capi.awesome.connect_signal("context_menu:show", function()
ret:toggle() ret:toggle()
mousegrabber.run(function() mousegrabber.run(function()
@@ -44,7 +42,7 @@ function context_menu.new(args)
end, nil) end, nil)
end) end)
return w return ret
end end
function context_menu.mt:__call(...) function context_menu.mt:__call(...)

View File

@@ -17,13 +17,11 @@ awful.screen.connect_for_each_screen(
User_config.layouts[1] User_config.layouts[1]
) )
require("src.modules.desktop.context_menu") { screen = s }
require("src.modules.desktop.desktop") { screen = s } require("src.modules.desktop.desktop") { screen = s }
require("src.modules.powermenu.powermenu")(s) require("src.modules.powermenu.powermenu")(s)
require("src.modules.audio.volume_osd") { screen = s } require("src.modules.audio.volume_osd") { screen = s }
--require("src.modules.audio.volume_controller") { screen = s } --require("src.modules.audio.volume_controller") { screen = s }
require("src.modules.brightness.brightness_osd")(s) require("src.modules.brightness.brightness_osd")(s)
require("src.modules.bluetooth.init") { screen = s }
require("src.modules.titlebar.titlebar") require("src.modules.titlebar.titlebar")
require("src.modules.crylia_bar.init")(s) require("src.modules.crylia_bar.init")(s)
--require("src.modules.crylia_wibox.init")(s) --require("src.modules.crylia_wibox.init")(s)

View File

@@ -10,6 +10,8 @@ local gfilesystem = require("gears").filesystem
local gobject = require("gears").object local gobject = require("gears").object
local gcolor = require("gears").color local gcolor = require("gears").color
local wibox = require("wibox") local wibox = require("wibox")
local base = require("wibox.widget.base")
local NM = require("lgi").NM
local ap_form = require("src.modules.network_controller.ap_form") local ap_form = require("src.modules.network_controller.ap_form")
@@ -17,39 +19,28 @@ local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/network
local access_point = { mt = {} } local access_point = { mt = {} }
access_point.connected = false
function access_point.new(args) function access_point.new(args)
args = args or {} args = args or {}
if not args.access_point then return end if not args.NetworkManagerAccessPoint then return end
local ret = gobject { enable_properties = true, enable_auto_signals = true }
gtable.crush(ret, access_point, true)
local strength = args.access_point.strength or 0
--normalize strength between 1 and 4
strength = math.floor(strength / 25) + 1
local icon = "wifi-strength-" .. strength .. ".svg"
local bg, fg, icon_color = Theme_config.network_manager.access_point.bg, Theme_config.network_manager.access_point.fg, local bg, fg, icon_color = Theme_config.network_manager.access_point.bg, Theme_config.network_manager.access_point.fg,
Theme_config.network_manager.access_point.icon_color Theme_config.network_manager.access_point.icon_color
if args.active == args.access_point.access_point_path then --[[ if get_active_access_point() == args.NetworkManagerAccessPoint.access_point_path then
bg, fg, icon_color = Theme_config.network_manager.access_point.fg, Theme_config.network_manager.access_point.bg, bg, fg, icon_color = Theme_config.network_manager.access_point.fg, Theme_config.network_manager.access_point.bg,
Theme_config.network_manager.access_point.icon_color2 Theme_config.network_manager.access_point.icon_color2
end end ]]
local ap_widget = wibox.widget { local ret = base.make_widget_from_value(wibox.widget {
{ {
{ {
{ {
{ {
{ {
image = gcolor.recolor_image( image = gcolor.recolor_image(
icondir .. icon, icon_color), icondir .. "wifi-strength-" .. math.floor(args.NetworkManagerAccessPoint.Strength / 25) + 1 .. ".svg",
icon_color),
id = "icon", id = "icon",
resize = true, resize = true,
valign = "center", valign = "center",
@@ -67,7 +58,8 @@ function access_point.new(args)
{ {
{ {
{ {
text = args.access_point.ssid or args.access_point.hw_address or "Unknown", text = NM.utils_ssid_to_utf8(args.NetworkManagerAccessPoint.Ssid) or
args.NetworkManagerAccessPoint.hw_address or "Unknown",
id = "alias", id = "alias",
widget = wibox.widget.textbox widget = wibox.widget.textbox
}, },
@@ -132,31 +124,32 @@ function access_point.new(args)
border_width = Theme_config.network_manager.access_point.border_width, border_width = Theme_config.network_manager.access_point.border_width,
id = "background", id = "background",
shape = Theme_config.network_manager.access_point.device_shape, shape = Theme_config.network_manager.access_point.device_shape,
device = ret.access_point,
widget = wibox.container.background widget = wibox.container.background
} })
ap_form { screen = args.screen, SSID = args.access_point.ssid } gtable.crush(ret, access_point, true)
ap_widget:buttons( ret.NetworkManagerAccessPoint = args.NetworkManagerAccessPoint
ret.ap_form = ap_form { screen = args.screen, ssid = NM.utils_ssid_to_utf8(ret.NetworkManagerAccessPoint.Ssid) }
ret:buttons(
gtable.join( gtable.join(
awful.button( awful.button(
{}, {},
1, 1,
nil, nil,
function() function()
ap_form:popup_toggle() ret.ap_form:popup_toggle()
end end
) )
) )
) )
ap_widget:get_children_by_id("con")[1].image = gcolor.recolor_image( ret:get_children_by_id("con")[1].image = gcolor.recolor_image(
icondir .. "link.svg", icon_color) icondir .. "link.svg", icon_color)
Hover_signal(ap_widget) Hover_signal(ret)
ret.widget = ap_widget
return ret return ret
end end

View File

@@ -15,44 +15,16 @@ local capi = {
} }
local ap_form = { mt = {} } local ap_form = { mt = {} }
ap_form._private = {}
ap_form.settigns_form = { function ap_form:popup_toggle()
ssid = awful.widget.inputbox { self.visible = not self.visible
widget_template = wibox.template { end
widget = wibox.widget {
{ function ap_form.new(args)
{ args = args or {}
{ args.screen = args.screen or awful.screen.preferred()
widget = wibox.widget.textbox,
halign = "left", local settigns_form = {
valign = "center",
id = "text_role",
},
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = "#212121",
fg = "#F0F0F0",
border_color = "#414141",
border_width = 2,
shape = gshape.rounded_rect,
forced_width = 300,
forced_height = 50,
},
update_callback = function(template_widget, args)
template_widget.widget.const.marg.text_role.markup = args.text
end
}
},
password = awful.widget.inputbox { password = awful.widget.inputbox {
widget_template = wibox.template { widget_template = wibox.template {
widget = wibox.widget { widget = wibox.widget {
@@ -88,30 +60,19 @@ ap_form.settigns_form = {
end end
} }
}, },
} }
function ap_form:popup_toggle() local ret = awful.popup {
self._private.popup.visible = not self._private.popup.visible
end
function ap_form.new(args)
args = args or {}
args.screen = args.screen or awful.screen.preferred()
local ret = gobject {}
ret._private = {}
gtable.crush(ret, ap_form, true)
gtable.crush(ret, args)
ret._private.popup = awful.popup {
widget = { widget = {
{
{ -- Header { -- Header
{ {
nil, nil,
{ {
{ {
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
text = args.SSID, text = args.ssid,
font = User_config.font.specify .. ",extra bold 16",
halign = "center", halign = "center",
valign = "center", valign = "center",
}, },
@@ -128,8 +89,10 @@ function ap_form.new(args)
halign = "center", halign = "center",
}, },
widget = wibox.container.margin, widget = wibox.container.margin,
margins = dpi(5),
}, },
widget = wibox.container.background, widget = wibox.container.background,
shape = Theme_config.network_manager.form.close_icon_shape,
id = "close_button", id = "close_button",
bg = Theme_config.network_manager.form.close_bg bg = Theme_config.network_manager.form.close_bg
}, },
@@ -140,43 +103,34 @@ function ap_form.new(args)
fg = Theme_config.network_manager.form.header_fg, fg = Theme_config.network_manager.form.header_fg,
}, },
{ -- Form { -- Form
{ -- SSID
{
widget = wibox.widget.textbox,
text = "SSID",
halign = "center",
valign = "center"
},
nil,
-- Change to inputtextbox container
ret.settigns_form.ssid,
layout = wibox.layout.align.horizontal
},
{ -- Password { -- Password
{
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
text = "Password", text = "Password",
halign = "center", halign = "center",
valign = "center" valign = "center"
}, },
nil, {
-- Change to inputtextbox container widget = wibox.container.margin,
ret.settigns_form.password, left = dpi(20),
layout = wibox.layout.align.horizontal right = dpi(20),
}, },
spacing = dpi(10), -- Change to inputtextbox container
layout = wibox.layout.fixed.vertical settigns_form.password,
layout = wibox.layout.align.horizontal
}, },
{ -- Actions { -- Actions
{ -- Auto connect { -- Auto connect
{
{ {
{ {
checked = false, checked = false,
shape = Theme_config.network_manager.form.checkbox_shape, shape = Theme_config.network_manager.form.checkbox_shape,
color = Theme_config.network_manager.form.checkbox_bg, color = Theme_config.network_manager.form.checkbox_fg,
check_color = Theme_config.network_manager.form.checkbox_fg, paddings = dpi(3),
check_border_color = Theme_config.network_manager.form.check_border_color, check_color = Theme_config.network_manager.form.checkbox_bg,
check_border_width = Theme_config.network_manager.form.check_border_width, border_color = Theme_config.network_manager.form.checkbox_bg,
border_width = 2,
id = "checkbox",
widget = wibox.widget.checkbox widget = wibox.widget.checkbox
}, },
widget = wibox.container.constraint, widget = wibox.container.constraint,
@@ -184,16 +138,22 @@ function ap_form.new(args)
width = dpi(30), width = dpi(30),
height = dpi(30) height = dpi(30)
}, },
widget = wibox.container.place,
halign = "center",
valign = "center"
},
{ {
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
text = "Auto connect", text = "Auto connect",
halign = "center", halign = "center",
valign = "center" valign = "center"
}, },
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal layout = wibox.layout.fixed.horizontal
}, },
nil, nil,
{ -- Connect { -- Connect
{
{ {
{ {
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
@@ -201,16 +161,25 @@ function ap_form.new(args)
halign = "center", halign = "center",
valign = "center" valign = "center"
}, },
widget = wibox.container.margin,
margins = dpi(10),
},
widget = wibox.container.background, widget = wibox.container.background,
bg = Theme_config.network_manager.form.button_bg, bg = Theme_config.network_manager.form.button_bg,
fg = Theme_config.network_manager.form.button_fg, fg = Theme_config.network_manager.form.button_fg,
shape = Theme_config.network_manager.form.button_shape,
id = "connect_button",
}, },
widget = wibox.container.margin, widget = wibox.container.margin,
margins = dpi(10), margins = dpi(10),
}, },
layout = wibox.layout.align.horizontal layout = wibox.layout.align.horizontal
}, },
layout = wibox.layout.align.vertical spacing = dpi(20),
layout = wibox.layout.fixed.vertical
},
widget = wibox.container.margin,
margins = dpi(10)
}, },
placement = awful.placement.centered, placement = awful.placement.centered,
ontop = true, ontop = true,
@@ -220,37 +189,36 @@ function ap_form.new(args)
bg = Theme_config.network_manager.form.bg, bg = Theme_config.network_manager.form.bg,
fg = Theme_config.network_manager.form.fg, fg = Theme_config.network_manager.form.fg,
shape = Theme_config.network_manager.form.shape, shape = Theme_config.network_manager.form.shape,
border_color = Theme_config.network_manager.form.border_color,
border_width = Theme_config.network_manager.form.border_width,
type = "dialog", type = "dialog",
screen = args.screen, screen = args.screen,
} }
ret._private.popup.widget:get_children_by_id("close_button")[1]:connect_signal("button::press", function() gtable.crush(ret, ap_form, true)
ret:popup_toggle()
local checkbox = ret.widget:get_children_by_id("checkbox")[1]
checkbox:connect_signal("button::press", function()
checkbox.checked = not checkbox.checked
end) end)
ret.settigns_form.ssid:connect_signal( local close_button = ret.widget:get_children_by_id("close_button")[1]
"submit", close_button:connect_signal("button::press", function()
function(text) ret:popup_toggle()
end end)
) Hover_signal(close_button)
ret.settigns_form.ssid:connect_signal( local connect_button = ret.widget:get_children_by_id("connect_button")[1]
"stopped", connect_button:connect_signal("button::press", function()
function() ret:emit_signal("ap_form::connect", {
end ssid = args.ssid,
) password = settigns_form.password:get_text(),
auto_connect = ret.widget:get_children_by_id("checkbox")[1].checked
ret.settigns_form.password:connect_signal( })
"submit", print("Connect to " .. args.ssid:get_text(), "\nPassword: " .. settigns_form.password:get_text(),
function(text) "\nAuto connect: " .. tostring(ret.widget:get_children_by_id("checkbox")[1].checked))
end end)
) Hover_signal(connect_button)
ret.settigns_form.password:connect_signal(
"stopped",
function()
end
)
return ret return ret
end end

View File

@@ -14,23 +14,23 @@ local gcolor = require("gears").color
local gears = require("gears") local gears = require("gears")
local lgi = require("lgi") local lgi = require("lgi")
local wibox = require("wibox") local wibox = require("wibox")
local NM = require("lgi").NM local NM = require("lgi").NM
local base = require("wibox.widget.base")
local rubato = require("src.lib.rubato") local rubato = require("src.lib.rubato")
local access_point = require("src.modules.network_controller.access_point") local access_point = require("src.modules.network_controller.access_point")
local dnd_widget = require("awful.widget.toggle_widget")
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/network/" local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/network/"
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }
local network = { mt = {} } local network = { mt = {} }
network.access_points = { layout = wibox.layout.fixed.vertical }
network.NMState = { network.NMState = {
UNKNOWN = 0, UNKNOWN = 0,
ASLEEP = 10, ASLEEP = 10,
@@ -81,37 +81,45 @@ local function flags_to_security(flags, wpa_flags, rsn_flags)
return (str:gsub("^%s", "")) return (str:gsub("^%s", ""))
end end
local function get_wifi_proxy(self) local function generate_uuid()
local devices = self._private.client_proxy:GetDevices() return string.gsub('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', '[xy]', function(c)
for _, device in ipairs(devices) do local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
local device_proxy = dbus_proxy.Proxy:new { return string.format('%x', v)
end)
end
function network:get_wifi_proxy()
local devices = self._private.NetworkManager:GetDevices()
for _, path in ipairs(devices) do
local NetworkManagerDevice = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM, bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager", name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Device", interface = "org.freedesktop.NetworkManager.Device",
path = device path = path
} }
if device_proxy.DeviceType == network.DeviceType.WIFI then if NetworkManagerDevice.DeviceType == network.DeviceType.WIFI then
self._private.device_proxy = device_proxy self._private.NetworkManagerDevice = NetworkManagerDevice
self._private.wifi_proxy = dbus_proxy.Proxy:new { self._private.NetworkManagerDeviceWireless = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM, bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager", name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Device.Wireless", interface = "org.freedesktop.NetworkManager.Device.Wireless",
path = device path = path
} }
self._private.device_proxy:connect_signal(function(proxy, new_state, old_state, reason) self._private.NetworkManagerDevice:connect_signal(function(proxy, new_state, old_state, reason)
local active_access_point_proxy = dbus_proxy.Proxy:new { local NetworkManagerAccessPoint = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM, bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager", name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint", interface = "org.freedesktop.NetworkManager.AccessPoint",
path = self._private.wifi_proxy.ActiveAccessPoint path = self._private.wifi_proxy.ActiveAccessPoint
} }
self:emit_signal(tostring(active_access_point_proxy.HwAddress) .. "::state", new_state, old_state) self:emit_signal(tostring(NetworkManagerAccessPoint.HwAddress) .. "::state", new_state, old_state)
if new_state == network.DeviceState.ACTIVATED then if new_state == network.DeviceState.ACTIVATED then
local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid) local ssid = NM.utils_ssid_to_utf8(NetworkManagerAccessPoint.Ssid)
self:emit_signal("NM::AccessPointConnected", ssid, active_access_point_proxy.Strength) self:emit_signal("NM::AccessPointConnected", ssid, NetworkManagerAccessPoint.Strength)
print("AP Connected: ", ssid, NetworkManagerAccessPoint.Strength)
end end
end, "StateChanged") end, "StateChanged")
end end
@@ -119,8 +127,7 @@ local function get_wifi_proxy(self)
end end
function network.device_state_to_string(state) function network.device_state_to_string(state)
local device_state_to_string = local device_state_to_string = {
{
[0] = "Unknown", [0] = "Unknown",
[10] = "Unmanaged", [10] = "Unmanaged",
[20] = "Unavailable", [20] = "Unavailable",
@@ -139,63 +146,30 @@ function network.device_state_to_string(state)
return device_state_to_string[state] return device_state_to_string[state]
end end
local function get_access_point_connections(self, ssid) function network:get_access_point_connections(ssid)
local connection_proxies = {} local cn = {}
local connections = self._private.settings_proxy:ListConnections() local connections = self._private.NetworkManagerSettings:ListConnections()
for _, connection_path in ipairs(connections) do for _, connection_path in ipairs(connections) do
local connection_proxy = dbus_proxy.Proxy:new { local NetworkManagerSettingsConnection = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM, bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager", name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Settings.Connection", interface = "org.freedesktop.NetworkManager.Settings.Connection",
path = connection_path path = connection_path
} }
if connection_proxy.Filename:find(ssid) then if NetworkManagerSettingsConnection.Filename:find(ssid) then
table.insert(connection_proxies, connection_proxy) table.insert(cn, NetworkManagerSettingsConnection)
end end
end end
return connection_proxies return cn
end end
local function generate_uuid() function network:create_profile(ap, password, auto_connect)
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
local uuid = 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)
return uuid
end
local function create_profile(ap, password, auto_connect)
local s_con =
{
-- ["interface-name"] = lgi.GLib.Variant("s", ap.device_interface),
["uuid"] = lgi.GLib.Variant("s", generate_uuid()),
["id"] = lgi.GLib.Variant("s", ap.ssid),
["type"] = lgi.GLib.Variant("s", "802-11-wireless"),
["autoconnect"] = lgi.GLib.Variant("b", auto_connect),
}
local s_ip4 =
{
["method"] = lgi.GLib.Variant("s", "auto")
}
local s_ip6 =
{
["method"] = lgi.GLib.Variant("s", "auto"),
}
local s_wifi =
{
["mode"] = lgi.GLib.Variant("s", "infrastructure"),
}
local s_wsec = {} local s_wsec = {}
if ap.security ~= "" then if ap.security ~= "" then
if ap.security:match("WPA") ~= nil then if ap.security:match("WPA") then
s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "wpa-psk") s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "wpa-psk")
s_wsec["auth-alg"] = lgi.GLib.Variant("s", "open") s_wsec["auth-alg"] = lgi.GLib.Variant("s", "open")
--s_wsec["psk"] = lgi.GLib.Variant("s", helpers.string.trim(password)) --s_wsec["psk"] = lgi.GLib.Variant("s", helpers.string.trim(password))
@@ -207,108 +181,85 @@ local function create_profile(ap, password, auto_connect)
end end
return { return {
["connection"] = s_con, ["connection"] = {
["ipv4"] = s_ip4, -- ["interface-name"] = lgi.GLib.Variant("s", ap.device_interface),
["ipv6"] = s_ip6, ["uuid"] = lgi.GLib.Variant("s", generate_uuid()),
["802-11-wireless"] = s_wifi, ["id"] = lgi.GLib.Variant("s", ap.ssid),
["type"] = lgi.GLib.Variant("s", "802-11-wireless"),
["autoconnect"] = lgi.GLib.Variant("b", auto_connect),
},
["ipv4"] = {
["method"] = lgi.GLib.Variant("s", "auto")
},
["ipv6"] = {
["method"] = lgi.GLib.Variant("s", "auto"),
},
["802-11-wireless"] = {
["mode"] = lgi.GLib.Variant("s", "infrastructure"),
},
["802-11-wireless-security"] = s_wsec ["802-11-wireless-security"] = s_wsec
} }
end end
---Scan for access points and create a widget for each one.
function network:scan_access_points() function network:scan_access_points()
self._private.access_points = {} local ap_list = self:get_children_by_id("wifi_ap_list")[1]
self._private.wifi_proxy:RequestScanAsync(function(proxy, context, success, failure) self._private.NetworkManagerDeviceWireless:RequestScanAsync(function(proxy, context, success, failure)
if failure ~= nil then if failure then
self.access_points = { layout = wibox.layout.fixed.vertical } -- Send an error notification
self:emit_signal("NM::AccessPointsFound", self.access_points[1].ssid) print("AP Scan failed: ", failure)
self:emit_signal("NM::ScanFailed", tostring(failure))
return return
end end
local access_points = self._private.wifi_proxy:GetAllAccessPoints() -- Get every access point even those who hide their ssid
print(#self._private.NetworkManagerDeviceWireless:GetAllAccessPoints())
for _, ap in ipairs(self._private.NetworkManagerDeviceWireless:GetAllAccessPoints()) do
self._private.access_points = {} -- Create a new proxy for every ap
if (not access_point) or (#access_points == 0) then local NetworkManagerAccessPoint = dbus_proxy.Proxy:new {
self.access_points = { layout = wibox.layout.fixed.vertical }
self:emit_signal("NM::AccessPointsFound", self.access_points[1].ssid)
end
for _, ap in ipairs(access_points) do
local access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM, bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager", name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint", interface = "org.freedesktop.NetworkManager.AccessPoint",
path = ap path = ap
} }
--[[ for _, ap2 in ipairs(ap_list.children) do
if access_point_proxy.Ssid then if ap2.NetworkManagerAccessPoint.HwAddress:match(ap.HwAddress or "") then
local appSsid = access_point_proxy.Ssid or "" goto continue
local ssid = NM.utils_ssid_to_utf8(appSsid) or ""
local security = flags_to_security(access_point_proxy.Flags, access_point_proxy.WpaFlags)
local password = ""
local connections = get_access_point_connections(self, ssid)
for _, connection in ipairs(connections) do
if connection.Filename:find(ssid) then
local secrets = connection:GetSecrets("802-11-wireless-security")
if secrets then
password = secrets["802-11-wireless-security"].psk
end end
end ]]
print("AP Found: ", NetworkManagerAccessPoint.HwAddress, NM.utils_ssid_to_utf8(NetworkManagerAccessPoint.Ssid),
NetworkManagerAccessPoint.Strength)
-- We are only interested in those with a ssid
if NetworkManagerAccessPoint.Ssid then
ap_list:add(access_point { NetworkManagerAccessPoint = NetworkManagerAccessPoint })
end end
end end
table.insert(self._private.access_points, { table.sort(ap_list, function(a, b)
ssid = ssid, return a.NetworkManagerAccessPoint.Strength > b.NetworkManagerAccessPoint.Strength
security = security,
password = password,
strength = access_point_proxy.Strength,
hw_address = access_point_proxy.HwAddress,
device_interface = self._private.device_proxy.Interface,
device_path = self._private.device_proxy.object_path,
access_point_path = ap
})
end
end
self.access_points = { layout = wibox.layout.fixed.vertical }
local seen = {}
for _, ap2 in ipairs(self._private.access_points) do
if not seen[ap2.ssid] then
seen[ap2.ssid] = true
table.insert(self.access_points,
access_point.new { access_point = ap2, active = self._private.wifi_proxy.ActiveAccessPoint }.widget)
end
end
table.sort(self._private.access_points, function(a, b)
return a.strength > b.strength
end) end)
print("AP_Anzahl: ", #ap_list.children)
self:emit_signal("NM::AccessPointsFound", self.access_points[1].ssid)
end, { call_id = "my-id" }, {}) end, { call_id = "my-id" }, {})
end end
function network:toggle()
self.container.visible = not self.container.visible
end
function network:is_ap_active(ap) function network:is_ap_active(ap)
print(self._private.wifi_proxy.ActiveAccessPoint)
return ap.path == self._private.wifi_proxy.ActiveAccessPoint return ap.path == self._private.wifi_proxy.ActiveAccessPoint
end end
function network:disconnect_ap() function network:disconnect_ap()
self._private.client_proxy:DeactivateConnection(self._private.device_proxy.ActiveConnection) self._private.NetworkManager:DeactivateConnection(self._private.NetworkManagerDevice.ActiveConnection)
end end
function network:connect_ap(ap, pw, auto_connect) function network:connect_ap(ap, pw, auto_connect)
local connections = get_access_point_connections(self, ap.ssid) local connections = self:get_access_point_connections(ap.ssid)
local profile = create_profile(ap, pw, auto_connect) local profile = self:create_profile(ap, pw, auto_connect)
if #connections == 0 then if #connections == 0 then
self._private.client_proxy:AddAndActivateConnectionAsync(function(proxy, context, success, failure) self._private.NetworkManager:AddAndActivateConnectionAsync(function(proxy, context, success, failure)
if failure then if failure then
self:emit_signal("NM::AccessPointFailed", tostring(failure)) self:emit_signal("NM::AccessPointFailed", tostring(failure))
return return
@@ -318,7 +269,7 @@ function network:connect_ap(ap, pw, auto_connect)
end, { call_id = "my-id", profile, ap.device_proxy_path, ap.path }) end, { call_id = "my-id", profile, ap.device_proxy_path, ap.path })
else else
connections[1]:Update(profile) connections[1]:Update(profile)
self._private.client_proxy:ActivateConnectionAsync(function(proxy, context, success, failure) self._private.NetworkManager:ActivateConnectionAsync(function(proxy, context, success, failure)
if failure then if failure then
self:emit_signal("NM::AccessPointFailed", tostring(failure)) self:emit_signal("NM::AccessPointFailed", tostring(failure))
return return
@@ -337,89 +288,21 @@ function network:toggle_access_point(ap, password, auto_connect)
end end
end end
function network:toggle_wireless() ---Toggles networking on or off
local enable = not self._private.client_proxy.WirelessEnabled function network:toggle_wifi()
local enable = not self._private.NetworkManager.WirelessEnabled
if enable then if enable then
self._private.client_proxy:Enable(true) self._private.NetworkManager.Enable(true)
end end
self._private.client_proxy:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable)) self._private.NetworkManager:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable))
self._private.NetworkManager.WirelessEnabled = { signature = "b", value = enable }
return enable
end end
function network.new(args) function network.new(args)
args = args or {} args = args or {}
local ret = gobject {} local ret = base.make_widget_from_value(wibox.widget {
gtable.crush(ret, network, true)
ret._private = {}
ret._private.client_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager",
path = "/org/freedesktop/NetworkManager",
}
ret._private.settings_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Settings",
path = "/org/freedesktop/NetworkManager/Settings",
}
local property_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.DBus.Properties",
path = "/org/freedesktop/NetworkManager",
}
-- dbus proxy signals are in reversed order (function, signal)
property_proxy:connect_signal(function(_, properties, data)
if data.WirelessEnables ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then
ret._private.WirelessEnabled = data.WirelessEnabled
ret:emit_signal("NM::WirelessStateChanged", ret._private.WirelessEnabled)
if data.WirelessEnabled then
gtimer {
timeout = 5,
autostart = true,
call_now = false,
single_shot = true,
callback = function()
ret:get_access_points()
end
}
end
end
end, "PropertiesChanged")
get_wifi_proxy(ret)
ret:scan_access_points()
gtimer.delayed_call(function()
ret:emit_signal("NM::WirelessStateChanged", ret._private.client_proxy.WirelessEnabled)
local active_access_point = ret._private.wifi_proxy.ActiveAccessPoint
if ret._private.device_proxy.State == network.DeviceState.ACTIVATED and active_access_point ~= "/" then
local active_access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint",
path = active_access_point,
}
local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid)
ret:emit_signal("NM:AccessPointConnected", ssid, active_access_point_proxy.Strength)
end
end)
local network_widget = wibox.widget {
{ {
{ {
{ {
@@ -488,6 +371,17 @@ function network.new(args)
}, },
{ {
{ -- action buttons { -- action buttons
{
dnd_widget {
color = Theme_config.network_manager.power_icon_color,
size = dpi(40)
},
id = "dnd",
widget = wibox.container.place,
valign = "center",
halign = "center"
},
nil,
{ -- refresh { -- refresh
{ {
{ {
@@ -512,31 +406,6 @@ function network.new(args)
widget = wibox.container.background, widget = wibox.container.background,
id = "refresh" id = "refresh"
}, },
nil,
{ -- airplane mode
{
{
image = gcolor.recolor_image(icondir .. "airplane-off.svg",
Theme_config.network_manager.airplane_icon_color),
resize = false,
valign = "center",
halign = "center",
widget = wibox.widget.imagebox,
id = "icon"
},
widget = wibox.container.margin,
margins = dpi(5),
id = "center",
},
border_width = dpi(2),
border_color = Theme_config.network_manager.border_color,
shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(4))
end,
bg = Theme_config.network_manager.refresh_bg,
widget = wibox.container.background,
id = "airplane"
},
layout = wibox.layout.align.horizontal layout = wibox.layout.align.horizontal
}, },
widget = wibox.container.margin, widget = wibox.container.margin,
@@ -562,54 +431,82 @@ function network.new(args)
width = dpi(400), width = dpi(400),
strategy = "exact", strategy = "exact",
widget = wibox.container.constraint widget = wibox.container.constraint
})
local dnd = ret:get_children_by_id("dnd")[1]:get_widget()
dnd:connect_signal("dnd::toggle", function(enable)
ret:toggle_wifi()
end)
gtable.crush(ret, network, true)
--#region Wifi Proxies
ret._private.NetworkManager = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager",
path = "/org/freedesktop/NetworkManager",
} }
local refresh_button = network_widget:get_children_by_id("refresh")[1] ret._private.NetworkManagerSettings = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Settings",
path = "/org/freedesktop/NetworkManager/Settings",
}
refresh_button:buttons( ret._private.NetworkManagerProperties = dbus_proxy.Proxy:new {
gtable.join( bus = dbus_proxy.Bus.SYSTEM,
awful.button( name = "org.freedesktop.NetworkManager",
{}, interface = "org.freedesktop.DBus.Properties",
1, path = "/org/freedesktop/NetworkManager",
nil, }
function()
ret._private.NetworkManagerProperties:connect_signal(function(_, properties, data)
if data.WirelessEnables ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then
ret._private.WirelessEnabled = data.WirelessEnabled
ret:emit_signal("NetworkManager::status", ret._private.WirelessEnabled)
print(ret._private.WirelessEnabled)
if data.WirelessEnabled then
gtimer {
timeout = 5,
autostart = true,
call_now = false,
single_shot = true,
callback = function()
ret:scan_access_points() ret:scan_access_points()
end end
) }
)
)
Hover_signal(refresh_button)
local airplane_button = network_widget:get_children_by_id("airplane")[1]
airplane_button:buttons(
gtable.join(
awful.button(
{},
1,
nil,
function()
if ret:toggle_wireless() then
airplane_button.center.icon.image = gcolor.recolor_image(icondir
.. "airplane-off.svg",
Theme_config.network_manager.airplane_icon_color)
else
airplane_button.center.icon.image = gcolor.recolor_image(icondir
.. "airplane-on.svg",
Theme_config.network_manager.airplane_icon_color)
end end
end
end, "PropertiesChanged")
ret:get_wifi_proxy()
ret:scan_access_points() ret:scan_access_points()
gtimer.delayed_call(function()
local active_access_point = ret._private.NetworkManagerDeviceWireless.ActiveAccessPoint
if ret._private.NetworkManager.State == network.DeviceState.ACTIVATED and active_access_point ~= "/" then
local active_access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint",
path = active_access_point,
}
end end
) end)
)
)
Hover_signal(airplane_button) --#endregion
local wifi_margin = network_widget:get_children_by_id("wifi_margin")[1] --#region Dropdown logic
local wifi_list = network_widget:get_children_by_id("wifi_list")[1] local wifi_margin = ret:get_children_by_id("wifi_margin")[1]
local wifi = network_widget:get_children_by_id("wifi")[1].center local wifi_list = ret:get_children_by_id("wifi_list")[1]
local wifi = ret:get_children_by_id("wifi")[1].center
local rubato_timer = rubato.timed { local rubato_timer = rubato.timed {
duration = 0.2, duration = 0.2,
@@ -620,15 +517,14 @@ function network.new(args)
end end
} }
wifi_margin:buttons( wifi_margin:buttons(gtable.join(
gtable.join( awful.button({}, 1, nil,
awful.button(
{},
1,
nil,
function() function()
if wifi_list.forced_height == 0 then if wifi_list.forced_height == 0 then
local size = (#ret.access_points * 49) + 1 if not ret:get_children_by_id("wifi_ap_list")[1].children then
return
end
local size = (5 * 49) + 1
size = size > 210 and 210 or size size = size > 210 and 210 or size
@@ -648,36 +544,20 @@ function network.new(args)
end end
end end
) )
) ))
) --#endregion
ret.widget = awful.popup { local refresh_button = ret:get_children_by_id("refresh")[1]
widget = network_widget, refresh_button:buttons(gtable.join(
bg = Theme_config.network_manager.bg, awful.button({}, 1, nil,
screen = args.screen, function()
stretch = false,
visible = false,
ontop = true,
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(350), top = dpi(60) } })
end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end
}
capi.awesome.connect_signal("NM::toggle_container", function()
ret.widget.visible = not ret.widget.visible
ret:scan_access_points() ret:scan_access_points()
end) end
)
))
Hover_signal(refresh_button)
capi.awesome.connect_signal("NM::toggle_wifi", function() return ret
ret:toggle_wireless()
end)
ret:connect_signal("NM::AccessPointsFound", function(tab)
network_widget:get_children_by_id("wifi_ap_list")[1].children = ret.access_points
end)
end end
function network.mt:__call(...) function network.mt:__call(...)

View File

@@ -7,8 +7,7 @@ local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears") local gears = require("gears")
local wibox = require("wibox") local wibox = require("wibox")
local dnd_widget = require("awful.widget.toggle_widget")
local rubato = require("src.lib.rubato")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
@@ -19,6 +18,17 @@ local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/no
return function(s) return function(s)
local dnd = dnd_widget({
text = "Do not disturb",
color = Theme_config.notification_center.dnd_color,
fg = Theme_config.notification_center.dnd_fg,
size = dpi(40)
})
dnd:get_widget():connect_signal("dnd::toggle", function(enabled)
User_config.dnd = enabled
end)
--#region Activation area --#region Activation area
local activation_area = awful.popup { local activation_area = awful.popup {
@@ -90,121 +100,6 @@ return function(s)
halign = "right", halign = "right",
} }
local color = Theme_config.notification_center.dnd.disabled
local function toggle_animation(pos)
if pos > 43 then return end
return function(_, _, cr, width, height)
cr:set_source(gears.color(Theme_config.notification_center.dnd.bg));
cr:paint();
cr:set_source(gears.color(color))
cr:move_to(pos, 0)
local x = pos
local y = 5
local newwidth = width / 2 - 10
local newheight = height - 10
local radius = height / 6.0
local degrees = math.pi / 180.0;
cr:new_sub_path()
cr:arc(x + newwidth - radius, y + radius, radius, -90 * degrees, 0 * degrees)
cr:arc(x + newwidth - radius, y + newheight - radius, radius, 0 * degrees, 90 * degrees)
cr:arc(x + radius, y + newheight - radius, radius, 90 * degrees, 180 * degrees)
cr:arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
cr:close_path()
cr:fill()
end
end
local rubato_timed
local toggle_button = wibox.widget {
{
widget = wibox.widget {
fit = function(_, width, height)
return width, height
end,
draw = toggle_animation(0),
},
id = "background",
},
active = false,
widget = wibox.container.background,
bg = Theme_config.notification_center.dnd.bg,
border_color = Theme_config.notification_center.dnd.border_disabled,
border_width = dpi(2),
forced_height = dpi(40),
forced_width = dpi(80),
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(10))
end,
}
toggle_button:buttons(
gears.table.join(
awful.button({}, 1, function()
if toggle_button.active then
toggle_button.active = not toggle_button.active
toggle_button.border_color = Theme_config.notification_center.dnd.border_disabled
color = Theme_config.notification_center.dnd.disabled
User_config.dnd = false
rubato_timed.target = 5
else
toggle_button.active = not toggle_button.active
toggle_button.border_color = Theme_config.notification_center.dnd.border_enabled
color = Theme_config.notification_center.dnd.enabled
User_config.dnd = true
rubato_timed.target = 43
end
end
)
)
)
rubato_timed = rubato.timed {
duration = 0.5,
pos = 5,
subscribed = function(pos)
toggle_button:get_children_by_id("background")[1].draw = toggle_animation(pos)
toggle_button:emit_signal("widget::redraw_needed")
end
}
local dnd = wibox.widget {
{
{
{
{
text = "Do Not Disturb",
valign = "center",
align = "center",
widget = wibox.widget.textbox,
id = "clearall"
},
toggle_button,
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
id = "layout12"
},
id = "background4",
fg = Theme_config.notification_center.dnd.fg,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end,
forced_height = dpi(40),
widget = wibox.container.background
},
id = "margin3",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
widget = wibox.container.place,
valign = "bottom",
halign = "right",
}
local no_notification_widget = wibox.widget { local no_notification_widget = wibox.widget {
{ {
{ {
@@ -287,8 +182,13 @@ return function(s)
height = dpi(400), height = dpi(400),
widget = wibox.container.constraint widget = wibox.container.constraint
}, },
{
{ {
dnd, dnd,
widget = wibox.container.place,
valign = "center",
halign = "center"
},
nil, nil,
clear_all_widget, clear_all_widget,
layout = wibox.layout.align.horizontal layout = wibox.layout.align.horizontal

View File

@@ -1,249 +0,0 @@
--------------------------------
-- This is the network widget --
--------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/powermenu/"
return function(s)
-- Profile picture imagebox
local profile_picture = wibox.widget {
image = icondir .. "defaultpfp.svg",
resize = true,
forced_height = dpi(200),
clip_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(30))
end,
valign = "center",
halign = "center",
widget = wibox.widget.imagebox
}
-- Username textbox
local profile_name = wibox.widget {
align = 'center',
valign = 'center',
text = " ",
font = "JetBrains Mono Bold 30",
widget = wibox.widget.textbox
}
-- Get the profile script from /var/lib/AccountsService/icons/${USER}
-- and copy it to the assets folder
-- TODO: If the user doesnt have AccountsService look into $HOME/.faces
local update_profile_picture = function()
awful.spawn.easy_async_with_shell(
"./.config/awesome/src/scripts/pfp.sh 'userPfp'",
function(stdout)
if stdout then
profile_picture:set_image(stdout:gsub("\n", ""))
else
profile_picture:set_image(icondir .. "defaultpfp.svg")
end
end
)
end
update_profile_picture()
-- Get the full username(if set) and the username + hostname
local update_user_name = function()
awful.spawn.easy_async_with_shell(
"./.config/awesome/src/scripts/pfp.sh 'userName' '" .. User_config.namestyle .. "'",
function(stdout)
if stdout:gsub("\n", "") == "Rick Astley" then
profile_picture:set_image(gears.filesystem.get_configuration_dir() .. "src/assets/userpfp/" .. "rickastley.jpg")
end
profile_name:set_text(stdout)
end
)
end
update_user_name()
-- Universal Button widget
local button = function(name, icon, bg_color, callback)
local item = wibox.widget {
{
{
{
{
-- TODO: using gears.color to recolor a SVG will make it look super low res
-- currently I recolor it in the .svg file directly, but later implement
-- a better way to recolor a SVG
image = icon,
resize = true,
forced_height = dpi(30),
valign = "center",
halign = "center",
widget = wibox.widget.imagebox
},
{
text = name,
font = "JetBrains Mono Bold 30",
widget = wibox.widget.textbox
},
widget = wibox.layout.fixed.horizontal
},
margins = dpi(10),
widget = wibox.container.margin
},
fg = Theme_config.powermenu.button_fg,
bg = bg_color,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(10))
end,
widget = wibox.container.background,
id = 'background'
},
layout = wibox.layout.align.vertical
}
item:connect_signal(
"button::release",
function()
callback()
end
)
return item
end
-- Create the power menu actions
local suspend_command = function()
awful.spawn("systemctl suspend")
capi.awesome.emit_signal("module::powermenu:hide")
end
local logout_command = function()
capi.awesome.quit()
end
local lock_command = function()
awful.spawn("dm-tool lock")
capi.awesome.emit_signal("module::powermenu:hide")
end
local shutdown_command = function()
awful.spawn("shutdown now")
capi.awesome.emit_signal("module::powermenu:hide")
end
local reboot_command = function()
awful.spawn("reboot")
capi.awesome.emit_signal("module::powermenu:hide")
end
-- Create the buttons with their command and name etc
local shutdown_button = button("Shutdown", icondir .. "shutdown.svg", Theme_config.powermenu.shutdown_button_bg,
shutdown_command)
local reboot_button = button("Reboot", icondir .. "reboot.svg", Theme_config.powermenu.reboot_button_bg, reboot_command)
local suspend_button = button("Suspend", icondir .. "suspend.svg", Theme_config.powermenu.suspend_button_bg,
suspend_command)
local logout_button = button("Logout", icondir .. "logout.svg", Theme_config.powermenu.logout_button_bg, logout_command)
local lock_button = button("Lock", icondir .. "lock.svg", Theme_config.powermenu.lock_button_bg, lock_command)
-- Signals to change color on hover
Hover_signal(shutdown_button.background)
Hover_signal(reboot_button.background)
Hover_signal(suspend_button.background)
Hover_signal(logout_button.background)
Hover_signal(lock_button.background)
-- The powermenu widget
local powermenu = wibox.widget {
{
{
profile_picture,
profile_name,
spacing = dpi(50),
layout = wibox.layout.fixed.vertical
},
{
{
shutdown_button,
reboot_button,
logout_button,
lock_button,
suspend_button,
spacing = dpi(30),
layout = wibox.layout.fixed.horizontal
},
halign = "center",
valign = "center",
widget = wibox.container.place
},
layout = wibox.layout.fixed.vertical
},
halign = "center",
valign = "center",
widget = wibox.container.place
}
-- Container for the widget, covers the entire screen
local powermenu_container = wibox {
widget = powermenu,
screen = s,
type = "splash",
visible = false,
ontop = true,
bg = Theme_config.powermenu.container_bg,
height = s.geometry.height,
width = s.geometry.width,
x = s.geometry.x,
y = s.geometry.y
}
-- Close on rightclick
powermenu_container:buttons(
gears.table.join(
awful.button(
{},
3,
function()
capi.awesome.emit_signal("module::powermenu:hide")
end
)
)
)
-- Close on Escape
local powermenu_keygrabber = awful.keygrabber {
autostart = false,
stop_event = 'release',
keypressed_callback = function(self, mod, key, command)
if key == 'Escape' then
capi.awesome.emit_signal("module::powermenu:hide")
end
end
}
-- Signals
capi.awesome.connect_signal(
"module::powermenu:show",
function()
if s == capi.mouse.screen then
powermenu_container.visible = true
powermenu_keygrabber:start()
end
end
)
capi.awesome.connect_signal(
"module::powermenu:hide",
function()
powermenu_keygrabber:stop()
powermenu_container.visible = false
end
)
end

View File

@@ -1,447 +0,0 @@
-----------------------------------
-- This is the titlebar module --
-----------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
client = client
}
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/titlebar/"
awful.titlebar.enable_tooltip = true
awful.titlebar.fallback_name = 'Client'
-- Normal AND Focus(active/inactive) have to be set or errors will appear in stdout
Theme.titlebar_close_button_normal = icondir .. "close.svg"
Theme.titlebar_close_button_focus = icondir .. "close.svg"
Theme.titlebar_minimize_button_normal = icondir .. "minimize.svg"
Theme.titlebar_minimize_button_focus = icondir .. "minimize.svg"
Theme.titlebar_maximized_button_normal = icondir .. "maximize.svg"
Theme.titlebar_maximized_button_active = icondir .. "maximize.svg"
Theme.titlebar_maximized_button_inactive = icondir .. "maximize.svg"
local create_buttons = function(c)
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
)
)
return buttons
end
local create_titlebar = function(c, size, position)
local close_button = awful.titlebar.widget.closebutton(c)
local minimize_button = awful.titlebar.widget.minimizebutton(c)
local maximize_button = awful.titlebar.widget.maximizedbutton(c)
local tb
if position == "left" then
local titlebar = awful.titlebar(c, {
position = "left",
bg = Theme_config.titlebar.bg,
size = size
})
tb = wibox.widget {
{
{
{
close_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.close_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "closebutton"
},
{
maximize_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.maximize_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "maximizebutton"
},
{
minimize_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.minimize_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "minimizebutton"
},
spacing = dpi(10),
layout = wibox.layout.fixed.vertical,
id = "spacing"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "margin"
},
{
buttons = create_buttons(c),
layout = wibox.layout.flex.vertical
},
{
awful.titlebar.widget.iconwidget(c),
margins = dpi(5),
widget = wibox.container.margin
},
layout = wibox.layout.align.vertical,
id = "main"
}
titlebar:setup { tb, layout = wibox.layout.fixed.horizontal }
elseif position == "top" then
local titlebar = awful.titlebar(c, {
position = "top",
bg = Theme_config.titlebar.bg,
size = size
})
tb = wibox.widget {
{
awful.titlebar.widget.iconwidget(c),
margins = dpi(5),
widget = wibox.container.margin
},
{
{
awful.titlebar.widget.titlewidget(c),
valign = "center",
halign = "center",
layout = wibox.container.place,
},
buttons = create_buttons(c),
fill_space = true,
layout = wibox.layout.stack
},
{
{
{
minimize_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.minimize_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "minimizebutton"
},
{
maximize_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.maximize_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "maximizebutton"
},
{
close_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.close_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "closebutton"
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
id = "spacing"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "margin"
},
layout = wibox.layout.align.horizontal,
id = "main"
}
titlebar:setup { tb, layout = wibox.layout.fixed.vertical }
end
if not tb then return end
close_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.close_button.hover_border
local cb = tb:get_children_by_id("closebutton")[1]
cb.border_color = Theme_config.titlebar.close_button.hover_border
cb.bg = Theme_config.titlebar.close_button.hover_bg
end
)
close_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local cb = tb:get_children_by_id("closebutton")[1]
cb.border_color = Theme_config.titlebar.close_button.border_color
cb.bg = Theme_config.titlebar.close_button.bg
end
)
minimize_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.minimize_button.hover_border
local mb = tb:get_children_by_id("minimizebutton")[1]
mb.border_color = Theme_config.titlebar.minimize_button.hover_border
mb.bg = Theme_config.titlebar.minimize_button.hover_bg
end
)
minimize_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local mb = tb:get_children_by_id("minimizebutton")[1]
mb.border_color = Theme_config.titlebar.minimize_button.border_color
mb.bg = Theme_config.titlebar.minimize_button.bg
end
)
maximize_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.maximize_button.hover_border
local mb = tb:get_children_by_id("maximizebutton")[1]
mb.border_color = Theme_config.titlebar.maximize_button.hover_border
mb.bg = Theme_config.titlebar.maximize_button.hover_bg
end
)
maximize_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local mb = tb:get_children_by_id("maximizebutton")[1]
mb.border_color = Theme_config.titlebar.maximize_button.border_color
mb.bg = Theme_config.titlebar.maximize_button.bg
end
)
end
local create_titlebar_dialog_modal = function(c, size, position)
local close_button = awful.titlebar.widget.closebutton(c)
local minimize_button = awful.titlebar.widget.minimizebutton(c)
local maximize_button = awful.titlebar.widget.maximizedbutton(c)
local tb
if position == "left" then
local titlebar = awful.titlebar(c, {
position = "left",
bg = Theme_config.titlebar.bg,
size = size
})
tb = wibox.widget {
{
{
close_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.close_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "closebutton"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "margin"
},
{
buttons = create_buttons(c),
layout = wibox.layout.flex.vertical
},
{
awful.titlebar.widget.iconwidget(c),
margins = dpi(5),
widget = wibox.container.margin
},
layout = wibox.layout.align.vertical,
id = "main"
}
titlebar:setup { tb, layout = wibox.layout.fixed.horizontal }
elseif position == "top" then
local titlebar = awful.titlebar(c, {
position = "top",
bg = Theme_config.titlebar.bg,
size = size
})
tb = wibox.widget {
{
awful.titlebar.widget.iconwidget(c),
margins = dpi(5),
widget = wibox.container.margin
},
{
{
awful.titlebar.widget.titlewidget(c),
valign = "center",
halign = "center",
layout = wibox.container.place,
},
buttons = create_buttons(c),
fill_space = true,
layout = wibox.layout.stack
},
{
{
close_button,
widget = wibox.container.background,
border_color = Theme_config.titlebar.close_button.border_color,
border_width = dpi(2),
shape = function(cr, height, width)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
id = "closebutton"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "margin"
},
layout = wibox.layout.align.horizontal,
id = "main"
}
titlebar:setup { tb, layout = wibox.layout.fixed.vertical }
end
if not tb then return end
close_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.close_button.hover_border
local cb = tb:get_children_by_id("closebutton")[1]
cb.border_color = Theme_config.titlebar.close_button.hover_border
cb.bg = Theme_config.titlebar.close_button.hover_bg
end
)
close_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local cb = tb:get_children_by_id("closebutton")[1]
cb.border_color = Theme_config.titlebar.close_button.border_color
cb.bg = Theme_config.titlebar.close_button.bg
end
)
minimize_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.minimize_button.hover_border
local mb = tb:get_children_by_id("minimizebutton")[1]
mb.border_color = Theme_config.titlebar.minimize_button.hover_border
mb.bg = Theme_config.titlebar.minimize_button.hover_bg
end
)
minimize_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local mb = tb:get_children_by_id("minimizebutton")[1]
mb.border_color = Theme_config.titlebar.minimize_button.border_color
mb.bg = Theme_config.titlebar.minimize_button.bg
end
)
maximize_button:connect_signal(
"mouse::enter",
function()
c.border_color = Theme_config.titlebar.maximize_button.hover_border
local mb = tb:get_children_by_id("maximizebutton")[1]
mb.border_color = Theme_config.titlebar.maximize_button.hover_border
mb.bg = Theme_config.titlebar.maximize_button.hover_bg
end
)
maximize_button:connect_signal(
"mouse::leave",
function()
c.border_color = Theme_config.window.border_normal
local mb = tb:get_children_by_id("maximizebutton")[1]
mb.border_color = Theme_config.titlebar.maximize_button.border_color
mb.bg = Theme_config.titlebar.maximize_button.bg
end
)
end
capi.client.connect_signal(
"request::titlebars",
function(c)
if c.type == "dialog" then
create_titlebar_dialog_modal(c, dpi(35), User_config.titlebar_position)
elseif c.type == "modal" then
create_titlebar_dialog_modal(c, dpi(35), User_config.titlebar_position)
else
create_titlebar(c, dpi(35), User_config.titlebar_position)
end
if not c.floating or c.maximized or c.fullscreen then
if User_config.titlebar_position == "left" then
awful.titlebar.hide(c, "left")
elseif User_config.titlebar_position == "top" then
awful.titlebar.hide(c, "top")
end
end
end
)
capi.client.connect_signal(
"property::floating",
function(c)
if c.floating and not (c.maximized or c.fullscreen) then
if User_config.titlebar_position == "left" then
awful.titlebar.show(c, "left")
elseif User_config.titlebar_position == "top" then
awful.titlebar.show(c, "top")
end
else
if User_config.titlebar_position == "left" then
awful.titlebar.hide(c, "left")
elseif User_config.titlebar_position == "top" then
awful.titlebar.hide(c, "top")
end
end
end
)

View File

@@ -1,725 +0,0 @@
-----------------------------------
-- This is the volume controller --
-----------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mousegrabber = mousegrabber,
}
local rubato = require("src.lib.rubato")
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/audio/"
-- Returns the volume controller
return function(s)
-- Function to create source/sink devices
local function create_device(name, node, sink)
local device = wibox.widget {
{
{
{
id = "icon",
resize = false,
valign = "center",
halign = "center",
widget = wibox.widget.imagebox
},
spacing = dpi(10),
{
text = name,
id = "node",
widget = wibox.widget.textbox
},
id = "device_layout",
layout = wibox.layout.fixed.horizontal
},
id = "device_margin",
margins = dpi(9),
widget = wibox.container.margin
},
id = "background",
bg = Theme_config.volume_controller.device_bg,
border_color = Theme_config.volume_controller.device_border_color,
border_width = Theme_config.volume_controller.device_border_width,
shape = Theme_config.volume_controller.device_shape,
widget = wibox.container.background
}
if sink == true then
device:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
if node then
awful.spawn("./.config/awesome/src/scripts/vol.sh set_sink " .. node)
capi.awesome.emit_signal("update::bg_sink", node)
end
end
end
)
capi.awesome.connect_signal(
"update::bg_sink",
function(new_node)
if node == new_node then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_headphones_selected_bg
device.fg = Theme_config.volume_controller.device_headphones_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_headphones_fg
Hover_signal(device)
end
end
)
awful.spawn.easy_async_with_shell(
[[ pactl get-default-sink ]],
function(stdout)
local node_active = stdout:gsub("\n", "")
if node == node_active then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_headphones_selected_bg
device.fg = Theme_config.volume_controller.device_headphones_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_headphones_fg
Hover_signal(device)
end
end
)
capi.awesome.emit_signal("update::bg_sink", node)
else
device:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
if node then
awful.spawn("./.config/awesome/src/scripts/mic.sh set_source " .. node)
capi.awesome.emit_signal("update::bg_source", node)
end
end
end
)
capi.awesome.connect_signal(
"update::bg_source",
function(new_node)
if node == new_node then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_microphone_selected_bg
device.fg = Theme_config.volume_controller.device_microphone_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_microphone_fg
Hover_signal(device)
end
end
)
awful.spawn.easy_async_with_shell(
[[ pactl get-default-source ]],
function(stdout)
local node_active = stdout:gsub("\n", "")
if node == node_active then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_microphone_selected_bg
device.fg = Theme_config.volume_controller.device_microphone_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_microphone_fg
Hover_signal(device)
end
end
)
capi.awesome.emit_signal("update::bg_source", node)
end
return device
end
-- Container for the source devices
local dropdown_list_volume = wibox.widget {
{
{
{
{
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
step = dpi(50),
id = "volume_device_list",
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
id = "volume_device_background",
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
}
-- Container for the sink devices
local dropdown_list_microphone = wibox.widget {
{
{
{
{
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
id = "volume_device_list",
scrollbar_width = 0,
step = dpi(50),
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
id = "volume_device_background",
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
}
local volume_controller = wibox.widget {
{
{
-- Audio Device selector
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon"
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Output Device",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "audio_volume",
layout = wibox.layout.fixed.horizontal
},
id = "audio_bg",
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_headphones_fg,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
id = "audio_selector_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
{
id = "volume_list",
widget = dropdown_list_volume,
forced_height = 0
},
-- Microphone selector
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon",
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Input Device",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "mic_volume",
layout = wibox.layout.fixed.horizontal
},
id = "mic_bg",
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_microphone_fg,
shape = Theme_config.volume_controller.selector_shape,
widget = wibox.container.background
},
id = "mic_selector_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
{
id = "mic_list",
widget = dropdown_list_microphone,
forced_height = 0
},
-- Audio volume slider
{
{
{
resize = false,
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "volume-high.svg", Theme_config.volume_controller.volume_fg),
id = "icon",
},
{
{
bar_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.border_color,
bar_active_color = Theme_config.volume_controller.volume_fg,
handle_color = Theme_config.volume_controller.volume_fg,
handle_shape = gears.shape.circle,
handle_border_color = Theme_config.volume_controller.volume_fg,
handle_width = dpi(12),
maximum = 100,
forced_height = dpi(26),
widget = wibox.widget.slider,
id = "slider"
},
left = dpi(5),
id = "slider_margin",
widget = wibox.container.margin
},
id = "audio_volume",
layout = wibox.layout.align.horizontal
},
id = "audio_volume_margin",
top = dpi(10),
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
},
-- Microphone volume slider
{
{
{
resize = false,
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "microphone.svg", Theme_config.volume_controller.microphone_fg),
id = "icon"
},
{
{
bar_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.device_border_color,
bar_active_color = Theme_config.volume_controller.microphone_fg,
handle_color = Theme_config.volume_controller.microphone_fg,
handle_shape = gears.shape.circle,
handle_border_color = Theme_config.volume_controller.microphone_fg,
handle_width = dpi(12),
maximum = 100,
forced_height = dpi(26),
widget = wibox.widget.slider,
id = "slider"
},
left = dpi(5),
id = "slider_margin",
widget = wibox.container.margin
},
id = "mic_volume",
layout = wibox.layout.align.horizontal
},
id = "mic_volume_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
id = "controller_layout",
layout = wibox.layout.fixed.vertical
},
id = "controller_margin",
margins = dpi(10),
widget = wibox.container.margin
},
bg = Theme_config.volume_controller.bg,
border_color = Theme_config.volume_controller.border_color,
border_width = Theme_config.volume_controller.border_width,
shape = Theme_config.volume_controller.shape,
forced_width = dpi(400),
widget = wibox.container.background
}
-- Variables for easier access and better readability
local audio_selector_margin = volume_controller:get_children_by_id("audio_selector_margin")[1]
local volume_list = volume_controller:get_children_by_id("volume_list")[1]
local audio_bg = volume_controller:get_children_by_id("audio_bg")[1]
local audio_volume = volume_controller:get_children_by_id("audio_volume")[1].center
-- Click event for the audio dropdown
audio_selector_margin:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = volume_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
volume_list.forced_height = v
end
}
if volume_list.forced_height == 0 then
rubato_timer.target = dpi(200)
audio_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
audio_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color))
else
rubato_timer.target = 0
audio_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end
audio_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color))
end
end
end
)
-- Variables for easier access and better readability
local mic_selector_margin = volume_controller:get_children_by_id("mic_selector_margin")[1]
local mic_list = volume_controller:get_children_by_id("mic_list")[1]
local mic_bg = volume_controller:get_children_by_id("mic_bg")[1]
local mic_volume = volume_controller:get_children_by_id("mic_volume")[1].center
-- Click event for the microphone dropdown
mic_selector_margin:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = mic_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
mic_list.forced_height = v
end
}
if mic_list.forced_height == 0 then
rubato_timer.target = dpi(200)
mic_selector_margin.mic_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color))
else
rubato_timer.target = 0
mic_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end
mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color))
end
end
end
)
local audio_slider_margin = volume_controller:get_children_by_id("audio_volume_margin")[1].audio_volume.slider_margin.slider
-- Volume slider change event
audio_slider_margin:connect_signal(
"property::value",
function()
awful.spawn.with_shell("pactl set-sink-volume @DEFAULT_SINK@ " .. tonumber(audio_slider_margin.value) .. "%")
end
)
local mic_slider_margin = volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.slider_margin.slider
-- Microphone slider change event
mic_slider_margin:connect_signal(
"property::value",
function()
awful.spawn("pactl set-source-volume @DEFAULT_SOURCE@ " .. tonumber(mic_slider_margin.value) .. "%")
end
)
-- Main container
local volume_controller_container = awful.popup {
widget = wibox.container.background,
ontop = true,
bg = Theme_config.volume_controller.bg,
stretch = false,
visible = false,
screen = s,
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(305), top = dpi(60) } })
end,
shape = Theme_config.volume_controller.shape,
}
-- Get all source devices
local function get_source_devices()
awful.spawn.easy_async_with_shell(
[[
pactl list sinks | grep -E 'node.name|device.description|alsa.card_name' | awk '{gsub(/"/, ""); for(i = 1;i < NF;i++) printf $i " "; print $NF}'
]],
function(stdout)
local device_list = {}
local was_alsa = false
local node_names, alsa_names = {}, {}
for val in stdout:gmatch("[^\n]+") do
if val:match("alsa%.card_name") then
table.insert(alsa_names, val:match("alsa%.card_name%s=%s(.*)"))
was_alsa = true
elseif val:match("device%.description") and not was_alsa then
table.insert(alsa_names, val:match("device%.description%s=%s(.*)"))
was_alsa = false
else
was_alsa = false
end
if val:match("node%.name") then
table.insert(node_names, val:match("node%.name%s=%s(.*)"))
end
end
for k = 1, #alsa_names, 1 do
device_list[#device_list + 1] = create_device(alsa_names[k], node_names[k], true)
end
dropdown_list_volume:get_children_by_id("volume_device_list")[1].children = device_list
end
)
end
-- Get all input devices
local function get_input_devices()
awful.spawn.easy_async_with_shell(
[[
pactl list sources | grep -E "node.name|device.description|alsa.card_name" | awk '{gsub(/"/, ""); for(i = 1;i < NF;i++) printf $i " "; print $NF}'
]],
function(stdout)
local device_list = {}
local was_alsa = false
local node_names, alsa_names = {}, {}
for val in stdout:gmatch("[^\n]+") do
if val:match("alsa%.card_name") then
table.insert(alsa_names, val:match("alsa%.card_name%s=%s(.*)"))
was_alsa = true
elseif val:match("device%.description") and not was_alsa then
table.insert(alsa_names, val:match("device%.description%s=%s(.*)"))
was_alsa = false
else
was_alsa = false
end
if val:match("node%.name") then
table.insert(node_names, val:match("node%.name%s=%s(.*)"))
end
end
for k = 1, #alsa_names, 1 do
device_list[#device_list + 1] = create_device(alsa_names[k], node_names[k], false)
end
dropdown_list_microphone:get_children_by_id("volume_device_list")[1].children = device_list
end
)
end
capi.awesome.connect_signal(
"audio::device_changed",
function()
get_input_devices()
end
)
capi.awesome.connect_signal(
"microphone::device_changed",
function()
get_source_devices()
end
)
-- Set the volume and icon
capi.awesome.connect_signal(
"audio::get",
function(muted, volume)
if muted then
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.icon:set_image(gears.color
.recolor_image(icondir .. "volume-mute.svg", Theme_config.volume_controller.volume_fg))
else
volume = tonumber(volume)
if not volume then
return
end
local icon = icondir .. "volume"
if volume < 1 then
icon = icon .. "-mute"
elseif volume >= 1 and volume < 34 then
icon = icon .. "-low"
elseif volume >= 34 and volume < 67 then
icon = icon .. "-medium"
elseif volume >= 67 then
icon = icon .. "-high"
end
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.slider_margin.slider:
set_value(volume)
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.icon:set_image(gears.color
.recolor_image(icon
.. ".svg", Theme_config.volume_controller.volume_fg))
end
end
)
-- Get microphone volume
capi.awesome.connect_signal(
"microphone::get",
function(muted, volume)
if muted then
--volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.slider_margin.slider:set_value(tonumber(0))
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone-off.svg", Theme_config.volume_controller.microphone_fg))
else
volume = tonumber(volume)
if not volume then
return
end
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.slider_margin.slider:set_value(tonumber(volume))
if volume > 0 then
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone.svg", Theme_config.volume_controller.microphone_fg))
else
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone-off.svg", Theme_config.volume_controller.microphone_fg))
end
end
end
)
-- When the mouse leaves the popup it stops the mousegrabber and hides the popup.
volume_controller_container:connect_signal(
"mouse::leave",
function()
capi.mousegrabber.run(
function()
capi.awesome.emit_signal("volume_controller::toggle", s)
capi.mousegrabber.stop()
return true
end,
"arrow"
)
end
)
volume_controller_container:connect_signal(
"mouse::enter",
function()
capi.mousegrabber.stop()
end
)
-- Grabs all keys and hides popup when anything is pressed
-- TODO: Make it possible to navigate and select using the kb
awful.keygrabber {
autostart = false,
stop_event = 'release',
keypressed_callback = function()
capi.awesome.emit_signal("volume_controller::toggle", s)
capi.mousegrabber.stop()
end
}
-- Draw the popup
volume_controller_container:setup {
volume_controller,
layout = wibox.layout.fixed.horizontal
}
-- Toggle container visibility
capi.awesome.connect_signal(
"volume_controller::toggle",
function(scr)
if scr == s then
volume_controller_container.visible = not volume_controller_container.visible
end
end
)
end

View File

@@ -1,147 +0,0 @@
-----------------------------------
-- This is the volume_old module --
-----------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/audio/"
-- Returns the volume_osd
return function(s)
local volume_osd_widget = wibox.widget {
{
{
{ -- Volume Icon
image = gears.color.recolor_image(icondir .. "volume-high.svg", Theme_config.volume_osd.icon_color),
valign = "center",
halign = "center",
resize = false,
id = "icon",
widget = wibox.widget.imagebox
},
{ -- Volume Bar
{
{
id = "progressbar1",
color = Theme_config.volume_osd.bar_bg_active,
background_color = Theme_config.volume_osd.bar_bg,
max_value = 100,
value = 50,
forced_height = dpi(6),
shape = function(cr, width, heigth)
gears.shape.rounded_bar(cr, width, heigth, dpi(6))
end,
widget = wibox.widget.progressbar
},
id = "progressbar_container2",
halign = "center",
valign = "center",
widget = wibox.container.place
},
id = "progressbar_container",
width = dpi(240),
heigth = dpi(20),
stragety = "max",
widget = wibox.container.constraint
},
id = "layout1",
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
forced_width = dpi(300),
forced_height = dpi(80),
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end,
border_color = Theme_config.volume_osd.border_color,
border_width = Theme_config.volume_osd.border_width,
fg = Theme_config.volume_osd.fg,
bg = Theme_config.volume_osd.bg,
widget = wibox.container.background
}
capi.awesome.connect_signal(
"audio::get",
function(muted, volume)
if muted then
volume_osd_widget:get_children_by_id("icon")[1]
:set_image(gears.color.recolor_image(
icondir .. "volume-mute" .. ".svg", Theme_config.volume_osd.icon_color))
volume_osd_widget:get_children_by_id("progressbar1")[1].value = tonumber(0)
else
volume = tonumber(volume)
if not volume then
return
end
volume_osd_widget:get_children_by_id("progressbar1")[1].value = tonumber(volume)
local icon = icondir .. "volume"
if volume < 1 then
icon = icon .. "-mute"
elseif volume >= 1 and volume < 34 then
icon = icon .. "-low"
elseif volume >= 34 and volume < 67 then
icon = icon .. "-medium"
elseif volume >= 67 then
icon = icon .. "-high"
end
volume_osd_widget:get_children_by_id("icon")[1]:set_image(gears.color.recolor_image(icon .. ".svg",
Theme_config.volume_osd.icon_color))
end
end
)
local volume_container = awful.popup {
widget = {},
ontop = true,
stretch = false,
visible = false,
screen = s,
placement = function(c) awful.placement.bottom_left(c, { margins = dpi(20) }) end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(14))
end
}
local hide_volume_osd = gears.timer {
timeout = 2,
autostart = true,
callback = function()
volume_container.visible = false
end
}
volume_container:setup {
volume_osd_widget,
layout = wibox.layout.fixed.horizontal
}
capi.awesome.connect_signal(
"widget::volume_osd:rerun",
function()
if capi.mouse.screen == s then
volume_container.visible = true
if hide_volume_osd.started then
hide_volume_osd:again()
else
hide_volume_osd:start()
end
end
end
)
end

View File

@@ -59,6 +59,12 @@ Theme_config.date = {
fg = color["Grey900"] fg = color["Grey900"]
} }
Theme_config.dnd = {
bg = color["Grey900"],
disabled = color["Grey800"],
border_disabled = color["Grey800"],
}
Theme_config.gpu_usage = { Theme_config.gpu_usage = {
bg = color["Green200"], bg = color["Green200"],
fg = color["Grey900"] fg = color["Grey900"]
@@ -250,6 +256,19 @@ Theme_config.network_manager = {
icon_fg = color["Grey900"], icon_fg = color["Grey900"],
border_color = color["Grey800"], border_color = color["Grey800"],
border_width = dpi(2), border_width = dpi(2),
button_bg = color["Blue200"],
button_fg = color["Grey900"],
checkbox_fg = color["Grey900"],
checkbox_bg = color["DeepOrange200"],
checkbox_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(6))
end,
button_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
close_icon_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
shape = function(cr, width, height) shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8)) gears.shape.rounded_rect(cr, width, height, dpi(8))
end end
@@ -294,6 +313,8 @@ Theme_config.notification_center = {
border_color = color["Grey800"], border_color = color["Grey800"],
border_width = dpi(4), border_width = dpi(4),
spacing_color = color["Grey800"], spacing_color = color["Grey800"],
dnd_color = color["Purple200"],
dnd_fg = color["Pink200"],
-- Clear all button -- Clear all button
clear_all_button = { clear_all_button = {
@@ -301,16 +322,6 @@ Theme_config.notification_center = {
fg = color["Grey900"] fg = color["Grey900"]
}, },
-- DnD button
dnd = {
bg = color["Grey900"],
fg = color["Pink200"],
disabled = color["Grey700"],
enabled = color["Purple200"],
border_disabled = color["Grey800"],
border_enabled = color["Purple200"]
},
-- Notification_list -- Notification_list
notification_list = { notification_list = {
timer_fg = color["Teal200"], timer_fg = color["Teal200"],
@@ -431,7 +442,7 @@ Theme_config.bluetooth_controller = {
refresh_icon_color = color["Grey900"], refresh_icon_color = color["Grey900"],
refresh_bg = color["LightBlue200"], refresh_bg = color["LightBlue200"],
power_icon_color = color["Grey900"], power_icon_color = color["Grey900"],
power_bg = color["Blue200"] power_bg = color["Blue200"],
} }
Theme_config.brightness_osd = { Theme_config.brightness_osd = {

View File

@@ -17,7 +17,7 @@ User_config = {
Flatpak application: flatpak run com.example.App Flatpak application: flatpak run com.example.App
]] -- ]] --
autostart = { autostart = {
"picom --experimental-backends", "picom",
"xfce4-power-manager", "xfce4-power-manager",
"light-locker --lock-on-suspend --lock-on-lid &", "light-locker --lock-on-suspend --lock-on-lid &",
"/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1", "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1",

View File

@@ -1,18 +1,13 @@
local awful = require("awful") local awful = require("awful")
local pulse = require("pulseaudio_dbus")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }
local lgi = require("lgi") local lgi = require("lgi")
local pulseaudio = require("lua_libpulse_glib")
local pa = pulseaudio.new()
local ctx = pa:context("awesome")
print(ctx)
--[[ ctx:connect(nil, function(state) --[[ ctx:connect(nil, function(state)
if state == 4 then if state == 4 then
print("Connection is ready") print("Connection is ready")

View File

@@ -1,9 +0,0 @@
require("src.tools.helpers.cpu_temp")
--!Find a better way that doesn't need manual GC since it has a huge performance impact
--require("src.tools.helpers.cpu_usage")
require("src.tools.helpers.cpu_freq")
require("src.tools.helpers.ram")
require("src.tools.helpers.gpu_usage")
require("src.tools.helpers.gpu_temp")
require("src.tools.helpers.audio")
require("src.tools.helpers.backlight")

View File

@@ -1,440 +0,0 @@
-------------------------------------------
-- @author https://github.com/Kasper24
-- @copyright 2021-2022 Kasper24
-------------------------------------------
local lgi = require("lgi")
local NM = lgi.NM
local awful = require("awful")
local gobject = require("gears.object")
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local dbus_proxy = require("services.dbus_proxy")
local network = {}
local instance = nil
network.NMState = {
UNKNOWN = 0, -- Networking state is unknown. This indicates a daemon error that
-- makes it unable to reasonably assess the state. In such event the applications
-- are expected to assume Internet connectivity might be present and not disable
-- controls that require network access. The graphical shells may hide the network
-- accessibility indicator altogether since no meaningful status indication can be provided.
ASLEEP = 10, -- Networking is not enabled, the system is being suspended or resumed from suspend.
DISCONNECTED = 20, -- There is no active network connection. The graphical
-- shell should indicate no network connectivity and the applications
-- should not attempt to access the network.
DISCONNECTING = 30, -- Network connections are being cleaned up.
-- The applications should tear down their network sessions.
CONNECTING = 40, -- A network connection is being started The graphical
-- shell should indicate the network is being connected while the
-- applications should still make no attempts to connect the network.
CONNECTED_LOCAL = 50, -- There is only local IPv4 and/or IPv6 connectivity,
-- but no default route to access the Internet. The graphical
-- shell should indicate no network connectivity.
CONNECTED_SITE = 60, -- There is only site-wide IPv4 and/or IPv6 connectivity.
-- This means a default route is available, but the Internet connectivity check
-- (see "Connectivity" property) did not succeed. The graphical shell
-- should indicate limited network connectivity.
CONNECTED_GLOBAL = 70, -- There is global IPv4 and/or IPv6 Internet connectivity
-- This means the Internet connectivity check succeeded, the graphical shell should
-- indicate full network connectivity.
}
network.DeviceType = {
ETHERNET = 1,
WIFI = 2
}
network.DeviceState = {
UNKNOWN = 0, -- the device's state is unknown
UNMANAGED = 10, -- the device is recognized, but not managed by NetworkManager
UNAVAILABLE = 20, --the device is managed by NetworkManager,
--but is not available for use. Reasons may include the wireless switched off,
--missing firmware, no ethernet carrier, missing supplicant or modem manager, etc.
DISCONNECTED = 30, -- the device can be activated,
--but is currently idle and not connected to a network.
PREPARE = 40, -- the device is preparing the connection to the network.
-- This may include operations like changing the MAC address,
-- setting physical link properties, and anything else required
-- to connect to the requested network.
CONFIG = 50, -- the device is connecting to the requested network.
-- This may include operations like associating with the Wi-Fi AP,
-- dialing the modem, connecting to the remote Bluetooth device, etc.
NEED_AUTH = 60, -- the device requires more information to continue
-- connecting to the requested network. This includes secrets like WiFi passphrases,
-- login passwords, PIN codes, etc.
IP_CONFIG = 70, -- the device is requesting IPv4 and/or IPv6 addresses
-- and routing information from the network.
IP_CHECK = 80, -- the device is checking whether further action
-- is required for the requested network connection.
-- This may include checking whether only local network access is available,
-- whether a captive portal is blocking access to the Internet, etc.
SECONDARIES = 90, -- the device is waiting for a secondary connection
-- (like a VPN) which must activated before the device can be activated
ACTIVATED = 100, -- the device has a network connection, either local or global.
DEACTIVATING = 110, -- a disconnection from the current network connection
-- was requested, and the device is cleaning up resources used for that connection.
-- The network connection may still be valid.
FAILED = 120 -- the device failed to connect to
-- the requested network and is cleaning up the connection request
}
function network.device_state_to_string(state)
local device_state_to_string =
{
[0] = "Unknown",
[10] = "Unmanaged",
[20] = "Unavailable",
[30] = "Disconnected",
[40] = "Prepare",
[50] = "Config",
[60] = "Need Auth",
[70] = "IP Config",
[80] = "IP Check",
[90] = "Secondaries",
[100] = "Activated",
[110] = "Deactivated",
[120] = "Failed"
}
return device_state_to_string[state]
end
local function flags_to_security(flags, wpa_flags, rsn_flags)
local str = ""
if flags == 1 and wpa_flags == 0 and rsn_flags == 0 then
str = str .. " WEP"
end
if wpa_flags ~= 0 then
str = str .. " WPA1"
end
if not rsn_flags ~= 0 then
str = str .. " WPA2"
end
if wpa_flags == 512 or rsn_flags == 512 then
str = str .. " 802.1X"
end
return (str:gsub("^%s", ""))
end
local function generate_uuid()
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
local uuid = 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)
return uuid
end
local function create_profile(access_point, password, auto_connect)
local s_con =
{
-- ["interface-name"] = lgi.GLib.Variant("s", access_point.device_interface),
["uuid"] = lgi.GLib.Variant("s", generate_uuid()),
["id"] = lgi.GLib.Variant("s", access_point.ssid),
["type"] = lgi.GLib.Variant("s", "802-11-wireless"),
["autoconnect"] = lgi.GLib.Variant("b", auto_connect),
}
local s_ip4 =
{
["method"] = lgi.GLib.Variant("s", "auto")
}
local s_ip6 =
{
["method"] = lgi.GLib.Variant("s", "auto"),
}
local s_wifi =
{
["mode"] = lgi.GLib.Variant("s", "infrastructure"),
}
local s_wsec = {}
if access_point.security ~= "" then
if access_point.security:match("WPA") ~= nil then
s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "wpa-psk")
s_wsec["auth-alg"] = lgi.GLib.Variant("s", "open")
s_wsec["psk"] = lgi.GLib.Variant("s", helpers.string.trim(password))
else
s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "None")
s_wsec["wep-key-type"] = lgi.GLib.Variant("s", NM.WepKeyType.PASSPHRASE)
s_wsec["wep-key0"] = lgi.GLib.Variant("s", helpers.string.trim(password))
end
end
return {
["connection"] = s_con,
["ipv4"] = s_ip4,
["ipv6"] = s_ip6,
["802-11-wireless"] = s_wifi,
["802-11-wireless-security"] = s_wsec
}
end
local function on_wifi_device_state_changed(self, proxy, new_state, old_state, reason)
local active_access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint",
path = self._private.wifi_proxy.ActiveAccessPoint
}
self:emit_signal(tostring(active_access_point_proxy.HwAddress) .. "::state", new_state, old_state)
if new_state == network.DeviceState.ACTIVATED then
local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid)
self:emit_signal("access_point::connected", ssid, active_access_point_proxy.Strength)
end
end
local function get_access_point_connections(self, ssid)
local connection_proxies = {}
local connections = self._private.settings_proxy:ListConnections()
for _, connection_path in ipairs(connections) do
local connection_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Settings.Connection",
path = connection_path
}
if string.find(connection_proxy.Filename, ssid) then
table.insert(connection_proxies, connection_proxy)
end
end
return connection_proxies
end
local function get_wifi_proxy(self)
local devices = self._private.client_proxy:GetDevices()
for _, device_path in ipairs(devices) do
local device_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Device",
path = device_path
}
if device_proxy.DeviceType == network.DeviceType.WIFI then
self._private.device_proxy = device_proxy
self._private.wifi_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Device.Wireless",
path = device_path
}
self._private.device_proxy:connect_signal("StateChanged", function(proxy, new_state, old_state, reason)
on_wifi_device_state_changed(self, proxy, new_state, old_state, reason)
end)
end
end
end
function network:scan_access_points()
self._private.access_points = {}
self._private.wifi_proxy:RequestScanAsync(function(proxy, context, success, failure)
if failure ~= nil then
print("Rescan wifi failed: ", failure)
print("Rescan wifi failed error code: ", failure.code)
self:emit_signal("scan_access_points::failed", tostring(failure), tostring(failure.code))
return
end
local access_points = self._private.wifi_proxy:GetAccessPoints()
for _, access_point_path in ipairs(access_points) do
local access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint",
path = access_point_path
}
-- for _, access_point in ipairs(self._private.access_points) do
-- if access_point.hw_address == access_point_proxy.HwAddress then
-- print("duplicates")
-- return
-- end
-- end
if access_point_proxy.Ssid ~= nil then
local ssid = NM.utils_ssid_to_utf8(access_point_proxy.Ssid)
local security = flags_to_security(access_point_proxy.Flags, access_point_proxy.WpaFlags,
access_point_proxy.RsnFlags)
local password = ""
local connections = get_access_point_connections(self, ssid)
for _, connection in ipairs(connections) do
if string.find(connection.Filename, ssid) then
local secrets = connection:GetSecrets("802-11-wireless-security")
if secrets ~= nil then
password = secrets["802-11-wireless-security"].psk
end
end
end
table.insert(self._private.access_points, {
raw_ssid = access_point_proxy.Ssid,
ssid = ssid,
security = security,
password = password,
strength = access_point_proxy.Strength,
path = access_point_path,
hw_address = access_point_proxy.HwAddress,
device_interface = self._private.device_proxy.Interface,
device_proxy_path = self._private.device_proxy.object_path,
})
end
end
table.sort(self._private.access_points, function(a, b)
return a.strength > b.strength
end)
self:emit_signal("scan_access_points::success", self._private.access_points)
end, { call_id = "my-id" }, {})
end
function network:connect_to_access_point(access_point, password, auto_connect)
local connections = get_access_point_connections(self, access_point.ssid)
local profile = create_profile(access_point, password, auto_connect)
-- No connection profiles, need to create one
if #connections == 0 then
-- AddAndActivateConnectionAsync doesn't actually verify that the profile is valid
-- The NetworkManager libary has methods to verify manually, but they are not exposed to DBus
-- so instead I'm using the 2 seperate methods
self._private.client_proxy:AddAndActivateConnectionAsync(function(proxy, context, success, failure)
if failure ~= nil then
print("Failed to activate connection: ", failure)
print("Failed to activate connection error code: ", failure.code)
self:emit_signal("activate_access_point::failed", tostring(failure), tostring(failure.code))
return
end
self:emit_signal("activate_access_point::success", access_point.ssid)
end, { call_id = "my-id" }, profile, access_point.device_proxy_path, access_point.path)
else
connections[1]:Update(profile)
self._private.client_proxy:ActivateConnectionAsync(function(proxy, context, success, failure)
if failure ~= nil then
print("Failed to activate connection: ", failure)
print("Failed to activate connection error code: ", failure.code)
self:emit_signal("activate_access_point::failed", tostring(failure), tostring(failure.code))
return
end
self:emit_signal("activate_access_point::success", access_point.ssid)
end, { call_id = "my-id" }, connections[1].object_path, access_point.device_proxy_path, access_point.path)
end
end
function network:is_access_point_active(access_point)
return access_point.path == self._private.wifi_proxy.ActiveAccessPoint
end
function network:disconnect_from_access_point()
self._private.client_proxy:DeactivateConnection(self._private.device_proxy.ActiveConnection)
end
function network:toggle_access_point(access_point, password, auto_connect)
if self:is_access_point_active(access_point) then
self:disconnect_from_access_point()
else
self:connect_to_access_point(access_point, password, auto_connect)
end
end
function network:toggle_wireless_state()
local enable = not self._private.client_proxy.WirelessEnabled
if enable == true then
self:set_network_state(true)
end
self._private.client_proxy:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable))
self._private.client_proxy.WirelessEnabled = { signature = "b", value = enable }
end
function network:set_network_state(state)
self._private.client_proxy:Enable(state)
end
function network:open_settings()
awful.spawn("nm-connection-editor", false)
end
local function new()
local ret = gobject {}
gtable.crush(ret, network, true)
ret._private = {}
ret._private.access_points = {}
ret._private.client_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager",
path = "/org/freedesktop/NetworkManager"
}
ret._private.settings_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.Settings",
path = "/org/freedesktop/NetworkManager/Settings"
}
local client_properties_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.DBus.Properties",
path = "/org/freedesktop/NetworkManager"
}
client_properties_proxy:connect_signal("PropertiesChanged", function(self, interface, data)
if data.WirelessEnabled ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then
ret._private.WirelessEnabled = data.WirelessEnabled
ret:emit_signal("wireless_state", data.WirelessEnabled)
if data.WirelessEnabled == true then
gtimer { timeout = 5, autostart = true, call_now = false, single_shot = true, callback = function()
ret:scan_access_points()
end }
end
end
end)
get_wifi_proxy(ret)
ret:scan_access_points()
gtimer.delayed_call(function()
ret:emit_signal("wireless_state", ret._private.client_proxy.WirelessEnabled)
local active_access_point = ret._private.wifi_proxy.ActiveAccessPoint
if ret._private.device_proxy.State == network.DeviceState.ACTIVATED and active_access_point ~= "/" then
local active_access_point_proxy = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = "org.freedesktop.NetworkManager",
interface = "org.freedesktop.NetworkManager.AccessPoint",
path = active_access_point
}
local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid)
ret:emit_signal("access_point::connected", ssid, active_access_point_proxy.Strength)
end
end)
return ret
end
if not instance then
instance = new()
end
return instance

View File

@@ -7,6 +7,8 @@ local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears") local gears = require("gears")
local wibox = require("wibox") local wibox = require("wibox")
require("src.tools.helpers.audio")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }

View File

@@ -17,6 +17,22 @@ local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/bl
-- Returns the bluetooth widget -- Returns the bluetooth widget
return function(s) return function(s)
local bt_widget = require("src.modules.bluetooth.init") { screen = s }
local bluetooth_container = awful.popup {
widget = bt_widget:get_widget(),
ontop = true,
bg = Theme_config.bluetooth_controller.container_bg,
stretch = false,
visible = false,
forced_width = dpi(400),
screen = s,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end
}
local bluetooth_widget = wibox.widget { local bluetooth_widget = wibox.widget {
{ {
{ {
@@ -43,24 +59,23 @@ return function(s)
end, end,
widget = wibox.container.background widget = wibox.container.background
} }
bt_widget:connect_signal("bluetooth::status", function(status)
bluetooth_widget:get_children_by_id("icon")[1].image = gears.color.recolor_image(status._private.Adapter1.Powered and
icondir .. "bluetooth-on.svg" or icondir .. "bluetooth-off.svg", Theme_config.bluetooth.fg)
end)
-- Hover signal to change color when mouse is over -- Hover signal to change color when mouse is over
Hover_signal(bluetooth_widget) Hover_signal(bluetooth_widget)
capi.awesome.connect_signal("state", function(state)
if state then
bluetooth_widget:get_children_by_id("icon")[1]:set_image(gears.color.recolor_image(icondir .. "bluetooth-on.svg",
Theme_config.bluetooth.fg))
else
bluetooth_widget:get_children_by_id("icon")[1]:set_image(gears.color.recolor_image(icondir .. "bluetooth-off.svg",
Theme_config.bluetooth.fg))
end
end)
bluetooth_widget:connect_signal( bluetooth_widget:connect_signal(
"button::press", "button::press",
function(_, _, _, key) function(_, _, _, key)
if key == 1 then if key == 1 then
capi.awesome.emit_signal("bluetooth_controller::toggle", s) local geo = mouse.current_wibox:geometry()
bluetooth_container.x = geo.x
bluetooth_container.y = geo.y + dpi(55)
bluetooth_container.visible = not bluetooth_container.visible
else else
capi.awesome.emit_signal("toggle_bluetooth") capi.awesome.emit_signal("toggle_bluetooth")
end end

View File

@@ -11,6 +11,10 @@ local wibox = require("wibox")
local color = require("src.lib.color") local color = require("src.lib.color")
local rubato = require("src.lib.rubato") local rubato = require("src.lib.rubato")
require("src.tools.helpers.cpu_freq")
require("src.tools.helpers.cpu_temp")
--!Has to be disabled until rewritten to perform better require("src.tools.helpers.cpu_usage")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }

View File

@@ -75,7 +75,7 @@ return function(s)
awful.button({}, 1, function() awful.button({}, 1, function()
local geo = mouse.current_wibox:geometry() local geo = mouse.current_wibox:geometry()
calendar_popup.x = geo.x calendar_popup.x = geo.x
calendar_popup.y = geo.y + Global_config.top_struts calendar_popup.y = geo.y + dpi(55)
calendar_popup.visible = not calendar_popup.visible calendar_popup.visible = not calendar_popup.visible
end) end)
) )

View File

@@ -11,6 +11,9 @@ local wibox = require("wibox")
local color = require("src.lib.color") local color = require("src.lib.color")
local rubato = require("src.lib.rubato") local rubato = require("src.lib.rubato")
require("src.tools.helpers.gpu_temp")
require("src.tools.helpers.gpu_usage")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }

View File

@@ -17,6 +17,7 @@ local capi = {
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/kblayout/" local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/kblayout/"
return function(s) return function(s)
local kblayout_widget = wibox.widget { local kblayout_widget = wibox.widget {
{ {
{ {

View File

@@ -24,8 +24,10 @@ local interfaces = {
local network_mode = nil local network_mode = nil
local nm_widget = require("src.modules.network_controller.init")
-- Returns the network widget -- Returns the network widget
return function() return function(s)
local startup = true local startup = true
local reconnect_startup = true local reconnect_startup = true
local wifi_strength local wifi_strength
@@ -331,6 +333,21 @@ return function()
end end
} }
local network_container = awful.popup {
widget = nm_widget {},
bg = Theme_config.network_manager.bg,
screen = s,
stretch = false,
visible = false,
ontop = true,
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(350), top = dpi(60) } })
end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end
}
-- Signals -- Signals
Hover_signal(network_widget) Hover_signal(network_widget)
@@ -341,7 +358,7 @@ return function()
1, 1,
nil, nil,
function() function()
capi.awesome.emit_signal("NM::toggle_container") network_container.visible = not network_container.visible
end end
), ),
awful.button( awful.button(

View File

@@ -9,6 +9,8 @@ local gears = require("gears")
local watch = awful.widget.watch local watch = awful.widget.watch
local wibox = require("wibox") local wibox = require("wibox")
require("src.tools.helpers.ram")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
} }

40
awesome/todo.md Normal file
View File

@@ -0,0 +1,40 @@
# TODO list for my AwesomeWM rice
## Modules
### Applicationlauncher [100% Done]
#### Features
- Automatically collects all .desktop files that are marked as visible and displays them
- Execute application
- Search for an application
- Right click context menu
- Options to execute as sudo, pin to dock or add to desktop
- Infinite scoll (well technically, infinite if you installed infinite apps lol)
- Algorithm to select the best search match
- Keep track of most launched applications and serve them over others
### Bluetooth [95% Done]
#### Features
- Connecting/Disconnecting a device
- Finding other devices and grouping them into paired and not paired
- Removing them from beeing Paired
- Trusting/Untrusting a device
- Toggle Bluetooth on/off
- Scan again for devices
- Update as soon a new device is found
- When removed put it into the discovered list from paired
- Renaming a device
- Pairing a new device
- Dropdown with multiple options per device
#### TODO
- Getting and asking for a passcode
- "Greying out" non avaiable options in the dropdown
## Widgets

View File

@@ -0,0 +1,395 @@
---------------------------------------------------------------------------
-- A widget to write text in
--@DOC_wibox_widget_defaults_inputtextbox_EXAMPLE@
--
-- @author Rene Kievits
-- @copyright 2022 Rene Kievits
-- @widgetmod wibox.widget.inputbox
-- @supermodule wibox.widget.textbox
---------------------------------------------------------------------------
local base = require("wibox.widget.base")
local gdebug = require("gears.debug")
local gfs = require("gears.filesystem")
local gobject = require("gears.object")
local gstring = require("gears.string")
local beautiful = require("beautiful")
local keygrabber = require("awful.keygrabber")
local lgi = require("lgi")
local gtable = require("gears.table")
local wibox = require("wibox")
local abutton = require("awful.button")
local setmetatable = setmetatable
local capi =
{
selection = selection,
mousegrabber = mousegrabber,
mouse = mouse,
}
local inputbox = { mt = {} }
local function text_with_cursor(text, cursor_pos, self)
local char, spacer, text_start, text_end
local cursor_fg = beautiful.inputbox_cursor_fg or "#313131"
local cursor_bg = beautiful.inputbox_cursor_bg or "#0dccfc"
local text_color = beautiful.inputbox_fg or "#ffffff"
local placeholder_text = beautiful.inputbox_placeholder_text or "Type here..."
local placeholder_fg = beautiful.inputbox_placeholder_fg or "#777777"
local highlight_bg = beautiful.inputbox_highlight_bg or "#35ffe4"
local highlight_fg = beautiful.inputbox_highlight_fg or "#000000"
if text == "" then
return "<span foreground='" .. placeholder_fg .. "'>" .. placeholder_text .. "</span>"
end
if #text < cursor_pos then
char = " "
spacer = ""
text_start = gstring.xml_escape(text)
text_end = ""
else
local offset = 0
if #text:sub(cursor_pos, cursor_pos) == -1 then
offset = 1
end
char = gstring.xml_escape(text:sub(cursor_pos, cursor_pos + offset))
spacer = " "
text_start = gstring.xml_escape(text:sub(1, cursor_pos - 1))
text_end = gstring.xml_escape(text:sub(cursor_pos + offset + 1))
end
if self._private.highlight and self._private.highlight.cur_pos_start and self._private.highlight.cur_pos_end then
-- split the text into 3 parts based on the highlight and cursor position
local text_start_highlight = gstring.xml_escape(text:sub(1, self._private.highlight.cur_pos_start - 1))
local text_highlighted = gstring.xml_escape(text:sub(self._private.highlight.cur_pos_start,
self._private.highlight.cur_pos_end))
local text_end_highlight = gstring.xml_escape(text:sub(self._private.highlight.cur_pos_end + 1))
return "<span foreground='" .. text_color .. "'>" .. text_start_highlight .. "</span>" ..
"<span foreground='" .. highlight_fg .. "' background='" .. highlight_bg .. "'>" ..
text_highlighted ..
"</span>" .. "<span foreground='" .. text_color .. "'>" .. text_end_highlight .. "</span>"
else
return "<span foreground='" .. text_color .. "'>" .. text_start .. "</span>" ..
"<span background='" .. cursor_bg .. "' foreground='" .. cursor_fg .. "'>" ..
char .. "</span>" .. "<span foreground='" .. text_color .. "'>" .. text_end .. spacer .. "</span>"
end
end
--- Clears the current text
function inputbox:clear()
self:set_text("")
end
function inputbox:get_text()
return self._private.text or ""
end
function inputbox:set_text(text)
self._private.text = text
self:emit_signal("property::text", text)
end
--- Stop the keygrabber and mousegrabber
function inputbox:stop()
self:emit_signal("stopped")
keygrabber.stop()
capi.mousegrabber.stop()
end
function inputbox:focus()
keygrabber.stop()
if not keygrabber.is_running then
self:run()
end
-- Stops the mousegrabber when not clicked on the widget
--[[ capi.mousegrabber.run(
function(m)
if m.buttons[1] then
if capi.mouse.current_wibox ~= self:get_widget().widget then
self:emit_signal("keygrabber::stop", "")
return false
end
end
return true
end, "left_ptr"
) ]]
self:connect_signal("button::press", function()
if capi.mouse.current_widget ~= self then
self:emit_signal("keygrabber::stop", "")
end
end)
end
function inputbox:run()
if not self._private.text then self._private.text = "" end
-- Init the cursor position, but causes on refocus the cursor to move to the left
local cursor_pos = #self:get_text() + 1
self:emit_signal("started")
-- Init and reset(when refocused) the highlight
self._private.highlight = {}
-- Emitted when the keygrabber is stopped
self:connect_signal("cancel", function()
self:stop()
self:emit_signal("stopped")
end)
-- Emitted when the keygrabber should submit the text
self:connect_signal("submit", function(text)
self:stop()
self:emit_signal("stopped", text)
end)
self:emit_signal("key_pressed", "B", "A")
keygrabber.run(function(mod, key, event)
local mod_keys = {}
for _, v in ipairs(mod) do
mod_keys[v] = true
end
if not (event == "press") then return end
--Escape cases
-- Just quit and leave the text as is
if (not mod_keys.Control) and (key == "Escape") then
self:emit_signal("cancel")
elseif (not mod_keys.Control and key == "KP_Enter") or (not mod_keys.Control and key == "Return") then
self:emit_signal("submit", self:get_text())
self:set_text("")
end
-- All shift, control or key cases
if mod_keys.Shift then
if key == "Left" then
if cursor_pos > 1 then
if not self._private.highlight.cur_pos_start then
self._private.highlight.cur_pos_start = cursor_pos - 1
end
if not self._private.highlight.cur_pos_end then
self._private.highlight.cur_pos_end = cursor_pos
end
if self._private.highlight.cur_pos_start < cursor_pos then
self._private.highlight.cur_pos_end = self._private.highlight.cur_pos_end - 1
else
self._private.highlight.cur_pos_start = self._private.highlight.cur_pos_start - 1
end
cursor_pos = cursor_pos - 1
end
elseif key == "Right" then
if #self._private.text >= cursor_pos then
if not self._private.highlight.cur_pos_end then
self._private.highlight.cur_pos_end = cursor_pos - 1
end
if not self._private.highlight.cur_pos_start then
self._private.highlight.cur_pos_start = cursor_pos
end
if self._private.highlight.cur_pos_end <= cursor_pos then
self._private.highlight.cur_pos_end = self._private.highlight.cur_pos_end + 1
else
self._private.highlight.cur_pos_start = self._private.highlight.cur_pos_start + 1
end
cursor_pos = cursor_pos + 1
if cursor_pos > #self._private.text + 1 then
self._private.highlight = {}
end
end
else
if key:wlen() == 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
string.upper(key) .. self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos + 1
end
end
elseif mod_keys.Control then
if key == "a" then
-- Mark the entire text
self._private.highlight = {
cur_pos_start = 1,
cur_pos_end = #self._private.text
}
elseif key == "c" then
-- TODO: Copy the highlighted text when the selection setter gets implemented
elseif key == "v" then
local sel = capi.selection()
if sel then
sel = sel:gsub("\n", "")
if self._private.highlight and self._private.highlight.cur_pos_start and
self._private.highlight.cur_pos_end then
-- insert the text into the selected part
local text_start = self._private.text:sub(1, self._private.highlight.cur_pos_start - 1)
local text_end = self._private.text:sub(self._private.highlight.cur_pos_end + 1)
self:set_text(text_start .. sel .. text_end)
self._private.highlight = {}
cursor_pos = #text_start + #sel + 1
else
self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
sel .. self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos + #sel
end
end
elseif key == "x" then
--TODO: "cut". Copy selected then clear text, this requires to add the c function first.
self._private.highlight = {}
elseif key == "Left" then
-- Find all spaces
local spaces = {}
local t, i = self._private.text, 0
while t:find("%s") do
i = t:find("%s")
table.insert(spaces, i)
t = t:sub(1, i - 1) .. "-" .. t:sub(i + 1)
end
local cp = 1
for _, v in ipairs(spaces) do
if (v < cursor_pos) then
cp = v
end
end
cursor_pos = cp
elseif key == "Right" then
local next_space = self._private.text:sub(cursor_pos):find("%s")
if next_space then
cursor_pos = cursor_pos + next_space
else
cursor_pos = #self._private.text + 1
end
end
else
if key == "BackSpace" then
-- If text is highlighted delete that, else just delete the character to the left
if self._private.highlight and self._private.highlight.cur_pos_start and
self._private.highlight.cur_pos_end then
local text_start = self._private.text:sub(1, self._private.highlight.cur_pos_start - 1)
local text_end = self._private.text:sub(self._private.highlight.cur_pos_end + 1)
self:set_text(text_start .. text_end)
self._private.highlight = {}
cursor_pos = #text_start + 1
else
if cursor_pos > 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 2) ..
self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos - 1
end
end
elseif key == "Delete" then
-- If text is highlighted delete that, else just delete the character to the right
if self._private.highlight and self._private.highlight.cur_pos_start and
self._private.highlight.cur_pos_end then
local text_start = self._private.text:sub(1, self._private.highlight.cur_pos_start - 1)
local text_end = self._private.text:sub(self._private.highlight.cur_pos_end + 1)
self:set_text(text_start .. text_end)
self._private.highlight = {}
cursor_pos = #text_start + 1
else
if cursor_pos <= #self._private.text then
self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
self._private.text:sub(cursor_pos + 1))
end
end
elseif key == "Left" then
-- Move cursor ro the left
if cursor_pos > 1 then
cursor_pos = cursor_pos - 1
end
self._private.highlight = {}
elseif key == "Right" then
-- Move cursor to the right
if cursor_pos <= #self._private.text then
cursor_pos = cursor_pos + 1
end
self._private.highlight = {}
else
-- Print every alphanumeric key
-- It seems like gears.xmlescape doesn't support non alphanumeric characters
if key:wlen() == 1 then
self:set_text(self._private.text:sub(1, cursor_pos - 1) ..
key .. self._private.text:sub(cursor_pos))
cursor_pos = cursor_pos + #key
end
end
-- Make sure the cursor cannot go out of bounds
if cursor_pos < 1 then
cursor_pos = 1
elseif cursor_pos > #self._private.text + 1 then
cursor_pos = #self._private.text + 1
end
end
-- Update cycle
self.text = text_with_cursor(self:get_text(), cursor_pos, self)
-- using self:emit_signal... results in nil tables beeing send
awesome.emit_signal("inputbox::key_pressed", mod_keys, key)
end)
end
function inputbox.new(args)
args = args or {}
local w = wibox.widget.textbox(args.text or "")
gtable.crush(w, inputbox, true)
w:buttons(
gtable.join {
abutton({}, 1, function()
w:focus()
end),
abutton({}, 3, function()
-- TODO: Figure out how to paste with highlighted support
-- Maybe with a signal?
end)
}
)
-- Change the cursor to "xterm" on hover over
local old_cursor, old_wibox
w:connect_signal(
"mouse::enter",
function()
local wid = capi.mouse.current_wibox
if wid then
old_cursor, old_wibox = wid.cursor, wid
wid.cursor = "xterm"
end
end
)
-- Change the cursor back once leaving the widget
w:connect_signal(
"mouse::leave",
function()
old_wibox.cursor = old_cursor
old_wibox = nil
end
)
w.text = text_with_cursor("", 1, w)
return w
end
function inputbox.mt:__call(...)
return inputbox.new(...)
end
return setmetatable(inputbox, inputbox.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@@ -1,282 +0,0 @@
---------------------------------------------------------------------------
-- A widget to write text in
--@DOC_wibox_widget_defaults_inputtextbox_EXAMPLE@
--
-- @author Rene Kievits
-- @copyright 2022, Rene Kievits
-- @widgetmod wibox.widget.inputtextbox
-- @supermodule wibox.widget.base
---------------------------------------------------------------------------
local base = require("wibox.widget.base")
local gdebug = require("gears.debug")
local gfs = require("gears.filesystem")
local gobject = require("gears.object")
local gstring = require("gears.string")
local beautiful = require("beautiful")
local keygrabber = require("awful.keygrabber")
local lgi = require("lgi")
local gtable = require("gears.table")
local wibox = require("wibox")
local setmetatable = setmetatable
local inputtextbox = { mt = {} }
--Private data
local data = {}
data.history = {}
local search_term = nil
local function itera(inc, a, i)
i = i + inc
local v = a[i]
if v then return i, v end
end
--- Load history file in history table
-- @param id The data.history identifier which is the path to the filename.
-- @param[opt] max The maximum number of entried in file.
local function history_check_load(id, max)
if id and id ~= "" and not data.history[id] then
data.history[id] = { max = 50, table = {} }
if max then
data.history[id].max = max
end
local f = io.open(id, "r")
if not f then return end
for line in f:lines() do
if gtable.hasitem(data.histroy[id].table, line) then
if #data.history[id].table >= data.history[id].max then
break
end
end
end
f:close()
end
end
local function is_word_char(c)
if string.find(c, "[{[(,.:;_-+=@/ ]") then
return false
else
return true
end
end
local function cword_start(s, pos)
local i = pos
if i > 1 then
i = i - 1
end
while i >= 1 and not is_word_char(s:sub(i, i)) do
i = i - 1
end
while i >= 1 and is_word_char(s:sub(i, i)) do
i = i - 1
end
if i <= #s then
i = i + 1
end
return i
end
local function cword_end(s, pos)
local i = pos
while i <= #s and not is_word_char(s:sub(i, i)) do
i = i + 1
end
while i <= #s and is_word_char(s:sub(i, i)) do
i = i + 1
end
return i
end
--- Save history table in history file
-- @param id The data.history identifier
local function history_save(id)
if data.history[id] then
gfs.make_parent_directories(id)
local f = io.open(id, "w")
if not f then
gdebug.print_warning("Failed to write the history to " .. id)
return
end
for i = 1, math.min(#data.history[id].table, data.history[id].max) do
f:write(data.history[id].table[i] .. "\n")
end
f:close()
end
end
--- Return the number of items in history table regarding the id
-- @param id The data.history identifier
-- @return the number of items in history table, -1 if history is disabled
local function history_items(id)
if data.history[id] then
return #data.history[id].table
else
return -1
end
end
--- Add an entry to the history file
-- @param id The data.history identifier
-- @param command The command to add
local function history_add(id, command)
if data.history[id] and command ~= "" then
local index = gtable.hasitem(data.history[id].table, command)
if index == nil then
table.insert(data.history[id].table, command)
-- Do not exceed our max_cmd
if #data.history[id].table > data.history[id].max then
table.remove(data.history[id].table, 1)
end
history_save(id)
else
-- Bump this command to the end of history
table.remove(data.history[id].table, index)
table.insert(data.history[id].table, command)
history_save(id)
end
end
end
local function have_multibyte_char_at(text, position)
return text:sub(position, position):wlen() == -1
end
local function text_with_cursor(args)
local char, spacer, text_start, text_end, ret
local text = args.text or ""
local hint = args.hint or ""
local cursor = args.cursor or ""
local indicator = args.indicator or "|"
if args.select_all then
if #text == 0 then char = " " else char = gstring.xml_escape(text) end
spacer = " "
text_start = ""
text_end = ""
elseif #text < args.cursor_pos then
char = " "
spacer = ""
text_start = gstring.xml_escape(text)
text_end = ""
else
local offset = 0
if have_multibyte_char_at(text, args.cursor_pos) then
offset = 1
end
char = gstring.xml_escape(text:sub(args.cursor_pos, args.cursor_pos + offset))
spacer = " "
text_start = gstring.xml_escape(text:sub(1, args.cursor_pos - 1))
text_end = gstring.xml_escape(text:sub(args.cursor_pos + offset + 1))
end
if args.highlighter then
text_start, text_end = args.highlighter(text_start, text_end)
end
if #text == 0 then
ret = hint .. spacer
else
ret = text_start .. indicator .. text_end .. spacer
end
return ret
end
local function update(self)
self.textbox:set_font(self.font)
self.textbox:set_markup(text_with_cursor {
text = self.text,
hint = self.hint,
cursor = self.cursor,
cursor_pos = self.cursor_pos,
select_all = self.select_all,
indicator = self.indicator,
highlighter = self.highlighter,
})
end
function inputtextbox:start()
self.textbox:set_font(self.font)
self.textbox:set_markup(text_with_cursor {
text = self.text,
hint = self.hint,
cursor = self.cursor,
cursor_pos = self.cursor_pos,
select_all = self.select_all,
indicator = self.indicator,
highlighter = self.highlighter,
})
self._private.grabber = keygrabber.run(
function(modifierts, key, event)
local mod = {}
for _, v in ipairs(modifierts) do mod[v] = true end
--Get out cases
if (mod.Control and (key == "c" or key == "g")) or (not mod.Control and key == "Escape") then
self:stop()
return false
elseif (mod.Control and (key == "j" or key == "m")) then
--callback
return
end
end
)
end
function inputtextbox:stop()
keygrabber.stop(self._private.grabber)
history_save(self.history_path)
return false
end
--- Create a new inputtextbox
--
-- @tparam[opt=""] string text The hint text when there is no input
-- @treturn table A new inputtextbox widget
-- @constructorfct wibox.widget.inputtextbox
local function new(args)
args = args or {}
args.callback = args.callback or nil
args.hint = args.hint or ""
args.font = args.font or beautiful.inputtextbox_font or beautiful.font
args.bg = args.bg or beautiful.inputtextbox_bg or beautiful.bg_normal
args.fg_hint = args.fg_hint or beautiful.inputtextbox_fg_hint or beautiful.fg_normal or "#888888"
args.fg = args.fg or beautiful.inputtextbox_fg or beautiful.fg_normal
args.cursor = args.cursor or "fleur"
args.select_all = args.select_all or false
args.highlighter = args.highlighter or nil
local textbox = wibox.widget.textbox()
textbox:set_text(args.hint or "")
--textbox:set_fg(args.fg_hint or beautiful.fg_hint or "#888888")
--textbox:set_bg(args.bg_normal or beautiful.bg_normal or "#212121")
local ret = gobject({})
ret._private = {}
gtable.crush(ret, inputtextbox)
gtable.crush(ret, args)
return ret
end
function inputtextbox.mt.__call(...)
return new(...)
end
return setmetatable(inputtextbox, inputtextbox.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80