diff --git a/awesome/awful/widget/inputbox.lua b/awesome/awful/widget/inputbox.lua index ba59ce3..e371d6e 100644 --- a/awesome/awful/widget/inputbox.lua +++ b/awesome/awful/widget/inputbox.lua @@ -8,16 +8,15 @@ --------------------------------------------------------------------------- local setmetatable = setmetatable -local abutton = require("awful.button") local beautiful = require("beautiful") local gtable = require("gears.table") local base = require("wibox.widget.base") local gstring = require("gears.string") -local keygrabber = require("awful.keygrabber") -local wtemplate = require("wibox.template") +local akeygrabber = require("awful.keygrabber") +local akey = require("awful.key") +local textbox = require("wibox.widget.textbox") -local capi = -{ +local capi = { selection = selection, mousegrabber = mousegrabber, 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_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_text = self.hint_text or "" 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" @@ -41,16 +39,17 @@ local function text_with_cursor(text, cursor_pos, self) return "" .. placeholder_text .. "" end + local offset = 0 + if text:sub(cursor_pos - 1, cursor_pos - 1) == -1 then + offset = 1 + 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)) @@ -64,14 +63,12 @@ local function text_with_cursor(text, cursor_pos, self) self._private.highlight.cur_pos_end)) local text_end_highlight = gstring.xml_escape(text:sub(self._private.highlight.cur_pos_end + 1)) - return "" .. text_start_highlight .. "" .. + return text_start_highlight .. "" .. - text_highlighted .. - "" .. "" .. text_end_highlight .. "" + text_highlighted .. "" .. text_end_highlight else - return "" .. text_start .. "" .. - "" .. - char .. "" .. "" .. text_end .. spacer .. "" + return text_start .. "" .. + char .. "" .. text_end .. spacer end end @@ -91,99 +88,6 @@ end 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 function inputbox:clear() self:set_text("") @@ -195,35 +99,23 @@ end function inputbox:set_text(text) self._private.text = text + self.markup = text_with_cursor(self:get_text(), #self:get_text(), self) self:emit_signal("property::text", text) end --- Stop the keygrabber and mousegrabber function inputbox:stop() + if (not self.akeygrabber) or (not self.akeygrabber.is_running) then return end self:emit_signal("stopped") - keygrabber.stop() - capi.mousegrabber.stop() + self.akeygrabber.stop() end function inputbox:focus() - keygrabber.stop() - if not keygrabber.is_running then + if (not self.akeygrabber) or (not self.akeygrabber.is_running) then + akeygrabber.stop() 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", "") @@ -231,226 +123,293 @@ function inputbox:focus() 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 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 + self.akeygrabber = akeygrabber { + autostart = true, + start_callback = function() + self:emit_signal("started") + end, + stop_callback = function(_, stop_key) + if stop_key == "Return" then + self:emit_signal("submit", self:get_text(), stop_key) + -- Only reset text on enter as on escape you might want to continue later + self:set_text("") else + self:emit_signal("stopped", stop_key) + end + end, + stop_key = { "Escape", "Return" }, + keybindings = { + --lShift, rShift = #50, #62 + --lControl, rControl = #37, #105 + akey { + modifiers = { "Shift" }, + key = "Left", -- left + on_press = function() + 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 + 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 + end + + cursor_pos = cursor_pos - 1 + end + 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 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 + 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", "Right") + end + }, + akey { + modifiers = { "Control" }, + key = "a", -- a + on_press = function() + -- Mark the entire text + self._private.highlight = { + cur_pos_start = 1, + cur_pos_end = #self._private.text + } + self.markup = text_with_cursor(self:get_text(), cursor_pos, self) + self:emit_signal("inputbox::key_pressed", "Control", "a") + end + }, + akey { + modifiers = { "Control" }, + key = "v", -- v + on_press = function() + 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 + + self.markup = text_with_cursor(self:get_text(), cursor_pos, self) + self:emit_signal("inputbox::key_pressed", "Control", "v") + 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 + 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 + 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") + if next_space then + cursor_pos = cursor_pos + next_space + else + cursor_pos = #self._private.text + 1 + end + + 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", "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 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 + 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)) + cursor_pos = cursor_pos - 1 - offset + end + end + 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 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 + 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 + if cursor_pos > 1 then + cursor_pos = cursor_pos - 1 + end + self._private.highlight = {} + end + }, + akey { + modifiers = {}, + key = "Right", --right + on_press = function() + -- Move cursor to the right + if cursor_pos <= #self._private.text then + cursor_pos = cursor_pos + 1 + end + self._private.highlight = {} + end + }, + --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 + 1 + cursor_pos = cursor_pos + #key 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 + elseif modifiers[1] == "Mod2" or "" then 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 + 1 + 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 + self.markup = text_with_cursor(self:get_text(), cursor_pos, self) + self:emit_signal("inputbox::key_pressed", modifiers, key) 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 --- Creates a new inputbox widget @@ -467,51 +426,16 @@ end -- @treturn awful.widget.inputbox The inputbox widget. -- @constructorfct awful.widget.inputbox 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) - w:set_widget(wtemplate.make_from_value(args.widget_template)) + w.keybindings = args.keybindings or {} + w.hint_text = args.hint_text - 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 - ) - - -- Initialize the text and placeholder with a first update - w:get_widget():update { - text = text_with_cursor("", 1, w) - } + w.markup = args.text or text_with_cursor("", 1, w) return w end diff --git a/awesome/awful/widget/toggle_widget.lua b/awesome/awful/widget/toggle_widget.lua new file mode 100644 index 0000000..1907e9c --- /dev/null +++ b/awesome/awful/widget/toggle_widget.lua @@ -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) diff --git a/awesome/rc.lua b/awesome/rc.lua index bcb5c0c..2762f45 100644 --- a/awesome/rc.lua +++ b/awesome/rc.lua @@ -17,10 +17,9 @@ screen = screen selection = selection 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 = {} - require("src.theme.user_config") require("src.theme.theme_config") require("src.tools.gio_icon_lookup") @@ -33,6 +32,4 @@ require("src.core.rules") require("src.bindings.global_buttons") require("src.bindings.bind_to_tags") require("src.modules.init") -require("src.tools.helpers.init") --require("src.tools.auto_starter")(User_config.autostart) ---require("src.tools.dbus.bluetooth_dbus")() diff --git a/awesome/src/assets/icons/bluetooth/audio-card.svg b/awesome/src/assets/icons/bluetooth/audio-card.svg index a09c799..556a7ed 100644 --- a/awesome/src/assets/icons/bluetooth/audio-card.svg +++ b/awesome/src/assets/icons/bluetooth/audio-card.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/audio-headphones.svg b/awesome/src/assets/icons/bluetooth/audio-headphones.svg index 49d9ff5..12427d8 100644 --- a/awesome/src/assets/icons/bluetooth/audio-headphones.svg +++ b/awesome/src/assets/icons/bluetooth/audio-headphones.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/audio-headset.svg b/awesome/src/assets/icons/bluetooth/audio-headset.svg index 68de8be..f15a13b 100644 --- a/awesome/src/assets/icons/bluetooth/audio-headset.svg +++ b/awesome/src/assets/icons/bluetooth/audio-headset.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/bluetooth-off.svg b/awesome/src/assets/icons/bluetooth/bluetooth-off.svg index 4a8775a..8968d0e 100644 --- a/awesome/src/assets/icons/bluetooth/bluetooth-off.svg +++ b/awesome/src/assets/icons/bluetooth/bluetooth-off.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/bluetooth-on.svg b/awesome/src/assets/icons/bluetooth/bluetooth-on.svg index 2d7ae3a..5347f3f 100644 --- a/awesome/src/assets/icons/bluetooth/bluetooth-on.svg +++ b/awesome/src/assets/icons/bluetooth/bluetooth-on.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/camera-photo.svg b/awesome/src/assets/icons/bluetooth/camera-photo.svg index 14d9649..668c23d 100644 --- a/awesome/src/assets/icons/bluetooth/camera-photo.svg +++ b/awesome/src/assets/icons/bluetooth/camera-photo.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/camera-video.svg b/awesome/src/assets/icons/bluetooth/camera-video.svg index 5222ea3..e7c6cc8 100644 --- a/awesome/src/assets/icons/bluetooth/camera-video.svg +++ b/awesome/src/assets/icons/bluetooth/camera-video.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/computer.svg b/awesome/src/assets/icons/bluetooth/computer.svg index de38c7d..4b9e9de 100644 --- a/awesome/src/assets/icons/bluetooth/computer.svg +++ b/awesome/src/assets/icons/bluetooth/computer.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/delete.svg b/awesome/src/assets/icons/bluetooth/delete.svg new file mode 100644 index 0000000..0f0c936 --- /dev/null +++ b/awesome/src/assets/icons/bluetooth/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/awesome/src/assets/icons/bluetooth/edit.svg b/awesome/src/assets/icons/bluetooth/edit.svg new file mode 100644 index 0000000..2e90a4f --- /dev/null +++ b/awesome/src/assets/icons/bluetooth/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/awesome/src/assets/icons/bluetooth/input-gaming.svg b/awesome/src/assets/icons/bluetooth/input-gaming.svg index cdf3ee2..ffdaecf 100644 --- a/awesome/src/assets/icons/bluetooth/input-gaming.svg +++ b/awesome/src/assets/icons/bluetooth/input-gaming.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/input-keyboard.svg b/awesome/src/assets/icons/bluetooth/input-keyboard.svg index c36d000..8e7e634 100644 --- a/awesome/src/assets/icons/bluetooth/input-keyboard.svg +++ b/awesome/src/assets/icons/bluetooth/input-keyboard.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/input-mouse.svg b/awesome/src/assets/icons/bluetooth/input-mouse.svg index c5ea217..bea7307 100644 --- a/awesome/src/assets/icons/bluetooth/input-mouse.svg +++ b/awesome/src/assets/icons/bluetooth/input-mouse.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/input-tablet.svg b/awesome/src/assets/icons/bluetooth/input-tablet.svg index ddf8170..1d80d18 100644 --- a/awesome/src/assets/icons/bluetooth/input-tablet.svg +++ b/awesome/src/assets/icons/bluetooth/input-tablet.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/link-off.svg b/awesome/src/assets/icons/bluetooth/link-off.svg index 3c5e302..6a83a3e 100644 --- a/awesome/src/assets/icons/bluetooth/link-off.svg +++ b/awesome/src/assets/icons/bluetooth/link-off.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/link.svg b/awesome/src/assets/icons/bluetooth/link.svg index 6f4c3b6..1121413 100644 --- a/awesome/src/assets/icons/bluetooth/link.svg +++ b/awesome/src/assets/icons/bluetooth/link.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/menu-down.svg b/awesome/src/assets/icons/bluetooth/menu-down.svg index 50b8625..1e14b40 100644 --- a/awesome/src/assets/icons/bluetooth/menu-down.svg +++ b/awesome/src/assets/icons/bluetooth/menu-down.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/menu-up.svg b/awesome/src/assets/icons/bluetooth/menu-up.svg index 5fb8642..bca0cb4 100644 --- a/awesome/src/assets/icons/bluetooth/menu-up.svg +++ b/awesome/src/assets/icons/bluetooth/menu-up.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/multimedia-player.svg b/awesome/src/assets/icons/bluetooth/multimedia-player.svg index b5cfa13..88452c5 100644 --- a/awesome/src/assets/icons/bluetooth/multimedia-player.svg +++ b/awesome/src/assets/icons/bluetooth/multimedia-player.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/network-wireless.svg b/awesome/src/assets/icons/bluetooth/network-wireless.svg index 3974275..1a3e7d4 100644 --- a/awesome/src/assets/icons/bluetooth/network-wireless.svg +++ b/awesome/src/assets/icons/bluetooth/network-wireless.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/phone.svg b/awesome/src/assets/icons/bluetooth/phone.svg index cd9374e..94d50bb 100644 --- a/awesome/src/assets/icons/bluetooth/phone.svg +++ b/awesome/src/assets/icons/bluetooth/phone.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/power.svg b/awesome/src/assets/icons/bluetooth/power.svg index 343d1ba..d88bac0 100644 --- a/awesome/src/assets/icons/bluetooth/power.svg +++ b/awesome/src/assets/icons/bluetooth/power.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/printer.svg b/awesome/src/assets/icons/bluetooth/printer.svg index 5e81f96..4da33c3 100644 --- a/awesome/src/assets/icons/bluetooth/printer.svg +++ b/awesome/src/assets/icons/bluetooth/printer.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/refresh.svg b/awesome/src/assets/icons/bluetooth/refresh.svg index 04b9c88..ad9bc0c 100644 --- a/awesome/src/assets/icons/bluetooth/refresh.svg +++ b/awesome/src/assets/icons/bluetooth/refresh.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/awesome/src/assets/icons/bluetooth/scanner.svg b/awesome/src/assets/icons/bluetooth/scanner.svg index d530d21..3477ac2 100644 --- a/awesome/src/assets/icons/bluetooth/scanner.svg +++ b/awesome/src/assets/icons/bluetooth/scanner.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/television.svg b/awesome/src/assets/icons/bluetooth/television.svg index 6c6dfcc..499049b 100644 --- a/awesome/src/assets/icons/bluetooth/television.svg +++ b/awesome/src/assets/icons/bluetooth/television.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/trusted.svg b/awesome/src/assets/icons/bluetooth/trusted.svg new file mode 100644 index 0000000..56c4c5c --- /dev/null +++ b/awesome/src/assets/icons/bluetooth/trusted.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/awesome/src/assets/icons/bluetooth/untrusted.svg b/awesome/src/assets/icons/bluetooth/untrusted.svg new file mode 100644 index 0000000..949f0c1 --- /dev/null +++ b/awesome/src/assets/icons/bluetooth/untrusted.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/awesome/src/assets/icons/bluetooth/video-display.svg b/awesome/src/assets/icons/bluetooth/video-display.svg index e8be002..2aad570 100644 --- a/awesome/src/assets/icons/bluetooth/video-display.svg +++ b/awesome/src/assets/icons/bluetooth/video-display.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/bluetooth/watch.svg b/awesome/src/assets/icons/bluetooth/watch.svg index 9db8a32..3951480 100644 --- a/awesome/src/assets/icons/bluetooth/watch.svg +++ b/awesome/src/assets/icons/bluetooth/watch.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/awesome/src/assets/icons/network/close.svg b/awesome/src/assets/icons/network/close.svg new file mode 100644 index 0000000..2636197 --- /dev/null +++ b/awesome/src/assets/icons/network/close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/awesome/src/assets/icons/network/refresh.svg b/awesome/src/assets/icons/network/refresh.svg new file mode 100644 index 0000000..ad9bc0c --- /dev/null +++ b/awesome/src/assets/icons/network/refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/awesome/src/core/notifications.lua b/awesome/src/core/notifications.lua index 12d54a6..bf07861 100644 --- a/awesome/src/core/notifications.lua +++ b/awesome/src/core/notifications.lua @@ -8,6 +8,7 @@ local gears = require("gears") local menubar = require('menubar') local naughty = require("naughty") local wibox = require("wibox") +local wtemplate = require("wibox.template") local rubato = require("src.lib.rubato") @@ -64,7 +65,7 @@ naughty.connect_signal( n.message = string.format("%s", Theme_config.notification.fg_normal_message, n.message) or "" 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 local use_image = false @@ -91,10 +92,10 @@ naughty.connect_signal( use_image = true end - local action_template_widget = {} + local action_template_widget if use_image then - action_template_widget = { + action_template_widget = wibox.template { { { { @@ -127,7 +128,7 @@ naughty.connect_signal( widget = wibox.container.margin } else - action_template_widget = { + action_template_widget = wibox.template { { { { @@ -176,8 +177,8 @@ naughty.connect_signal( arc_start = 10 end - local w_template = wibox.widget { - { + local w_template = wibox.template { + widget = wibox.widget { { { { @@ -187,161 +188,166 @@ naughty.connect_signal( { { { - image = gears.color.recolor_image(icondir .. "notification-outline.svg", - Theme_config.notification.icon_color), - resize = false, - valign = "center", - halign = "center", - widget = wibox.widget.imagebox + { + image = gears.color.recolor_image(icondir .. "notification-outline.svg", + Theme_config.notification.icon_color), + resize = false, + valign = "center", + halign = "center", + widget = wibox.widget.imagebox + }, + right = dpi(5), + widget = wibox.container.margin }, - right = dpi(5), - widget = wibox.container.margin + { + markup = n.app_name or 'System Notification', + align = "center", + valign = "center", + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.horizontal }, - { - markup = n.app_name or 'System Notification', - align = "center", - valign = "center", - widget = wibox.widget.textbox - }, - layout = wibox.layout.fixed.horizontal + fg = Theme_config.notification.fg_appname, + widget = wibox.container.background }, - fg = Theme_config.notification.fg_appname, - widget = wibox.container.background + margins = dpi(10), + widget = wibox.container.margin }, - margins = dpi(10), - widget = wibox.container.margin - }, - nil, - { + nil, { { - text = os.date("%H:%M"), - widget = wibox.widget.textbox + { + text = os.date("%H:%M"), + widget = wibox.widget.textbox + }, + id = "background", + fg = Theme_config.notification.fg_time, + widget = wibox.container.background }, - id = "background", - fg = Theme_config.notification.fg_time, - widget = wibox.container.background - }, - { { { { { - font = User_config.font.specify .. ", 10", - text = "✕", - align = "center", - valign = "center", - widget = wibox.widget.textbox + { + font = User_config.font.specify .. ", 10", + text = "✕", + align = "center", + valign = "center", + widget = wibox.widget.textbox + }, + start_angle = 4.71239, + thickness = dpi(2), + min_value = 0, + max_value = arc_start, + value = arc_start, + widget = wibox.container.arcchart, + id = "arc_chart" }, - start_angle = 4.71239, - thickness = dpi(2), - min_value = 0, - max_value = arc_start, - value = arc_start, - widget = wibox.container.arcchart, - id = "arc_chart" + id = "background1", + fg = Theme_config.notification.fg_close, + bg = Theme_config.notification.bg_close, + widget = wibox.container.background }, - id = "background1", - fg = Theme_config.notification.fg_close, - bg = Theme_config.notification.bg_close, - widget = wibox.container.background + strategy = "exact", + width = dpi(20), + height = dpi(20), + widget = wibox.container.constraint, + id = "const1" }, - strategy = "exact", - width = dpi(20), - height = dpi(20), - widget = wibox.container.constraint, - id = "const1" + margins = dpi(10), + widget = wibox.container.margin, + id = "arc_margin" }, - margins = dpi(10), - widget = wibox.container.margin, - id = "arc_margin" + layout = wibox.layout.fixed.horizontal, + id = "arc_app_layout_2" }, - layout = wibox.layout.fixed.horizontal, - id = "arc_app_layout_2" + id = "arc_app_layout", + layout = wibox.layout.align.horizontal }, - id = "arc_app_layout", - layout = wibox.layout.align.horizontal + id = "arc_app_bg", + border_color = Theme_config.notification.title_border_color, + border_width = Theme_config.notification.title_border_width, + widget = wibox.container.background }, - id = "arc_app_bg", - border_color = Theme_config.notification.title_border_color, - border_width = Theme_config.notification.title_border_width, - widget = wibox.container.background - }, - { { { { { - image = n.icon, - resize = true, - widget = wibox.widget.imagebox, - valign = "center", - halign = "center", - clip_shape = function(cr, width, height) - gears.shape.rounded_rect(cr, width, height, 10) - end + { + image = n.icon, + resize = true, + widget = wibox.widget.imagebox, + valign = "center", + halign = "center", + clip_shape = function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, 10) + end + }, + width = naughty.config.defaults.icon_size, + height = naughty.config.defaults.icon_size, + strategy = "exact", + widget = wibox.container.constraint }, - width = naughty.config.defaults.icon_size, - height = naughty.config.defaults.icon_size, - strategy = "exact", - widget = wibox.container.constraint - }, - halign = "center", - valign = "top", - widget = wibox.container.place - }, - left = dpi(20), - bottom = dpi(15), - top = dpi(15), - right = dpi(10), - widget = wibox.container.margin - }, - { - { - { - widget = naughty.widget.title, - align = "left" - }, - { - widget = naughty.widget.message, - align = "left" - }, - { - actions_template, + halign = "center", + valign = "top", widget = wibox.container.place }, - layout = wibox.layout.fixed.vertical + left = dpi(20), + bottom = dpi(15), + top = dpi(15), + right = dpi(10), + widget = wibox.container.margin }, - left = dpi(10), - bottom = dpi(10), - top = dpi(10), - right = dpi(20), - widget = wibox.container.margin + { + { + { + widget = naughty.widget.title, + align = "left" + }, + { + widget = naughty.widget.message, + align = "left" + }, + { + actions_template, + widget = wibox.container.place + }, + layout = wibox.layout.fixed.vertical + }, + left = dpi(10), + bottom = dpi(10), + top = dpi(10), + right = dpi(20), + widget = wibox.container.margin + }, + layout = wibox.layout.fixed.horizontal }, - layout = wibox.layout.fixed.horizontal + id = "widget_layout", + layout = wibox.layout.fixed.vertical }, - id = "widget_layout", - layout = wibox.layout.fixed.vertical + id = "min_size", + strategy = "min", + width = dpi(100), + widget = wibox.container.constraint }, - id = "min_size", - strategy = "min", - width = dpi(100), + id = "max_size", + strategy = "max", + width = Theme.notification_max_width or dpi(500), widget = wibox.container.constraint }, - id = "max_size", - strategy = "max", - width = Theme.notification_max_width or dpi(500), - widget = wibox.container.constraint + id = "background", + bg = Theme_config.notification.bg, + border_color = Theme_config.notification.border_color, + border_width = Theme_config.notification.border_width, + shape = Theme_config.notification.shape_inside, + widget = wibox.container.background }, - id = "background", - bg = Theme_config.notification.bg, - border_color = Theme_config.notification.border_color, - border_width = Theme_config.notification.border_width, - shape = Theme_config.notification.shape_inside, - 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 timeout = n.timeout @@ -359,7 +365,7 @@ naughty.connect_signal( rubato_timer.target = 0 - w_template:connect_signal( + w_template:get_widget():connect_signal( "mouse::enter", function() n.timeout = 99999 @@ -367,7 +373,7 @@ naughty.connect_signal( end ) - w_template:connect_signal( + w_template:get_widget():connect_signal( "mouse::leave", function() n.timeout = rubato_timer.pos @@ -379,33 +385,27 @@ naughty.connect_signal( Hover_signal(close) - close:connect_signal( - "button::press", - function() + close:connect_signal("button::press", function() + n:destroy() + end) + + w_template:get_widget():connect_signal("button::press", function(_, _, _, key) + if key == 3 then n:destroy() end - ) - - w_template:connect_signal( - "button::press", - function(_, _, _, key) - if key == 3 then - n:destroy() - end - -- Raise the client on click - if key == 1 then - for _, client in ipairs(capi.client.get()) do - if client.name:match(n.app_name) then - if not client:isvisible() and client.first_tag then - client.first_tag:view_only() - end - client:emit_signal('request::activate') - client:raise() + -- Raise the client on click + if key == 1 then + for _, client in ipairs(capi.client.get()) do + if client.name:match(n.app_name) then + if not client:isvisible() and client.first_tag then + client.first_tag:view_only() end + client:emit_signal('request::activate') + client:raise() end end end - ) + end) local box = naughty.layout.box { notification = n, diff --git a/awesome/src/core/signals.lua b/awesome/src/core/signals.lua index b1bc8d1..5e802c9 100644 --- a/awesome/src/core/signals.lua +++ b/awesome/src/core/signals.lua @@ -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 awful.placement.no_offscreen(c) 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 c.floating = false end diff --git a/awesome/src/dbus/bluetooth_dbus.lua b/awesome/src/dbus/bluetooth_dbus.lua deleted file mode 100644 index d488339..0000000 --- a/awesome/src/dbus/bluetooth_dbus.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/application_launcher/application.lua b/awesome/src/modules/application_launcher/application.lua index c490155..550f82e 100644 --- a/awesome/src/modules/application_launcher/application.lua +++ b/awesome/src/modules/application_launcher/application.lua @@ -44,6 +44,47 @@ function application_grid:get_widget() return self._private.widget 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() local list = {} 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, bg = Theme_config.application_launcher.application.bg, fg = Theme_config.application_launcher.application.fg, + desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "", shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, dpi(8)) end, @@ -256,29 +298,64 @@ function application_grid:set_applications(search_filter) 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 -- Match the filter 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.keywords or ""), string.lower(filter)) then - grid:add(application) - -- Get the current position in the grid of the application as a table - local pos = grid:get_widget_position(application) - - -- Check if the curser is currently at the same position as the application - capi.awesome.connect_signal( - "update::selected", - function() - 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 - else - application.border_color = Theme_config.application_launcher.application.border_color - end + if #dock == 0 then + 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 + + 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( + "update::selected", + function() + if self._private.curser.y == pos.row and self._private.curser.x == pos.col then + app.border_color = Theme_config.application_launcher.application.border_color_active + else + app.border_color = Theme_config.application_launcher.application.border_color + end + end + ) + end + capi.awesome.emit_signal("update::selected") self:set_widget(grid) end @@ -292,7 +369,6 @@ function application_grid:move_up() end function application_grid:move_down() - print(self._private.curser.y) self._private.curser.y = self._private.curser.y + 1 local grid_rows, _ = self:get_widget():get_dimension() 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, self._private.curser.x)[1] 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 function application_grid:reset() @@ -344,10 +449,17 @@ function application_grid.new(args) 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:set_applications() - return w end diff --git a/awesome/src/modules/application_launcher/init.lua b/awesome/src/modules/application_launcher/init.lua index ef7c988..436425a 100644 --- a/awesome/src/modules/application_launcher/init.lua +++ b/awesome/src/modules/application_launcher/init.lua @@ -10,6 +10,7 @@ local wibox = require("wibox") local gshape = require("gears.shape") local gtable = require("gears.table") local gobject = require("gears.object") +local abutton = require("awful.button") local capi = { awesome = awesome, @@ -18,39 +19,6 @@ local capi = { 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") {} @@ -62,10 +30,58 @@ function application_launcher.new(args) 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 { { { - 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, spacing = dpi(10), @@ -101,52 +117,70 @@ function application_launcher.new(args) border_width = Theme_config.application_launcher.border_width } + local searchbar_bg = applicaton_launcher:get_children_by_id("searchbar_bg")[1] + capi.awesome.connect_signal( "application_launcher::show", function() + capi.awesome.emit_signal("update::selected") if capi.mouse.screen == args.screen then ret.application_container.visible = not ret.application_container.visible end if ret.application_container.visible then - ret.searchbar:focus() + searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active + searchbar:focus() else + searchbar:set_text("") awful.keygrabber.stop() end end ) - ret.searchbar:connect_signal( + searchbar:connect_signal( "submit", - function(text) + function(_, text) ret.application_grid:execute() 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 ) - ret.searchbar:connect_signal( + searchbar:connect_signal( "stopped", - function() - ret.searchbar:get_widget().widget.border_color = Theme_config.application_launcher.searchbar.border_color + function(_, stop_key) + 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 ) - ret.searchbar:connect_signal( + searchbar:connect_signal( "started", 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 ) - awesome.connect_signal( + searchbar:connect_signal( "inputbox::key_pressed", - function(modkey, key) + function(_, modkey, key) if key == "Escape" then - ret.searchbar:stop() + searchbar:stop() capi.awesome.emit_signal("application_launcher::show") ret.application_grid:reset() - ret.searchbar:set_text("") + searchbar:set_text("") 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) if event == "press" then if key2 == "Down" then @@ -155,7 +189,7 @@ function application_launcher.new(args) local old_y = ret.application_grid._private.curser.y ret.application_grid:move_up() if old_y - ret.application_grid._private.curser.y == 0 then - ret.searchbar:focus() + searchbar:focus() end elseif key2 == "Left" then ret.application_grid:move_left() @@ -166,17 +200,20 @@ function application_launcher.new(args) ret.application_grid:execute() capi.awesome.emit_signal("application_launcher::show") ret.application_grid:reset() - ret.searchbar:set_text("") + searchbar:set_text("") + ret.application_grid:set_applications(searchbar:get_text()) elseif key2 == "Escape" then capi.awesome.emit_signal("application_launcher::show") ret.application_grid:reset() - ret.searchbar:set_text("") + searchbar:set_text("") + ret.application_grid:set_applications(searchbar:get_text()) awful.keygrabber.stop() end end end) + searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color end - ret.application_grid:set_applications(ret.searchbar:get_text()) + ret.application_grid:set_applications(searchbar:get_text()) end ) diff --git a/awesome/src/modules/application_launcher/searchbar.lua b/awesome/src/modules/application_launcher/searchbar.lua deleted file mode 100644 index 5d53141..0000000 --- a/awesome/src/modules/application_launcher/searchbar.lua +++ /dev/null @@ -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 "Search" - 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 .. - "" .. char .. "" .. 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 diff --git a/awesome/src/modules/bluetooth/device.lua b/awesome/src/modules/bluetooth/device.lua index 25db7d8..6b01ebe 100644 --- a/awesome/src/modules/bluetooth/device.lua +++ b/awesome/src/modules/bluetooth/device.lua @@ -5,52 +5,106 @@ -- Awesome Libs local awful = require("awful") local dpi = require("beautiful").xresources.apply_dpi -local gobject = require("gears").object local gtable = require("gears").table local gcolor = require("gears").color local gshape = require("gears").shape local gfilesystem = require("gears").filesystem local wibox = require("wibox") +local base = require("wibox.widget.base") +local lgi = require("lgi") +local dbus_proxy = require("dbus_proxy") -local capi = { - awesome = awesome, -} +local context_menu = require("src.modules.context_menu") local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/" +local capi = { + awesome = awesome +} + local device = { mt = {} } -function device:connect() - self.device:Connect() - self.widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link.svg", - Theme_config.bluetooth_controller.icon_color_dark) - capi.awesome.emit_signal("bluetooth::disconnect", device) +function device:layout(_, width, height) + if self._private.widget then + return { base.place_widget_at(self._private.widget, 0, 0, width, height) } + end end -function device:disconnect() - self.device:Disconnect() - self.widget:get_children_by_id("con")[1].image = gcolor.recolor_image(icondir .. "link-off.svg", - Theme_config.bluetooth_controller.icon_color_dark) - capi.awesome.emit_signal("bluetooth::connect", device) +function device: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 + +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 function device.new(args) args = args 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 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, - id = "alias", - widget = wibox.widget.textbox + inputbox, + widget = wibox.container.constraint, + strategy = "min", + width = dpi(400), + id = "const" }, { text = "Connecting...", @@ -150,33 +206,133 @@ function device.new(args) shape = function(cr, width, height) gshape.rounded_rect(cr, width, height, dpi(4)) end, - device = ret.device, widget = wibox.container.background - } + }) - if ret.device.Connected then - 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) + gtable.crush(ret, device, true) + + if args.device then + ret.device = args.device end - device_widget:buttons( + 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 + } + } + } + + ret:buttons( gtable.join( awful.button({}, 1, function() - if ret.device.Connected then - ret:disconnect() - else - ret:connect() + ret:toggle_connect() + end), + awful.button({}, 3, function() + 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 + cm:toggle() 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 end diff --git a/awesome/src/modules/bluetooth/init.lua b/awesome/src/modules/bluetooth/init.lua index a5376b8..7072f44 100644 --- a/awesome/src/modules/bluetooth/init.lua +++ b/awesome/src/modules/bluetooth/init.lua @@ -5,12 +5,16 @@ -- Awesome Libs local awful = require("awful") local dpi = require("beautiful").xresources.apply_dpi -local gobject = require("gears").object local gtable = require("gears").table local gcolor = require("gears").color local gshape = require("gears").shape local gfilesystem = require("gears").filesystem 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") @@ -18,54 +22,218 @@ local rubato = require("src.lib.rubato") local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/bluetooth/" +local dnd_widget = require("awful.widget.toggle_widget") + local capi = { awesome = awesome, mouse = mouse, mousegrabber = mousegrabber, } - local bluetooth = { mt = {} } -bluetooth.devices = { - paired = { layout = wibox.layout.fixed.vertical }, - discovered = { layout = wibox.layout.fixed.vertical } -} - -function bluetooth:get_devices() - return self.devices +function bluetooth:layout(_, width, height) + if self._private.widget then + return { base.place_widget_at(self._private.widget, 0, 0, width, height) } + end end -local function add_device(self, device, battery) - --Check if the device is already in the list - for _, status in pairs(self.devices) do - for _, dev in ipairs(status) do - if dev.device.Address == device.Address then - return +function bluetooth: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 + +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 + 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 + for _, value in pairs(plist.children) do + if value.device.Address:match(device.Address) then return end + end + + if device.Paired then + plist:add(bt_device { + device = device, + path = object_path, + remove_callback = function() + self:remove_device_information(device) + end, + }) + else + dlist:add(bt_device { + device = device, + path = object_path, + remove_callback = function() + self:remove_device_information(device) + end, + }) + end +end + +function bluetooth:remove_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 _, d in ipairs(dlist.children) do + if d.device.object_path == object_path then + dlist:remove_widgets(d) + 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 - end - if device.Paired then - table.insert(self.devices.paired, bt_device.new { device = device, battery = battery }.widget) - else - table.insert(self.devices.discovered, bt_device.new { device = device, battery = battery }.widget) - end + capi.awesome.emit_signal(object_path .. "_updated", Device1) + end, "PropertiesChanged") + + self:add_device(Device1, object_path) end -local function remove_device(self, device) - for i, dev in pairs(self.devices) do - if dev.Address == device.Address then - table.remove(self.devices, i) - end - 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 function bluetooth.new(args) args = args or {} - local ret = gobject { enable_properties = true, enable_auto_signals = true } - gtable.crush(ret, bluetooth, true) - - local bluetooth_container = wibox.widget { + local ret = base.make_widget_from_value(wibox.widget { { { { @@ -198,29 +366,15 @@ function bluetooth.new(args) }, { { -- action buttons - { -- turn off - { - { - image = gcolor.recolor_image(icondir .. "power.svg", - Theme_config.bluetooth_controller.power_icon_color), - resize = false, - valign = "center", - halign = "center", - widget = wibox.widget.imagebox, - id = "icon" - }, - widget = wibox.container.margin, - margins = dpi(5), - id = "center" + { + dnd_widget { + color = Theme_config.bluetooth_controller.power_bg, + size = dpi(40) }, - 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", + id = "dnd", + widget = wibox.container.place, + valign = "center", + halign = "center" }, nil, { -- refresh @@ -236,16 +390,16 @@ function bluetooth.new(args) widget = wibox.container.margin, margins = dpi(5), }, - 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.refresh_bg, + id = "scan", widget = wibox.container.background }, layout = wibox.layout.align.horizontal }, + id = "marg_dnd", widget = wibox.container.margin, top = dpi(10), }, @@ -266,28 +420,91 @@ function bluetooth.new(args) widget = wibox.container.background }, width = dpi(400), + forced_width = dpi(400), strategy = "exact", 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( - "bluetooth::device_changed", - function(device, battery) - add_device(ret, device, battery) - remove_device(ret, device) - bluetooth_container:get_children_by_id("connected_device_list")[1].children = ret:get_devices().paired - bluetooth_container:get_children_by_id("discovered_device_list")[1].children = ret:get_devices().discovered - end - ) + -- Create a proxy for the bluez Adapter1 interface + ret._private.Adapter1 = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.bluez", + interface = "org.bluez.Adapter1", + path = "/org/bluez/hci0" + } - 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 = bluetooth_container:get_children_by_id("connected")[1].center + -- Create a proxy for the bluez Adapter1 Properties interface + ret._private.Adapter1Properties = dbus_proxy.Proxy:new { + 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( "button::press", function() - capi.awesome.emit_signal("bluetooth::scan") local rubato_timer = rubato.timed { duration = 0.2, pos = connected_list.forced_height, @@ -297,7 +514,7 @@ function bluetooth.new(args) end } 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 rubato_timer.target = dpi(size) end @@ -317,16 +534,14 @@ function bluetooth.new(args) end ) - 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 + local discovered_margin = ret:get_children_by_id("discovered_margin")[1] + local discovered_list = ret:get_children_by_id("discovered_list")[1] + local discovered_bg = ret:get_children_by_id("discovered_bg")[1] + local discovered = ret:get_children_by_id("discovered")[1].center discovered_margin:connect_signal( "button::press", function() - capi.awesome.emit_signal("bluetooth::scan") - local rubato_timer = rubato.timed { duration = 0.2, pos = discovered_list.forced_height, @@ -337,7 +552,7 @@ function bluetooth.new(args) } 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 size = 210 end @@ -357,52 +572,17 @@ function bluetooth.new(args) end end ) + --#endregion - ret.widget = awful.popup { - widget = bluetooth_container, - ontop = true, - bg = Theme_config.bluetooth_controller.container_bg, - 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 - } + ret:get_children_by_id("scan")[1]:buttons({ + awful.button({}, 1, function() + ret:scan() + end) + }) - awesome.connect_signal( - "bluetooth_controller::toggle", - function() - if ret.widget.screen == capi.mouse.screen then - ret.widget.visible = not ret.widget.visible - end - end - ) + Hover_signal(ret:get_children_by_id("scan")[1]) - - 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 - ) + return ret end function bluetooth.mt:__call(...) diff --git a/awesome/src/modules/bluetooth_controller.lua b/awesome/src/modules/bluetooth_controller.lua deleted file mode 100644 index 44b66ee..0000000 --- a/awesome/src/modules/bluetooth_controller.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/brightness_osd.lua b/awesome/src/modules/brightness_osd.lua deleted file mode 100644 index 359f255..0000000 --- a/awesome/src/modules/brightness_osd.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/context_menu.lua b/awesome/src/modules/context_menu.lua deleted file mode 100644 index b8e9561..0000000 --- a/awesome/src/modules/context_menu.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/context_menu/init.lua b/awesome/src/modules/context_menu/init.lua index 6beec02..c7b4d4e 100644 --- a/awesome/src/modules/context_menu/init.lua +++ b/awesome/src/modules/context_menu/init.lua @@ -52,7 +52,7 @@ function context_menu:make_entries(wtemplate, entries, spacing) return 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 local menu_entry = wibox.widget { { @@ -124,7 +124,8 @@ function context_menu:make_entries(wtemplate, entries, spacing) if not entry.submenu then entry.callback() end - self.visible = false + capi.awesome.emit_signal("submenu::close") + capi.awesome.emit_signal("cm::hide") end }) }) @@ -169,10 +170,8 @@ function context_menu:make_entries(wtemplate, entries, spacing) menu_entry.popup.visible = false end) end - - table.insert(menu_entries, menu_entry) + menu_entries[key] = menu_entry end - return menu_entries end @@ -182,6 +181,8 @@ function context_menu:toggle() self.visible = not self.visible 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) args = args or {} @@ -202,6 +203,11 @@ function context_menu.new(args) 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) return ret diff --git a/awesome/src/modules/crylia_bar/center_bar.lua b/awesome/src/modules/crylia_bar/center_bar.lua index e6a54fc..ec832a1 100644 --- a/awesome/src/modules/crylia_bar/center_bar.lua +++ b/awesome/src/modules/crylia_bar/center_bar.lua @@ -62,10 +62,7 @@ return function(s, widgets) bg = Theme_config.center_bar.bg, visible = true, maximum_width = dpi(500), - 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 + placement = function(c) awful.placement.top(c, { margins = dpi(10) }) end } top_center:struts { diff --git a/awesome/src/modules/crylia_bar/dock.lua b/awesome/src/modules/crylia_bar/dock.lua index bc2f1ae..be31528 100644 --- a/awesome/src/modules/crylia_bar/dock.lua +++ b/awesome/src/modules/crylia_bar/dock.lua @@ -257,10 +257,7 @@ return function(screen) screen = screen, type = "dock", height = dpi(User_config.dock_icon_size + 10), - 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 + placement = function(c) awful.placement.bottom(c, { margins = dpi(10) }) end } --- A fakedock to send a signal when the mouse is over it diff --git a/awesome/src/modules/crylia_bar/left_bar.lua b/awesome/src/modules/crylia_bar/left_bar.lua index fdad12f..916f465 100644 --- a/awesome/src/modules/crylia_bar/left_bar.lua +++ b/awesome/src/modules/crylia_bar/left_bar.lua @@ -57,10 +57,7 @@ return function(s, w) bg = Theme_config.left_bar.bg, visible = true, maximum_width = dpi(650), - 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 + placement = function(c) awful.placement.top_left(c, { margins = dpi(10) }) end } top_left:struts { diff --git a/awesome/src/modules/crylia_bar/right_bar.lua b/awesome/src/modules/crylia_bar/right_bar.lua index a4a03ad..6a1addf 100644 --- a/awesome/src/modules/crylia_bar/right_bar.lua +++ b/awesome/src/modules/crylia_bar/right_bar.lua @@ -56,10 +56,7 @@ return function(s, w) bg = Theme_config.right_bar.bg, visible = true, screen = s, - 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 + placement = function(c) awful.placement.top_right(c, { margins = dpi(10) }) end } top_right:struts { diff --git a/awesome/src/modules/desktop/context_menu.lua b/awesome/src/modules/desktop/context_menu.lua index f276b02..80276fe 100644 --- a/awesome/src/modules/desktop/context_menu.lua +++ b/awesome/src/modules/desktop/context_menu.lua @@ -31,8 +31,6 @@ function context_menu.new(args) local ret = gobject {} gtable.crush(ret, context_menu, true) - - capi.awesome.connect_signal("context_menu:show", function() ret:toggle() mousegrabber.run(function() @@ -44,7 +42,7 @@ function context_menu.new(args) end, nil) end) - return w + return ret end function context_menu.mt:__call(...) diff --git a/awesome/src/modules/init.lua b/awesome/src/modules/init.lua index d2c01fa..6dfce6f 100644 --- a/awesome/src/modules/init.lua +++ b/awesome/src/modules/init.lua @@ -17,13 +17,11 @@ awful.screen.connect_for_each_screen( User_config.layouts[1] ) - require("src.modules.desktop.context_menu") { screen = s } require("src.modules.desktop.desktop") { screen = s } require("src.modules.powermenu.powermenu")(s) require("src.modules.audio.volume_osd") { screen = s } --require("src.modules.audio.volume_controller") { screen = s } require("src.modules.brightness.brightness_osd")(s) - require("src.modules.bluetooth.init") { screen = s } require("src.modules.titlebar.titlebar") require("src.modules.crylia_bar.init")(s) --require("src.modules.crylia_wibox.init")(s) diff --git a/awesome/src/modules/network_controller/access_point.lua b/awesome/src/modules/network_controller/access_point.lua index 3f00e85..6f6f3de 100644 --- a/awesome/src/modules/network_controller/access_point.lua +++ b/awesome/src/modules/network_controller/access_point.lua @@ -10,6 +10,8 @@ local gfilesystem = require("gears").filesystem local gobject = require("gears").object local gcolor = require("gears").color 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") @@ -17,39 +19,28 @@ local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/network local access_point = { mt = {} } -access_point.connected = false - function access_point.new(args) args = args or {} - if not args.access_point 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" + if not args.NetworkManagerAccessPoint then return end 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 - 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, 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( - icondir .. icon, icon_color), + icondir .. "wifi-strength-" .. math.floor(args.NetworkManagerAccessPoint.Strength / 25) + 1 .. ".svg", + icon_color), id = "icon", resize = true, 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", widget = wibox.widget.textbox }, @@ -132,31 +124,32 @@ function access_point.new(args) border_width = Theme_config.network_manager.access_point.border_width, id = "background", shape = Theme_config.network_manager.access_point.device_shape, - device = ret.access_point, 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( awful.button( {}, 1, nil, function() - ap_form:popup_toggle() + ret.ap_form:popup_toggle() 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) - Hover_signal(ap_widget) - - ret.widget = ap_widget + Hover_signal(ret) return ret end diff --git a/awesome/src/modules/network_controller/ap_form.lua b/awesome/src/modules/network_controller/ap_form.lua index db736dc..dc4be7c 100644 --- a/awesome/src/modules/network_controller/ap_form.lua +++ b/awesome/src/modules/network_controller/ap_form.lua @@ -15,202 +15,171 @@ local capi = { } local ap_form = { mt = {} } -ap_form._private = {} - -ap_form.settigns_form = { - ssid = 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, - 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 { - 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, - forced_width = 300, - forced_height = 50, - }, - update_callback = function(template_widget, args) - template_widget.widget.const.marg.text_role.markup = args.text - end - } - }, -} function ap_form:popup_toggle() - self._private.popup.visible = not self._private.popup.visible + self.visible = not self.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 = { - { -- Header - { - nil, + local settigns_form = { + password = awful.widget.inputbox { + widget_template = wibox.template { + widget = wibox.widget { { - { - widget = wibox.widget.textbox, - text = args.SSID, - halign = "center", - valign = "center", - }, - widget = wibox.container.margin, - margins = dpi(5) - }, - { -- Close button { { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(icondir .. "close.svg", Theme_config.network_manager.form.icon_fg), - resize = false, + widget = wibox.widget.textbox, + halign = "left", valign = "center", - halign = "center", + id = "text_role", }, widget = wibox.container.margin, + margins = 5, + id = "marg" }, - widget = wibox.container.background, - id = "close_button", - bg = Theme_config.network_manager.form.close_bg + widget = wibox.container.constraint, + strategy = "exact", + width = 400, + height = 50, + id = "const" }, - layout = wibox.layout.align.horizontal + widget = wibox.container.background, + bg = "#212121", + fg = "#F0F0F0", + border_color = "#414141", + border_width = 2, + shape = gshape.rounded_rect, + forced_width = 300, + forced_height = 50, }, - widget = wibox.container.background, - bg = Theme_config.network_manager.form.header_bg, - fg = Theme_config.network_manager.form.header_fg, - }, - { -- Form - { -- SSID + update_callback = function(template_widget, args) + template_widget.widget.const.marg.text_role.markup = args.text + end + } + }, + } + + local ret = awful.popup { + widget = { + { + { -- Header { - widget = wibox.widget.textbox, - text = "SSID", - halign = "center", - valign = "center" + nil, + { + { + widget = wibox.widget.textbox, + text = args.ssid, + font = User_config.font.specify .. ",extra bold 16", + halign = "center", + valign = "center", + }, + widget = wibox.container.margin, + margins = dpi(5) + }, + { -- Close button + { + { + widget = wibox.widget.imagebox, + image = gcolor.recolor_image(icondir .. "close.svg", Theme_config.network_manager.form.icon_fg), + resize = false, + valign = "center", + halign = "center", + }, + widget = wibox.container.margin, + margins = dpi(5), + }, + widget = wibox.container.background, + shape = Theme_config.network_manager.form.close_icon_shape, + id = "close_button", + bg = Theme_config.network_manager.form.close_bg + }, + layout = wibox.layout.align.horizontal }, - nil, - -- Change to inputtextbox container - ret.settigns_form.ssid, - layout = wibox.layout.align.horizontal + widget = wibox.container.background, + bg = Theme_config.network_manager.form.header_bg, + fg = Theme_config.network_manager.form.header_fg, }, - { -- Password - { + { -- Form + { -- Password widget = wibox.widget.textbox, text = "Password", halign = "center", valign = "center" }, - nil, + { + widget = wibox.container.margin, + left = dpi(20), + right = dpi(20), + }, -- Change to inputtextbox container - ret.settigns_form.password, + settigns_form.password, layout = wibox.layout.align.horizontal }, - spacing = dpi(10), - layout = wibox.layout.fixed.vertical - }, - { -- Actions - { -- Auto connect - { + { -- Actions + { -- Auto connect { - checked = false, - shape = Theme_config.network_manager.form.checkbox_shape, - color = Theme_config.network_manager.form.checkbox_bg, - check_color = Theme_config.network_manager.form.checkbox_fg, - check_border_color = Theme_config.network_manager.form.check_border_color, - check_border_width = Theme_config.network_manager.form.check_border_width, - widget = wibox.widget.checkbox - }, - widget = wibox.container.constraint, - strategy = "exact", - width = dpi(30), - height = dpi(30) - }, - { - widget = wibox.widget.textbox, - text = "Auto connect", - halign = "center", - valign = "center" - }, - layout = wibox.layout.fixed.horizontal - }, - nil, - { -- Connect - { - { - widget = wibox.widget.textbox, - text = "Connect", + { + { + checked = false, + shape = Theme_config.network_manager.form.checkbox_shape, + color = Theme_config.network_manager.form.checkbox_fg, + paddings = dpi(3), + check_color = Theme_config.network_manager.form.checkbox_bg, + border_color = Theme_config.network_manager.form.checkbox_bg, + border_width = 2, + id = "checkbox", + widget = wibox.widget.checkbox + }, + widget = wibox.container.constraint, + strategy = "exact", + width = dpi(30), + height = dpi(30) + }, + widget = wibox.container.place, halign = "center", valign = "center" }, - widget = wibox.container.background, - bg = Theme_config.network_manager.form.button_bg, - fg = Theme_config.network_manager.form.button_fg, + { + widget = wibox.widget.textbox, + text = "Auto connect", + halign = "center", + valign = "center" + }, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal }, - widget = wibox.container.margin, - margins = dpi(10), + nil, + { -- Connect + { + { + { + widget = wibox.widget.textbox, + text = "Connect", + halign = "center", + valign = "center" + }, + widget = wibox.container.margin, + margins = dpi(10), + }, + widget = wibox.container.background, + bg = Theme_config.network_manager.form.button_bg, + fg = Theme_config.network_manager.form.button_fg, + shape = Theme_config.network_manager.form.button_shape, + id = "connect_button", + }, + widget = wibox.container.margin, + margins = dpi(10), + }, + layout = wibox.layout.align.horizontal }, - layout = wibox.layout.align.horizontal + spacing = dpi(20), + layout = wibox.layout.fixed.vertical }, - layout = wibox.layout.align.vertical + widget = wibox.container.margin, + margins = dpi(10) }, placement = awful.placement.centered, ontop = true, @@ -220,37 +189,36 @@ function ap_form.new(args) bg = Theme_config.network_manager.form.bg, fg = Theme_config.network_manager.form.fg, 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", screen = args.screen, } - ret._private.popup.widget:get_children_by_id("close_button")[1]:connect_signal("button::press", function() - ret:popup_toggle() + gtable.crush(ret, ap_form, true) + + local checkbox = ret.widget:get_children_by_id("checkbox")[1] + checkbox:connect_signal("button::press", function() + checkbox.checked = not checkbox.checked end) - ret.settigns_form.ssid:connect_signal( - "submit", - function(text) - end - ) + local close_button = ret.widget:get_children_by_id("close_button")[1] + close_button:connect_signal("button::press", function() + ret:popup_toggle() + end) + Hover_signal(close_button) - ret.settigns_form.ssid:connect_signal( - "stopped", - function() - end - ) - - ret.settigns_form.password:connect_signal( - "submit", - function(text) - end - ) - - ret.settigns_form.password:connect_signal( - "stopped", - function() - end - ) + local connect_button = ret.widget:get_children_by_id("connect_button")[1] + connect_button:connect_signal("button::press", function() + ret:emit_signal("ap_form::connect", { + ssid = args.ssid, + password = settigns_form.password:get_text(), + auto_connect = ret.widget:get_children_by_id("checkbox")[1].checked + }) + print("Connect to " .. args.ssid:get_text(), "\nPassword: " .. settigns_form.password:get_text(), + "\nAuto connect: " .. tostring(ret.widget:get_children_by_id("checkbox")[1].checked)) + end) + Hover_signal(connect_button) return ret end diff --git a/awesome/src/modules/network_controller/init.lua b/awesome/src/modules/network_controller/init.lua index 175806c..7732c4e 100644 --- a/awesome/src/modules/network_controller/init.lua +++ b/awesome/src/modules/network_controller/init.lua @@ -14,23 +14,23 @@ local gcolor = require("gears").color local gears = require("gears") local lgi = require("lgi") local wibox = require("wibox") - local NM = require("lgi").NM +local base = require("wibox.widget.base") local rubato = require("src.lib.rubato") 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 capi = { awesome = awesome, } local network = { mt = {} } -network.access_points = { layout = wibox.layout.fixed.vertical } - network.NMState = { UNKNOWN = 0, ASLEEP = 10, @@ -81,37 +81,45 @@ local function flags_to_security(flags, wpa_flags, rsn_flags) return (str:gsub("^%s", "")) end -local function get_wifi_proxy(self) - local devices = self._private.client_proxy:GetDevices() - for _, device in ipairs(devices) do - local device_proxy = dbus_proxy.Proxy:new { +local function generate_uuid() + return string.gsub('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', '[xy]', function(c) + local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) + 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, name = "org.freedesktop.NetworkManager", interface = "org.freedesktop.NetworkManager.Device", - path = device + path = path } - if device_proxy.DeviceType == network.DeviceType.WIFI then - self._private.device_proxy = device_proxy - self._private.wifi_proxy = dbus_proxy.Proxy:new { + if NetworkManagerDevice.DeviceType == network.DeviceType.WIFI then + self._private.NetworkManagerDevice = NetworkManagerDevice + self._private.NetworkManagerDeviceWireless = dbus_proxy.Proxy:new { bus = dbus_proxy.Bus.SYSTEM, name = "org.freedesktop.NetworkManager", interface = "org.freedesktop.NetworkManager.Device.Wireless", - path = device + path = path } - self._private.device_proxy:connect_signal(function(proxy, new_state, old_state, reason) - local active_access_point_proxy = dbus_proxy.Proxy:new { + self._private.NetworkManagerDevice:connect_signal(function(proxy, new_state, old_state, reason) + local NetworkManagerAccessPoint = 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) + self:emit_signal(tostring(NetworkManagerAccessPoint.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("NM::AccessPointConnected", ssid, active_access_point_proxy.Strength) + local ssid = NM.utils_ssid_to_utf8(NetworkManagerAccessPoint.Ssid) + self:emit_signal("NM::AccessPointConnected", ssid, NetworkManagerAccessPoint.Strength) + print("AP Connected: ", ssid, NetworkManagerAccessPoint.Strength) end end, "StateChanged") end @@ -119,8 +127,7 @@ local function get_wifi_proxy(self) end function network.device_state_to_string(state) - local device_state_to_string = - { + local device_state_to_string = { [0] = "Unknown", [10] = "Unmanaged", [20] = "Unavailable", @@ -139,63 +146,30 @@ function network.device_state_to_string(state) return device_state_to_string[state] end -local function get_access_point_connections(self, ssid) - local connection_proxies = {} +function network:get_access_point_connections(ssid) + local cn = {} - local connections = self._private.settings_proxy:ListConnections() + local connections = self._private.NetworkManagerSettings:ListConnections() 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, name = "org.freedesktop.NetworkManager", interface = "org.freedesktop.NetworkManager.Settings.Connection", path = connection_path } - if connection_proxy.Filename:find(ssid) then - table.insert(connection_proxies, connection_proxy) + if NetworkManagerSettingsConnection.Filename:find(ssid) then + table.insert(cn, NetworkManagerSettingsConnection) end end - return connection_proxies + return cn 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(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"), - } - +function network:create_profile(ap, password, auto_connect) local s_wsec = {} 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["auth-alg"] = lgi.GLib.Variant("s", "open") --s_wsec["psk"] = lgi.GLib.Variant("s", helpers.string.trim(password)) @@ -207,108 +181,85 @@ local function create_profile(ap, password, auto_connect) end return { - ["connection"] = s_con, - ["ipv4"] = s_ip4, - ["ipv6"] = s_ip6, - ["802-11-wireless"] = s_wifi, + ["connection"] = { + -- ["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), + }, + ["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 } end +---Scan for access points and create a widget for each one. 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) - if failure ~= nil then - self.access_points = { layout = wibox.layout.fixed.vertical } - self:emit_signal("NM::AccessPointsFound", self.access_points[1].ssid) - self:emit_signal("NM::ScanFailed", tostring(failure)) + self._private.NetworkManagerDeviceWireless:RequestScanAsync(function(proxy, context, success, failure) + if failure then + -- Send an error notification + print("AP Scan failed: ", failure) return 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 = {} - if (not access_point) or (#access_points == 0) then - 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 { + -- Create a new proxy for every ap + local NetworkManagerAccessPoint = dbus_proxy.Proxy:new { bus = dbus_proxy.Bus.SYSTEM, name = "org.freedesktop.NetworkManager", interface = "org.freedesktop.NetworkManager.AccessPoint", path = ap } - - if access_point_proxy.Ssid then - local appSsid = access_point_proxy.Ssid or "" - 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 + --[[ for _, ap2 in ipairs(ap_list.children) do + if ap2.NetworkManagerAccessPoint.HwAddress:match(ap.HwAddress or "") then + goto continue end + end ]] - table.insert(self._private.access_points, { - ssid = ssid, - 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 - }) + 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 - 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 + table.sort(ap_list, function(a, b) + return a.NetworkManagerAccessPoint.Strength > b.NetworkManagerAccessPoint.Strength end) - - self:emit_signal("NM::AccessPointsFound", self.access_points[1].ssid) + print("AP_Anzahl: ", #ap_list.children) end, { call_id = "my-id" }, {}) end -function network:toggle() - self.container.visible = not self.container.visible -end - function network:is_ap_active(ap) - print(self._private.wifi_proxy.ActiveAccessPoint) return ap.path == self._private.wifi_proxy.ActiveAccessPoint end function network:disconnect_ap() - self._private.client_proxy:DeactivateConnection(self._private.device_proxy.ActiveConnection) + self._private.NetworkManager:DeactivateConnection(self._private.NetworkManagerDevice.ActiveConnection) end function network:connect_ap(ap, pw, auto_connect) - local connections = get_access_point_connections(self, ap.ssid) - local profile = create_profile(ap, pw, auto_connect) + local connections = self:get_access_point_connections(ap.ssid) + local profile = self:create_profile(ap, pw, auto_connect) 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 self:emit_signal("NM::AccessPointFailed", tostring(failure)) 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 }) else 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 self:emit_signal("NM::AccessPointFailed", tostring(failure)) return @@ -337,89 +288,21 @@ function network:toggle_access_point(ap, password, auto_connect) end end -function network:toggle_wireless() - local enable = not self._private.client_proxy.WirelessEnabled +---Toggles networking on or off +function network:toggle_wifi() + local enable = not self._private.NetworkManager.WirelessEnabled if enable then - self._private.client_proxy:Enable(true) + self._private.NetworkManager.Enable(true) end - self._private.client_proxy:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable)) - - return enable + self._private.NetworkManager:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable)) + self._private.NetworkManager.WirelessEnabled = { signature = "b", value = enable } end function network.new(args) args = args or {} - local ret = gobject {} - - 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 { + local ret = base.make_widget_from_value(wibox.widget { { { { @@ -488,6 +371,17 @@ function network.new(args) }, { { -- 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 { { @@ -512,31 +406,6 @@ function network.new(args) widget = wibox.container.background, 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 }, widget = wibox.container.margin, @@ -562,54 +431,82 @@ function network.new(args) width = dpi(400), strategy = "exact", 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( - gtable.join( - awful.button( - {}, - 1, - nil, - function() - ret:scan_access_points() - end - ) - ) - ) + ret._private.NetworkManagerProperties = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.DBus.Properties", + path = "/org/freedesktop/NetworkManager", + } - Hover_signal(refresh_button) + ret._private.NetworkManagerProperties:connect_signal(function(_, properties, data) + if data.WirelessEnables ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then + ret._private.WirelessEnabled = data.WirelessEnabled - local airplane_button = network_widget:get_children_by_id("airplane")[1] + ret:emit_signal("NetworkManager::status", ret._private.WirelessEnabled) + print(ret._private.WirelessEnabled) - 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) + if data.WirelessEnabled then + gtimer { + timeout = 5, + autostart = true, + call_now = false, + single_shot = true, + callback = function() + ret:scan_access_points() end - ret:scan_access_points() - end - ) - ) - ) + } + end + end + end, "PropertiesChanged") - Hover_signal(airplane_button) + ret:get_wifi_proxy() - local wifi_margin = network_widget:get_children_by_id("wifi_margin")[1] - local wifi_list = network_widget:get_children_by_id("wifi_list")[1] - local wifi = network_widget:get_children_by_id("wifi")[1].center + 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) + + --#endregion + + --#region Dropdown logic + local wifi_margin = ret:get_children_by_id("wifi_margin")[1] + 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 { duration = 0.2, @@ -620,64 +517,47 @@ function network.new(args) end } - wifi_margin:buttons( - gtable.join( - awful.button( - {}, - 1, - nil, - function() - if wifi_list.forced_height == 0 then - local size = (#ret.access_points * 49) + 1 - - size = size > 210 and 210 or size - - rubato_timer.target = dpi(size) - wifi_margin.wifi_bg.shape = function(cr, width, height) - gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4)) - end - wifi.icon:set_image(gcolor.recolor_image(icondir .. "menu-up.svg", - Theme_config.network_manager.wifi_icon_color)) - else - rubato_timer.target = 0 - wifi_margin.wifi_bg.shape = function(cr, width, height) - gshape.partially_rounded_rect(cr, width, height, true, true, true, true, dpi(4)) - end - wifi.icon:set_image(gcolor.recolor_image(icondir .. "menu-down.svg", - Theme_config.network_manager.wifi_icon_color)) + wifi_margin:buttons(gtable.join( + awful.button({}, 1, nil, + function() + if wifi_list.forced_height == 0 then + 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 + + rubato_timer.target = dpi(size) + wifi_margin.wifi_bg.shape = function(cr, width, height) + gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4)) + end + wifi.icon:set_image(gcolor.recolor_image(icondir .. "menu-up.svg", + Theme_config.network_manager.wifi_icon_color)) + else + rubato_timer.target = 0 + wifi_margin.wifi_bg.shape = function(cr, width, height) + gshape.partially_rounded_rect(cr, width, height, true, true, true, true, dpi(4)) + end + wifi.icon:set_image(gcolor.recolor_image(icondir .. "menu-down.svg", + Theme_config.network_manager.wifi_icon_color)) end - ) + end ) - ) + )) + --#endregion - ret.widget = awful.popup { - widget = network_widget, - bg = Theme_config.network_manager.bg, - screen = args.screen, - 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 - } + local refresh_button = ret:get_children_by_id("refresh")[1] + refresh_button:buttons(gtable.join( + awful.button({}, 1, nil, + function() + ret:scan_access_points() + end + ) + )) + Hover_signal(refresh_button) - capi.awesome.connect_signal("NM::toggle_container", function() - ret.widget.visible = not ret.widget.visible - ret:scan_access_points() - end) - - capi.awesome.connect_signal("NM::toggle_wifi", function() - 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) + return ret end function network.mt:__call(...) diff --git a/awesome/src/modules/notification-center/init.lua b/awesome/src/modules/notification-center/init.lua index aea936c..96cae16 100644 --- a/awesome/src/modules/notification-center/init.lua +++ b/awesome/src/modules/notification-center/init.lua @@ -7,8 +7,7 @@ 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 dnd_widget = require("awful.widget.toggle_widget") local capi = { awesome = awesome, @@ -19,6 +18,17 @@ local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/no 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 local activation_area = awful.popup { @@ -90,121 +100,6 @@ return function(s) 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 { { { @@ -288,7 +183,12 @@ return function(s) widget = wibox.container.constraint }, { - dnd, + { + dnd, + widget = wibox.container.place, + valign = "center", + halign = "center" + }, nil, clear_all_widget, layout = wibox.layout.align.horizontal diff --git a/awesome/src/modules/powermenu.lua b/awesome/src/modules/powermenu.lua deleted file mode 100644 index c39e862..0000000 --- a/awesome/src/modules/powermenu.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/titlebar.lua b/awesome/src/modules/titlebar.lua deleted file mode 100644 index 68a1b7e..0000000 --- a/awesome/src/modules/titlebar.lua +++ /dev/null @@ -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 -) diff --git a/awesome/src/modules/volume_controller.lua b/awesome/src/modules/volume_controller.lua deleted file mode 100644 index 8569e3e..0000000 --- a/awesome/src/modules/volume_controller.lua +++ /dev/null @@ -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 diff --git a/awesome/src/modules/volume_osd.lua b/awesome/src/modules/volume_osd.lua deleted file mode 100644 index fe32aff..0000000 --- a/awesome/src/modules/volume_osd.lua +++ /dev/null @@ -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 diff --git a/awesome/src/theme/theme_config.lua b/awesome/src/theme/theme_config.lua index b395b6c..f443f74 100644 --- a/awesome/src/theme/theme_config.lua +++ b/awesome/src/theme/theme_config.lua @@ -59,6 +59,12 @@ Theme_config.date = { fg = color["Grey900"] } +Theme_config.dnd = { + bg = color["Grey900"], + disabled = color["Grey800"], + border_disabled = color["Grey800"], +} + Theme_config.gpu_usage = { bg = color["Green200"], fg = color["Grey900"] @@ -250,6 +256,19 @@ Theme_config.network_manager = { icon_fg = color["Grey900"], border_color = color["Grey800"], 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) gears.shape.rounded_rect(cr, width, height, dpi(8)) end @@ -294,6 +313,8 @@ Theme_config.notification_center = { border_color = color["Grey800"], border_width = dpi(4), spacing_color = color["Grey800"], + dnd_color = color["Purple200"], + dnd_fg = color["Pink200"], -- Clear all button clear_all_button = { @@ -301,16 +322,6 @@ Theme_config.notification_center = { 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 = { timer_fg = color["Teal200"], @@ -431,7 +442,7 @@ Theme_config.bluetooth_controller = { refresh_icon_color = color["Grey900"], refresh_bg = color["LightBlue200"], power_icon_color = color["Grey900"], - power_bg = color["Blue200"] + power_bg = color["Blue200"], } Theme_config.brightness_osd = { diff --git a/awesome/src/theme/user_config.lua b/awesome/src/theme/user_config.lua index dd7d56d..a21871c 100644 --- a/awesome/src/theme/user_config.lua +++ b/awesome/src/theme/user_config.lua @@ -17,7 +17,7 @@ User_config = { Flatpak application: flatpak run com.example.App ]] -- autostart = { - "picom --experimental-backends", + "picom", "xfce4-power-manager", "light-locker --lock-on-suspend --lock-on-lid &", "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1", diff --git a/awesome/src/tools/helpers/audio.lua b/awesome/src/tools/helpers/audio.lua index 834ca6b..d59428e 100644 --- a/awesome/src/tools/helpers/audio.lua +++ b/awesome/src/tools/helpers/audio.lua @@ -1,18 +1,13 @@ local awful = require("awful") -local pulse = require("pulseaudio_dbus") local capi = { awesome = awesome, } 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) if state == 4 then print("Connection is ready") diff --git a/awesome/src/tools/helpers/init.lua b/awesome/src/tools/helpers/init.lua deleted file mode 100644 index a3b2b71..0000000 --- a/awesome/src/tools/helpers/init.lua +++ /dev/null @@ -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") diff --git a/awesome/src/tools/helpers/network_manager.lua b/awesome/src/tools/helpers/network_manager.lua deleted file mode 100644 index 3ec13b2..0000000 --- a/awesome/src/tools/helpers/network_manager.lua +++ /dev/null @@ -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 diff --git a/awesome/src/widgets/audio.lua b/awesome/src/widgets/audio.lua index 6bf7680..dda890f 100644 --- a/awesome/src/widgets/audio.lua +++ b/awesome/src/widgets/audio.lua @@ -7,6 +7,8 @@ local dpi = require("beautiful").xresources.apply_dpi local gears = require("gears") local wibox = require("wibox") +require("src.tools.helpers.audio") + local capi = { awesome = awesome, } diff --git a/awesome/src/widgets/bluetooth.lua b/awesome/src/widgets/bluetooth.lua index 2bc0c16..ae65ddf 100644 --- a/awesome/src/widgets/bluetooth.lua +++ b/awesome/src/widgets/bluetooth.lua @@ -17,6 +17,22 @@ local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/bl -- Returns the bluetooth widget 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 { { { @@ -43,24 +59,23 @@ return function(s) end, 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(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( "button::press", function(_, _, _, key) 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 capi.awesome.emit_signal("toggle_bluetooth") end diff --git a/awesome/src/widgets/cpu_info.lua b/awesome/src/widgets/cpu_info.lua index 9a9f2f5..7638d4a 100644 --- a/awesome/src/widgets/cpu_info.lua +++ b/awesome/src/widgets/cpu_info.lua @@ -11,6 +11,10 @@ local wibox = require("wibox") local color = require("src.lib.color") 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 = { awesome = awesome, } diff --git a/awesome/src/widgets/date.lua b/awesome/src/widgets/date.lua index 0665d87..a6265ea 100644 --- a/awesome/src/widgets/date.lua +++ b/awesome/src/widgets/date.lua @@ -75,7 +75,7 @@ return function(s) awful.button({}, 1, function() local geo = mouse.current_wibox:geometry() 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 end) ) diff --git a/awesome/src/widgets/gpu_info.lua b/awesome/src/widgets/gpu_info.lua index 4bb9cf0..5fdfddc 100644 --- a/awesome/src/widgets/gpu_info.lua +++ b/awesome/src/widgets/gpu_info.lua @@ -11,6 +11,9 @@ local wibox = require("wibox") local color = require("src.lib.color") local rubato = require("src.lib.rubato") +require("src.tools.helpers.gpu_temp") +require("src.tools.helpers.gpu_usage") + local capi = { awesome = awesome, } diff --git a/awesome/src/widgets/kblayout.lua b/awesome/src/widgets/kblayout.lua index c44b404..60de3a2 100644 --- a/awesome/src/widgets/kblayout.lua +++ b/awesome/src/widgets/kblayout.lua @@ -17,6 +17,7 @@ local capi = { local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/kblayout/" return function(s) + local kblayout_widget = wibox.widget { { { diff --git a/awesome/src/widgets/network.lua b/awesome/src/widgets/network.lua index 0e702ad..657ead9 100644 --- a/awesome/src/widgets/network.lua +++ b/awesome/src/widgets/network.lua @@ -24,8 +24,10 @@ local interfaces = { local network_mode = nil +local nm_widget = require("src.modules.network_controller.init") + -- Returns the network widget -return function() +return function(s) local startup = true local reconnect_startup = true local wifi_strength @@ -331,6 +333,21 @@ return function() 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 Hover_signal(network_widget) @@ -341,7 +358,7 @@ return function() 1, nil, function() - capi.awesome.emit_signal("NM::toggle_container") + network_container.visible = not network_container.visible end ), awful.button( diff --git a/awesome/src/widgets/ram_info.lua b/awesome/src/widgets/ram_info.lua index a7e8b16..2c7dcc2 100644 --- a/awesome/src/widgets/ram_info.lua +++ b/awesome/src/widgets/ram_info.lua @@ -9,6 +9,8 @@ local gears = require("gears") local watch = awful.widget.watch local wibox = require("wibox") +require("src.tools.helpers.ram") + local capi = { awesome = awesome, } diff --git a/awesome/todo.md b/awesome/todo.md new file mode 100644 index 0000000..85658b3 --- /dev/null +++ b/awesome/todo.md @@ -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 diff --git a/awesome/wibox/widget/inputbox.lua b/awesome/wibox/widget/inputbox.lua new file mode 100644 index 0000000..5c4af4b --- /dev/null +++ b/awesome/wibox/widget/inputbox.lua @@ -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 "" .. placeholder_text .. "" + 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 "" .. text_start_highlight .. "" .. + "" .. + text_highlighted .. + "" .. "" .. text_end_highlight .. "" + else + return "" .. text_start .. "" .. + "" .. + char .. "" .. "" .. text_end .. spacer .. "" + 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 diff --git a/awesome/wibox/widget/inputtextbox.lua b/awesome/wibox/widget/inputtextbox.lua deleted file mode 100644 index 32e29fd..0000000 --- a/awesome/wibox/widget/inputtextbox.lua +++ /dev/null @@ -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