From 0e3aafcff57d5ddbf59c8a2f1c60ebf9f34e4b72 Mon Sep 17 00:00:00 2001 From: Rene Kievits Date: Wed, 26 Apr 2023 00:28:06 +0200 Subject: [PATCH] Some fixes --- awesome/rc.lua | 17 +- awesome/src/bindings/global_keys.lua | 44 +- awesome/src/core/error_handling.lua | 73 +- awesome/src/core/notifications.lua | 679 +++++++++--------- awesome/src/core/rules.lua | 180 ++--- awesome/src/core/setup.lua | 12 +- awesome/src/core/signals.lua | 117 +-- awesome/src/core/titlebar.lua | 4 +- awesome/src/lib/overflow_widget/overflow.lua | 75 +- awesome/src/modules/app_launcher/init.lua | 106 ++- awesome/src/modules/bluetooth/device.lua | 2 +- awesome/src/modules/bluetooth/init.lua | 154 ++-- awesome/src/modules/calendar/init.lua | 6 +- awesome/src/modules/context_menu/init.lua | 2 +- awesome/src/modules/crylia_bar/dock.lua | 12 +- awesome/src/modules/desktop/desktop.lua | 2 +- awesome/src/modules/init.lua | 16 +- .../network_controller/access_point.lua | 4 +- .../modules/network_controller/ap_form.lua | 2 +- .../widgets/notification_list.lua | 39 +- awesome/src/modules/powermenu/init.lua | 204 +++--- awesome/src/modules/window_switcher/init.lua | 216 +++--- .../window_switcher/window_elements.lua | 252 ------- awesome/src/theme/init.lua | 229 +++--- awesome/src/tools/parse_ical.lua | 180 +++-- awesome/src/widgets/date.lua | 1 + 26 files changed, 1240 insertions(+), 1388 deletions(-) delete mode 100644 awesome/src/modules/window_switcher/window_elements.lua diff --git a/awesome/rc.lua b/awesome/rc.lua index 6e10db9..f18e4c5 100644 --- a/awesome/rc.lua +++ b/awesome/rc.lua @@ -11,7 +11,7 @@ ╰─────────────────────────────────────────────────────────────────╯ ]] ---#region prints +--#region s io.stdout:write([[ ]] .. '\n\27[32m' .. [[╭─────────────────────────────────────────────────────────────────╮ ]] .. '\27[32m' .. [[│]] .. '\27[1;36m' .. [[ ______ ___ ________ ]] .. '\27[32m' .. [[│ @@ -35,16 +35,13 @@ io.stderr:write([[ ]] .. '\27[0m\n') --#endregion -require('src.core.error_handling') -require('src.theme') -require('src.core.signals') -require('src.core.notifications') -require('src.core.rules') +require('src.core.error_handling') {} +require('src.theme') {} +require('src.core.signals') {} +require('src.core.notifications') {} +require('src.core.rules') {} require('src.bindings.global_buttons') require('src.bindings.bind_to_tags') -require('src.modules')() +require('src.modules') {} require('src.tools.auto_starter') {} - --require('src.core.setup')() - ---require('src.tools.helpers.pulseaudio')() diff --git a/awesome/src/bindings/global_keys.lua b/awesome/src/bindings/global_keys.lua index 6af383c..f9d3461 100644 --- a/awesome/src/bindings/global_keys.lua +++ b/awesome/src/bindings/global_keys.lua @@ -1,3 +1,6 @@ +local table = table +local ipairs = ipairs + -- Awesome libs local akeygrabber = require('awful.keygrabber') local akey = require('awful.key') @@ -15,8 +18,8 @@ local config = require('src.tools.config') local audio_helper = require('src.tools.helpers.audio') local backlight_helper = require('src.tools.helpers.backlight') local beautiful = require('beautiful') -local powermenu = require('src.modules.powermenu') local kb_helper = require('src.tools.helpers.kb_helper') +local window_switcher = require('src.modules.window_switcher') local capi = { awesome = awesome, @@ -26,13 +29,26 @@ local capi = { local modkey = beautiful.user_config['modkey'] + +local awful = require('awful') +local f = 1 akeygrabber { keybindings = { akey { modifiers = { 'Mod1' }, key = 'Tab', on_press = function() - capi.awesome.emit_signal('window_switcher::select_next') + local clients = awful.screen.focused():get_all_clients() + if f == #clients then + f = 1 + end + f = f + 1 + clients[f].minimized = false + if not clients[f]:isvisible() and clients[f].first_tag then + clients[f].first_tag:view_only() + end + clients[f]:emit_signal('request::activate') + clients[f]:raise() end, }, }, @@ -47,11 +63,13 @@ akeygrabber { stop_key = 'Mod1', stop_event = 'release', start_callback = function() - capi.awesome.emit_signal('toggle_window_switcher') + aclient.focus.history.disable_tracking() + window_switcher.popup.visible = true end, stop_callback = function() - capi.awesome.emit_signal('window_switcher::raise') - capi.awesome.emit_signal('toggle_window_switcher') + aclient.focus.history.enable_tracking() + window_switcher.popup.visible = false + collectgarbage('collect') end, export_keybindings = true, } @@ -63,18 +81,6 @@ return gtable.join( hotkeys_popup.show_help, { description = 'Cheat sheet', group = 'Awesome' } ), - --[[ akey( - { modkey }, - '#113', - atag.viewprev, - { description = 'View previous tag', group = 'Tag' } - ), - akey( - { modkey }, - '#114', - atag.viewnext, - { description = 'View next tag', group = 'Tag' } - ), ]] akey( { modkey }, '#66', @@ -201,7 +207,7 @@ return gtable.join( { modkey }, '#40', function() - capi.awesome.emit_signal('application_launcher::show') + require('src.modules.app_launcher'):toggle(capi.mouse.screen) end, { descripton = 'Application launcher', group = 'Application' } ), @@ -217,7 +223,7 @@ return gtable.join( { modkey, 'Shift' }, '#26', function() - powermenu:toggle() + require('src.modules.powermenu'):toggle() end, { descripton = 'Session options', group = 'System' } ), diff --git a/awesome/src/core/error_handling.lua b/awesome/src/core/error_handling.lua index dca877a..460143f 100644 --- a/awesome/src/core/error_handling.lua +++ b/awesome/src/core/error_handling.lua @@ -1,40 +1,53 @@ ----------------------------------------------------------------- --- This class is to output an error if you fuck up the config -- ----------------------------------------------------------------- +local setmetatable = setmetatable +local tostring = tostring + -- Awesome Libs -local naughty = require('naughty') local gfilesystem = require('gears.filesystem') +local gtimer = require('gears.timer') +local naughty = require('naughty') local capi = { awesome = awesome, } -if capi.awesome.startup_errors then - naughty.notify { preset = naughty.config.presets.critical, - title = 'Oops, there were errors during startup!', - text = capi.awesome.startup_errors, - gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg', - } -end - -do - local in_error = false - capi.awesome.connect_signal( - 'debug::error', - function(err) - if in_error then - return +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function() + if capi.awesome.startup_errors then + naughty.notification { + preset = naughty.config.presets.critical, + title = 'ERROR!', + app_name = 'System Notification', + message = capi.awesome.startup_errors, + icon = gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg', + } end - in_error = true - naughty.notification { - preset = naughty.config.presets.critical, - title = 'ERROR', - app_name = 'System Notification', - message = tostring(err), - icon = gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg', - } - in_error = false - end - ) + local in_error = false + capi.awesome.connect_signal('debug::error', function(err) + if in_error then return end + in_error = true + + naughty.notification { + preset = naughty.config.presets.critical, + title = 'ERROR', + app_name = 'System Notification', + message = tostring(err), + icon = gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg', + } + + -- Make sure an error is only put every 3 seconds to prevent spam + gtimer { + timeout = 3, + autostart = true, + single_shot = true, + callback = function() + in_error = false + end, + } + end) + end, + }) end +return instance diff --git a/awesome/src/core/notifications.lua b/awesome/src/core/notifications.lua index f42ea77..da170b0 100644 --- a/awesome/src/core/notifications.lua +++ b/awesome/src/core/notifications.lua @@ -1,19 +1,20 @@ -------------------------------- --- The Notification defaults -- -------------------------------- --- Awesome Libs +local setmetatable = setmetatable +-- Awesome Libs +local abutton = require('awful.button') local aspawn = require('awful.spawn') local beautiful = require('beautiful') -local dpi = require('beautiful').xresources.apply_dpi +local dpi = beautiful.xresources.apply_dpi local gcolor = require('gears.color') local gfilesystem = require('gears.filesystem') +local gtable = require('gears.table') local naughty = require('naughty') local wibox = require('wibox') -local abutton = require('awful.button') -local gtable = require('gears.table') +-- Third party libs local rubato = require('src.lib.rubato') + +-- Local Libs local hover = require('src.tools.hover') local capi = { @@ -21,382 +22,366 @@ local capi = { screen = screen, } -local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/notifications/' +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function() + local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/notifications/' -naughty.config.defaults.ontop = true -naughty.config.defaults.icon_size = dpi(80) -naughty.config.defaults.timeout = 5 -naughty.config.defaults.title = 'System Notification' -naughty.config.defaults.margin = dpi(10) -naughty.config.defaults.position = 'bottom_right' -naughty.config.defaults.border_width = dpi(2) -naughty.config.defaults.border_color = beautiful.colorscheme.border_color -naughty.config.defaults.spacing = dpi(10) + naughty.config.defaults.border_color = beautiful.colorscheme.border_color + naughty.config.defaults.border_width = dpi(2) + naughty.config.defaults.icon_size = dpi(64) + naughty.config.defaults.margin = dpi(10) + naughty.config.defaults.ontop = true + naughty.config.defaults.position = 'bottom_right' + naughty.config.defaults.spacing = dpi(10) + naughty.config.defaults.timeout = 5 + naughty.config.defaults.title = 'System Notification' -naughty.connect_signal('request::display', function(n) - if beautiful.user_config.dnd then - n:destroy() - else - if not n.icon then n.icon = gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg' end - if not n.app_name then n.app_name = 'System' end - if not n.title then n.title = 'System Notification' end - if not n.message then n.message = 'No message provided' end + naughty.connect_signal('request::display', function(n) + if beautiful.user_config.dnd then + n:destroy() + else + n.app_name = n.app_name or 'System' + n.icon = n.icon or gfilesystem.get_configuration_dir() .. 'src/assets/CT.svg' + n.message = n.message or 'No message provided' + n.title = n.title or 'System Notification' - local color = beautiful.colorscheme.bg_blue - if n.urgency == 'critical' then - color = beautiful.colorscheme.bg_red - end + local color = beautiful.colorscheme.bg_blue + if n.urgency == 'critical' then + color = beautiful.colorscheme.bg_red + end - if n.app_name == 'Spotify' then - n.actions = { - naughty.action { - program = 'Spotify', - id = 'skip-prev', - name = 'Previous', - position = 1, - }, naughty.action { - program = 'Spotify', - id = 'play-pause', - name = 'Play/Pause', - position = 2, - }, naughty.action { - program = 'Spotify', - id = 'skip-next', - name = 'Next', - position = 3, - }, - } - n.resident = true - end + if n.app_name == 'Spotify' then + n.actions = { + naughty.action { + program = 'Spotify', + id = 'skip-prev', + name = 'Previous', + position = 1, + }, naughty.action { + program = 'Spotify', + id = 'play-pause', + name = 'Play/Pause', + position = 2, + }, naughty.action { + program = 'Spotify', + id = 'skip-next', + name = 'Next', + position = 3, + }, + } + n.resident = true + end - if n.category == 'device.added' or n.category == 'network.connected' then - aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/device-added.oga') - elseif n.category == 'device.removed' or n.category == 'network.disconnected' then - aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/device-removed.oga') - elseif n.category == 'device.error' or n.category == 'im.error' or n.category == 'network.error' or n.category == - 'transfer.error' then - aspawn('ogg123 ogg123 /usr/share/sounds/Pop/stereo/alert/battery-low.oga') - elseif n.category == 'email.arrived' then - aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/message-new-email.oga') - end + if n.category == 'device.added' or n.category == 'network.connected' then + aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/device-added.oga') + elseif n.category == 'device.removed' or n.category == 'network.disconnected' then + aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/device-removed.oga') + elseif n.category == 'device.error' or n.category == 'im.error' or n.category == 'network.error' or n.category == + 'transfer.error' then + aspawn('ogg123 ogg123 /usr/share/sounds/Pop/stereo/alert/battery-low.oga') + elseif n.category == 'email.arrived' then + aspawn('ogg123 /usr/share/sounds/Pop/stereo/notification/message-new-email.oga') + end - local action_template = wibox.widget { - notification = n, - base_layout = wibox.widget { - spacing = dpi(90), - layout = wibox.layout.flex.horizontal, - }, - widget_template = { - { - { - widget = wibox.widget.textbox, - id = 'text_role', - valign = 'center', - halign = 'center', - font = 'JetBrainsMono Nerd Font, Bold 16', - }, - widget = wibox.container.constraint, - height = dpi(35), - strategy = 'exact', - }, - id = 'background_role', - widget = wibox.container.background, - bg = color, - fg = beautiful.colorscheme.bg, - shape = beautiful.shape[8], - }, - style = { - underline_normal = false, - underline_selected = false, - shape_normal = beautiful.shape[8], - --Don't remove or it will break - bg_normal = color, - bg_selected = color, - fg_normal = beautiful.colorscheme.bg, - fg_selected = beautiful.colorscheme.bg, - }, - widget = naughty.list.actions, - } + local action_template = wibox.widget { + notification = n, + base_layout = wibox.widget { + spacing = dpi(90), + layout = wibox.layout.flex.horizontal, + }, + widget_template = { + { + { + widget = wibox.widget.textbox, + id = 'text_role', + valign = 'center', + halign = 'center', + font = beautiful.user_config.font .. ' bold 16', + }, + widget = wibox.container.constraint, + height = dpi(35), + strategy = 'exact', + }, + id = 'background_role', + widget = wibox.container.background, + bg = color, + fg = beautiful.colorscheme.bg, + shape = beautiful.shape[8], + }, + style = { + underline_normal = false, + underline_selected = false, + shape_normal = beautiful.shape[8], + --Don't remove or it will break + bg_normal = color, + bg_selected = color, + fg_normal = beautiful.colorscheme.bg, + fg_selected = beautiful.colorscheme.bg, + }, + widget = naughty.list.actions, + } - -- Hack to get the action buttons to work even after update - for i = 1, #action_template._private.layout.children, 1 do - hover.bg_hover { widget = action_template._private.layout.children[i].children[1], overlay = 12, press_overlay = 24 } - end - if (#action_template._private.layout.children > 0) and action_template._private.notification[1].actions[1].program == 'Spotify' then - action_template._private.layout.children[1].children[1]:connect_signal('button::press', function() - aspawn('playerctl previous') - end) - action_template._private.layout.children[2].children[1]:connect_signal('button::press', function() - aspawn('playerctl play-pause') - end) - action_template._private.layout.children[3].children[1]:connect_signal('button::press', function() - aspawn('playerctl next') - end) - end + -- Hack to get the action buttons to work even after update + for i = 1, #action_template._private.layout.children, 1 do + hover.bg_hover { widget = action_template._private.layout.children[i].children[1], overlay = 12, press_overlay = 24 } + end + if (#action_template._private.layout.children > 0) and action_template._private.notification[1].actions[1].program == 'Spotify' then + action_template._private.layout.children[1].children[1]:connect_signal('button::press', function() + aspawn('playerctl previous') + end) + action_template._private.layout.children[2].children[1]:connect_signal('button::press', function() + aspawn('playerctl play-pause') + end) + action_template._private.layout.children[3].children[1]:connect_signal('button::press', function() + aspawn('playerctl next') + end) + end - local start_timer = n.timeout - if n.timeout == 0 then - start_timer = 5 - end + local start_timer = n.timeout + if n.timeout == 0 then + start_timer = 5 + end - local notification = wibox.template { - widget = wibox.widget { - { - { - { - { -- Title + local notification = wibox.template { + widget = wibox.widget { + { { { - { -- Icon + { -- Title { { - { + { -- Icon { - notification = n, - widget = naughty.widget.icon, - image = n.icon, - resize = true, + { + { + { + notification = n, + widget = naughty.widget.icon, + image = n.icon, + resize = true, + }, + widget = wibox.container.background, + shape = beautiful.shape[4], + }, + widget = wibox.container.place, + }, + widget = wibox.container.constraint, + strategy = 'exact', + width = dpi(20), + height = dpi(20), }, - widget = wibox.container.background, - shape = beautiful.shape[4], + { -- Title + { + notification = n, + widget = naughty.widget.title, + markup = [[]] .. (n.app_name or + 'Unknown App') .. [[ | ]] .. (n.title or 'System Notification') .. [[]], + halign = 'left', + valign = 'center', + }, + widget = wibox.container.constraint, + width = dpi(430), + height = dpi(35), + strategy = 'max', + }, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal, }, - widget = wibox.container.place, + widget = wibox.container.margin, + left = dpi(10), + }, + nil, + { + { + { -- Clock + widget = wibox.widget.textclock, + format = '%H:%M', + font = beautiful.user_config.font .. ' bold 16', + fg = beautiful.colorscheme.bg, + halign = 'right', + valign = 'center', + }, + { -- Close button + { + { + { + { + widget = wibox.widget.imagebox, + image = gcolor.recolor_image(icondir .. 'close.svg', beautiful.colorscheme.bg), + resize = true, + halign = 'center', + valign = 'center', + }, + start_angle = 4.71239, + thickness = dpi(2), + min_value = 0, + max_value = start_timer, + value = start_timer, + widget = wibox.container.arcchart, + id = 'arc', + }, + fg = beautiful.colorscheme.bg, + bg = color, + widget = wibox.container.background, + id = 'arc_bg', + }, + strategy = 'exact', + width = dpi(18), + height = dpi(18), + widget = wibox.container.constraint, + }, + left = dpi(5), + widget = wibox.container.margin, + }, + layout = wibox.layout.fixed.horizontal, + }, + right = dpi(5), + widget = wibox.container.margin, + }, + layout = wibox.layout.align.horizontal, + }, + widget = wibox.container.background, + bg = color, + fg = beautiful.colorscheme.bg, + shape = beautiful.shape[8], + }, + { -- Main body + { -- Image + { + { + notification = n, + image = n.icon, + valign = 'center', + halign = 'center', + upscale = true, + resize_strategy = 'scale', + widget = naughty.widget.icon, + }, + widget = wibox.container.background, + shape = beautiful.shape[10], }, widget = wibox.container.constraint, strategy = 'exact', - width = dpi(20), - height = dpi(20), + height = dpi(128), + width = dpi(128), }, - { -- Title + { { notification = n, - widget = naughty.widget.title, - markup = [[]] .. (n.app_name or - 'Unknown App') .. [[ | ]] .. (n.title or 'System Notification') .. [[]], + widget = naughty.widget.message, + font = beautiful.user_config.font .. ' bold 10', halign = 'left', valign = 'center', }, widget = wibox.container.constraint, - width = dpi(430), - height = dpi(35), - strategy = 'max', + strategy = 'exact', + height = dpi(128), }, - spacing = dpi(10), + spacing = dpi(15), layout = wibox.layout.fixed.horizontal, }, - widget = wibox.container.margin, - left = dpi(10), - }, - nil, - { - { - { -- Clock - widget = wibox.widget.textclock, - format = '%H:%M', - font = 'JetBrainsMono Nerd Font, Bold 16', - fg = beautiful.colorscheme.bg, - halign = 'right', - valign = 'center', + { -- Spacer + { + widget = wibox.container.background, + bg = beautiful.colorscheme.bg, }, - { -- Close button - { - { - { - { - widget = wibox.widget.imagebox, - image = gcolor.recolor_image(icondir .. 'close.svg', beautiful.colorscheme.bg), - resize = true, - halign = 'center', - valign = 'center', - }, - start_angle = 4.71239, - thickness = dpi(2), - min_value = 0, - max_value = start_timer, - value = start_timer, - widget = wibox.container.arcchart, - id = 'arc', - }, - fg = beautiful.colorscheme.bg, - bg = color, - widget = wibox.container.background, - id = 'arc_bg', - }, - strategy = 'exact', - width = dpi(18), - height = dpi(18), - widget = wibox.container.constraint, - }, - left = dpi(5), - widget = wibox.container.margin, - }, - layout = wibox.layout.fixed.horizontal, + widget = wibox.container.constraint, + strategy = 'exact', + height = dpi(2), }, - right = dpi(5), - widget = wibox.container.margin, + action_template, + spacing = dpi(15), + id = 'main_layout', + layout = wibox.layout.fixed.vertical, }, - layout = wibox.layout.align.horizontal, + widget = wibox.container.margin, + margins = dpi(15), }, - widget = wibox.container.background, - bg = color, - fg = beautiful.colorscheme.bg, + bg = beautiful.colorscheme.bg, + border_color = beautiful.colorscheme.border_color, + border_width = dpi(2), shape = beautiful.shape[8], + widget = wibox.container.background, }, - { -- Main body - { -- Image - { - { - notification = n, - image = n.icon, - valign = 'center', - halign = 'center', - upscale = true, - resize_strategy = 'scale', - widget = naughty.widget.icon, - }, - widget = wibox.container.background, - shape = beautiful.shape[10], - }, - widget = wibox.container.constraint, - strategy = 'exact', - height = dpi(128), - width = dpi(128), - }, - { - { - notification = n, - widget = naughty.widget.message, - font = 'JetBrainsMono Nerd Font, Regular 10', - halign = 'left', - valign = 'center', - }, - widget = wibox.container.constraint, - strategy = 'exact', - height = dpi(128), - }, - spacing = dpi(15), - layout = wibox.layout.fixed.horizontal, - }, - { -- Spacer - { - widget = wibox.container.background, - bg = beautiful.colorscheme.bg, - }, - widget = wibox.container.constraint, - strategy = 'exact', - height = dpi(2), - }, - action_template, - spacing = dpi(15), - id = 'main_layout', - layout = wibox.layout.fixed.vertical, + widget = wibox.container.constraint, + strategy = 'exact', + width = dpi(600), }, - widget = wibox.container.margin, - margins = dpi(15), - }, - bg = beautiful.colorscheme.bg, - border_color = beautiful.colorscheme.border_color, - border_width = dpi(2), - shape = beautiful.shape[8], - widget = wibox.container.background, - }, - widget = wibox.container.constraint, - strategy = 'exact', - width = dpi(600), - }, - } + } - if #action_template._private.layout.children < 1 then - notification:get_widget().children[1].children[1].children[1].children[3] = nil - end - - local arc_bg = notification:get_widget().children[1].children[1].children[1].children[1].children[1].children[2].children[1].children[2].children[1].children[1] - local arc = arc_bg.children[1] - - local timeout = n.timeout - - if timeout ~= 0 then - - local rubato_timer = rubato.timed { - duration = n.timeout, - pos = n.timeout, - easing = rubato.linear, - clamp_position = true, - subscribed = function(value) - arc.value = value - end, - } - - rubato_timer.target = 0 - - notification:get_widget():connect_signal('mouse::enter', function() - n.timeout = 99999 - rubato_timer.pause = true - end) - - notification:get_widget():connect_signal('mouse::leave', function() - n.timeout = rubato_timer.pos - rubato_timer.pause = false - rubato_timer.target = 0 - end) - end - - hover.bg_hover { widget = arc_bg } - - arc_bg:connect_signal('button::press', function() - n:destroy() - end) - - notification:get_widget():buttons { gtable.join( - abutton({}, 1, function() - for _, client in ipairs(capi.client.get()) do - if client.class:lower():match(n.app_name:lower()) then - if not client:isvisible() and client.first_tag then - client.first_tag:view_only() - end - client:emit_signal('request::activate') - client:raise() + if #action_template._private.layout.children < 1 then + notification:get_widget().children[1].children[1].children[1].children[3] = nil end - end - end), - abutton({}, 3, function() - n:destroy() - end) - ), } - local box = naughty.layout.box { - notification = n, - timeout = 5, - type = 'notification', - screen = capi.screen.primary, - widget_template = notification, - } - box.buttons = {} - n.buttons = {} - end -end) ---[[ -naughty.notification { - app_name = 'Spotify', - title = 'The Beatles - Here Comes The Sun', - message = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', - icon = '/home/crylia/Bilder/57384097.jpg', - timeout = 30, - actions = { - naughty.action { - name = 'amet', - position = 1, - text = 'Test', - }, - naughty.action { - name = 'Lorem ipsum dolor sit amet', - position = 2, - }, - naughty.action { - name = 'Lorem', - position = 3, - }, - }, -} - ]] + local arc_bg = notification:get_widget().children[1].children[1].children[1].children[1].children[1].children[2].children[1].children[2].children[1].children[1] + local arc = arc_bg.children[1] + + local timeout = n.timeout + + if timeout ~= 0 then + + local rubato_timer = rubato.timed { + duration = n.timeout, + pos = n.timeout, + easing = rubato.linear, + clamp_position = true, + subscribed = function(value) + arc.value = value + end, + } + + rubato_timer.target = 0 + + notification:get_widget():connect_signal('mouse::enter', function() + n.timeout = 99999 + rubato_timer.pause = true + end) + + notification:get_widget():connect_signal('mouse::leave', function() + n.timeout = rubato_timer.pos + rubato_timer.pause = false + rubato_timer.target = 0 + end) + end + + hover.bg_hover { widget = arc_bg } + + arc_bg:connect_signal('button::press', function() + n:destroy() + end) + + notification:get_widget():buttons { gtable.join( + abutton({}, 1, function() + for _, client in ipairs(capi.client.get()) do + if client.class:lower():match(n.app_name:lower()) 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), + abutton({}, 3, function() + n:destroy() + end) + ), } + + local box = naughty.layout.box { + notification = n, + timeout = 5, + type = 'notification', + screen = capi.screen.primary, + widget_template = notification, + } + box.buttons = {} + n.buttons = {} + end + end) + end, + }) +end +return instance diff --git a/awesome/src/core/rules.lua b/awesome/src/core/rules.lua index 51050e5..d8573f6 100644 --- a/awesome/src/core/rules.lua +++ b/awesome/src/core/rules.lua @@ -1,102 +1,112 @@ -------------------------------------------------------------------------------------------------- --- This class contains rules for float exceptions or special themeing for certain applications -- -------------------------------------------------------------------------------------------------- +local setmetatable = setmetatable +local ipairs = ipairs -- Awesome Libs local aclient = require('awful.client') local aplacement = require('awful.placement') local ascreen = require('awful.screen') local beautiful = require('beautiful') -local dpi = require('beautiful').xresources.apply_dpi +local dpi = beautiful.xresources.apply_dpi local ruled = require('ruled') local config = require('src.tools.config') -awesome.register_xproperty('_NET_WM_BYPASS_COMPOSITOR', 'boolean') +local capi = { + awesome = awesome, +} -ruled.client.connect_signal('request::rules', function() - ruled.client.append_rule { - rule = {}, - properties = { - border_width = dpi(2), - border_color = beautiful.colorscheme.border_color, - maximized = false, - maximized_horizontal = false, - maximized_vertical = false, - focus = aclient.focus.filter, - raise = true, - keys = require('src.bindings.client_keys'), - buttons = require('src.bindings.client_buttons'), - screen = ascreen.preferred, - placement = aplacement.under_mouse + aplacement.no_overlap + aplacement.no_offscreen + aplacement.centered, - }, - } +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function() + capi.awesome.register_xproperty('_NET_WM_BYPASS_COMPOSITOR', 'boolean') - ruled.client.append_rule { - rule_any = { - type = { - 'normal', - 'dialog', - }, - }, - properties = { - titlebars_enabled = true, - }, - } + ruled.client.connect_signal('request::rules', function() + ruled.client.append_rule { + rule = {}, + properties = { + border_width = dpi(2), + border_color = beautiful.colorscheme.border_color, + maximized = false, + maximized_horizontal = false, + maximized_vertical = false, + focus = aclient.focus.filter, + raise = true, + keys = require('src.bindings.client_keys'), + buttons = require('src.bindings.client_buttons'), + screen = ascreen.preferred, + placement = aplacement.under_mouse + aplacement.no_overlap + aplacement.no_offscreen + aplacement.centered, + }, + } - ruled.client.append_rule { - rule_any = { - class = { - 'proton-bridge', - '1password', - 'protonvpn', - 'Steam', - }, - }, - properties = { - minimized = true, - }, - } - ruled.client.append_rule { - rule_any = { - class = { - 'discord', - 'spotify', - }, - }, - properties = { - tag = '1', - screen = 2, - }, - } + ruled.client.append_rule { + rule_any = { + type = { + 'normal', + 'dialog', + }, + }, + properties = { + titlebars_enabled = true, + }, + } + + ruled.client.append_rule { + rule_any = { + class = { + 'proton-bridge', + '1password', + 'protonvpn', + 'Steam', + }, + }, + properties = { + minimized = true, + }, + } + ruled.client.append_rule { + rule_any = { + class = { + 'discord', + 'spotify', + }, + }, + properties = { + tag = '1', + screen = 2, + }, + } + + ruled.client.append_rule { + rule_any = { + class = { + 'steam_app_990080', + }, + }, + callback = function(c) + c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) + c:connect_signal('focus', function() + c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) + end) + c:connect_signal('raised', function() + c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) + end) + end, + } - ruled.client.append_rule { - rule_any = { - class = { - 'steam_app_990080', - }, - }, - callback = function(c) - c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) - c:connect_signal('focus', function() - c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) - end) - c:connect_signal('raised', function() - c:set_xproperty('_NET_WM_BYPASS_COMPOSITOR', true) end) + + + local data = config.read_json('/home/crylia/.config/awesome/src/config/floating.json') + for _, c in ipairs(data) do + ruled.client.append_rule { + rule = { class = c.WM_CLASS, instance = c.WM_INSTANCE }, + properties = { + floating = true, + }, + } + end end, - } - -end) - -do - local data = config.read_json('/home/crylia/.config/awesome/src/config/floating.json') - for _, c in ipairs(data) do - ruled.client.append_rule { - rule = { class = c.WM_CLASS, instance = c.WM_INSTANCE }, - properties = { - floating = true, - }, - } - end + }) end +return instance diff --git a/awesome/src/core/setup.lua b/awesome/src/core/setup.lua index 8c42797..40839d9 100644 --- a/awesome/src/core/setup.lua +++ b/awesome/src/core/setup.lua @@ -1,5 +1,8 @@ ---- A module to manage the first installation and setup the config without having to edit ---- the config files manually. +local setmetatable = setmetatable +local pairs = pairs +local ipairs = ipairs +local table = table +local math = math --Awesome Libs local abutton = require('awful.button') @@ -10,20 +13,19 @@ local atooltip = require('awful.tooltip') local beautiful = require('beautiful') local dpi = require('beautiful').xresources.apply_dpi local gcolor = require('gears.color') +local gfilesystem = require('gears.filesystem') local gtable = require('gears.table') local wibox = require('wibox') -local gfilesystem = require('gears.filesystem') -local inputwidget = require('src.modules.inputbox') --Own Libs local toggle_button = require('awful.widget.toggle_widget') +local inputwidget = require('src.modules.inputbox') local capi = { screen = screen, } local assets_dir = os.getenv('HOME') .. '/.config/awesome/src/assets/' -local font_dir = os.getenv('HOME') .. '/.config/awesome/src/assets/fonts/' local icon_dir = os.getenv('HOME') .. '/.config/awesome/src/assets/icons/setup/' local setup = { mt = {} } diff --git a/awesome/src/core/signals.lua b/awesome/src/core/signals.lua index 63cabcb..ef62e9a 100644 --- a/awesome/src/core/signals.lua +++ b/awesome/src/core/signals.lua @@ -1,11 +1,10 @@ ----@diagnostic disable: undefined-field +local setmetatable = setmetatable + -- Awesome Libs local aplacement = require('awful.placement') -local gtimer = require('gears.timer') local ascreen = require('awful.screen') -local ruled = require('ruled') - -local config = require('src.tools.config') +local beautiful = require('beautiful') +local gtimer = require('gears.timer') local capi = { awesome = awesome, @@ -15,60 +14,62 @@ local capi = { tag = tag, } -capi.screen.connect_signal('added', function() - capi.awesome.restart() -end) +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function() + capi.screen.connect_signal('added', function() + capi.awesome.restart() + end) -capi.screen.connect_signal('removed', function() - capi.awesome.restart() -end) + capi.screen.connect_signal('removed', function() + capi.awesome.restart() + end) -capi.client.connect_signal('manage', function(c) - if capi.awesome.startup and not c.size_hints.user_porition and not c.size_hints.program_position then - aplacement.no_offscreen(c) - end - if c.transient_for then - c.floating = true - end - if c.fullscreen then - gtimer.delayed_call(function() - if c.valid then - c:geometry(c.screen.geometry) + capi.client.connect_signal('manage', function(c) + if capi.awesome.startup and not c.size_hints.user_porition and not c.size_hints.program_position then + aplacement.no_offscreen(c) + end + if c.transient_for then + c.floating = true + end + if c.fullscreen then + gtimer.delayed_call(function() + if c.valid then + c:geometry(c.screen.geometry) + end + end) + end + end) + + capi.client.connect_signal('unmanage', function(c) + if #ascreen.focused().clients > 0 then + ascreen.focused().clients[1]:emit_signal('request::activate', 'mouse_enter', { + raise = true, + }) + end + collectgarbage('collect') + end) + + capi.tag.connect_signal('property::selected', function(c) + if #ascreen.focused().clients > 0 then + ascreen.focused().clients[1]:emit_signal('request::activate', 'mouse_enter', { + raise = true, + }) + end + end) + + -- Sloppy focus + if beautiful.user_config.sloppy_focus then + client.connect_signal('mouse::enter', function(c) + c:emit_signal( + 'request::activate', + 'mouse_enter', { + raise = true, + }) + end) end - end) - end - local data = config.read_json('/home/crylia/.config/awesome/src/config/floating.json') - for _, c in ipairs(data) do - ruled.client.append_rule { - rule = { class = c.WM_CLASS, instance = c.WM_INSTANCE }, - properties = { - floating = true, - }, - } - end -end) - -capi.client.connect_signal('unmanage', function(c) - if #ascreen.focused().clients > 0 then - ascreen.focused().clients[1]:emit_signal('request::activate', 'mouse_enter', { - raise = true, - }) - end -end) - -capi.tag.connect_signal('property::selected', function(c) - if #ascreen.focused().clients > 0 then - ascreen.focused().clients[1]:emit_signal('request::activate', 'mouse_enter', { - raise = true, - }) - end -end) - --- Sloppy focus ---[[ client.connect_signal('mouse::enter', function(c) - c:emit_signal( - 'request::activate', - 'mouse_enter', { - raise = true, + end, }) -end) ]] +end +return instance diff --git a/awesome/src/core/titlebar.lua b/awesome/src/core/titlebar.lua index 736c4d5..0ede8d9 100644 --- a/awesome/src/core/titlebar.lua +++ b/awesome/src/core/titlebar.lua @@ -8,7 +8,7 @@ local beautiful = require('beautiful') local cairo = require('lgi').cairo local dpi = require('beautiful').xresources.apply_dpi local gcolor = require('gears.color') -local gdk = require('lgi').Gdk +local gdk = require('lgi').require('Gdk', '3.0') local gfilesystem = require('gears.filesystem') local gsurface = require('gears.surface') local gtimer = require('gears.timer') @@ -497,8 +497,6 @@ local function create_titlebar_items(c, group) return layout end ----Adds the titlebar to the left of a client ----@param c client function add_titlebar(c) if titlebar_position == 'top' then atitlebar(c, { diff --git a/awesome/src/lib/overflow_widget/overflow.lua b/awesome/src/lib/overflow_widget/overflow.lua index c6eed22..ac513c3 100644 --- a/awesome/src/lib/overflow_widget/overflow.lua +++ b/awesome/src/lib/overflow_widget/overflow.lua @@ -18,6 +18,8 @@ local gshape = require('gears.shape') local gobject = require('gears.object') local mousegrabber = mousegrabber +local rubato = require('src.lib.rubato') + local overflow = { mt = {} } -- Determine the required space to draw the layout's children and, if necessary, @@ -33,7 +35,7 @@ function overflow:fit(context, orig_width, orig_height) local scrollbar_width = self._private.scrollbar_width local scrollbar_enabled = self._private.scrollbar_enabled local used_in_dir, used_max = 0, 0 - local is_y = self._private.dir == "y" + local is_y = self._private.dir == 'y' local avail_in_dir = is_y and orig_height or orig_width -- Set the direction covered by scrolling to the maximum value @@ -81,7 +83,7 @@ end -- Only those widgets that are currently visible will be placed. function overflow:layout(context, orig_width, orig_height) local result = {} - local is_y = self._private.dir == "y" + local is_y = self._private.dir == 'y' local widgets = self._private.widgets local avail_in_dir = is_y and orig_height or orig_width local scrollbar_width = self._private.scrollbar_width @@ -140,9 +142,9 @@ function overflow:layout(context, orig_width, orig_height) bar_w, bar_h = base.fit_widget(self, context, scrollbar_widget, scrollbar_width, bar_length) bar_y = bar_pos - if scrollbar_position == "left" then + if scrollbar_position == 'left' then widget_x = widget_x + bar_w - elseif scrollbar_position == "right" then + elseif scrollbar_position == 'right' then bar_x = orig_width - bar_w end @@ -153,9 +155,9 @@ function overflow:layout(context, orig_width, orig_height) bar_w, bar_h = base.fit_widget(self, context, scrollbar_widget, bar_length, scrollbar_width) bar_x = bar_pos - if scrollbar_position == "top" then + if scrollbar_position == 'top' then widget_y = widget_y + bar_h - elseif scrollbar_position == "bottom" then + elseif scrollbar_position == 'bottom' then bar_y = orig_height - bar_h end @@ -305,6 +307,13 @@ end -- @tparam number scroll_factor The scroll factor. -- @propemits true false +overflow.rubato_timed = rubato.timed { + duration = 0.5, + rate = 24, + clamp_position = true, +} + +local first_call = true function overflow:set_scroll_factor(factor) local current = self._private.scroll_factor local interval = self._private.used_in_dir - self._private.avail_in_dir @@ -318,10 +327,22 @@ function overflow:set_scroll_factor(factor) return end - self._private.scroll_factor = math.min(1, math.max(factor, 0)) + local function update_scroll() + self._private.scroll_factor = self.rubato_timed.pos + self:emit_signal('widget::layout_changed') + self:emit_signal('property::scroll_factor', factor) + end - self:emit_signal("widget::layout_changed") - self:emit_signal("property::scroll_factor", factor) + if first_call then + self.rubato_timed:subscribe(update_scroll) + end + + self.rubato_timed.target = math.min(1, math.max(factor + (self.rubato_timed.target - self.rubato_timed.pos), 0)) + print(self.rubato_timed.target) + --self._private.scroll_factor = math.min(1, math.max(factor, 0)) + + --self:emit_signal('widget::layout_changed') + --self:emit_signal('property::scroll_factor', factor) end function overflow:get_scroll_factor() @@ -347,8 +368,8 @@ function overflow:set_scrollbar_width(width) self._private.scrollbar_width = width - self:emit_signal("widget::layout_changed") - self:emit_signal("property::scrollbar_width", width) + self:emit_signal('widget::layout_changed') + self:emit_signal('property::scrollbar_width', width) end --- The scrollbar position. @@ -370,8 +391,8 @@ function overflow:set_scrollbar_position(position) self._private.scrollbar_position = position - self:emit_signal("widget::layout_changed") - self:emit_signal("property::scrollbar_position", position) + self:emit_signal('widget::layout_changed') + self:emit_signal('property::scrollbar_position', position) end function overflow:get_scrollbar_position() @@ -396,8 +417,8 @@ function overflow:set_scrollbar_enabled(enabled) self._private.scrollbar_enabled = enabled - self:emit_signal("widget::layout_changed") - self:emit_signal("property::scrollbar_enabled", enabled) + self:emit_signal('widget::layout_changed') + self:emit_signal('property::scrollbar_enabled', enabled) end function overflow:get_scrollbar_enabled() @@ -407,7 +428,7 @@ end -- Wraps a callback function for `mousegrabber` that is capable of -- updating the scroll factor. local function build_grabber(container, initial_x, initial_y, geo) - local is_y = container._private.dir == "y" + local is_y = container._private.dir == 'y' local bar_interval = container._private.avail_in_dir - container._private.bar_length local start_pos = container._private.scroll_factor * bar_interval local start = is_y and initial_y or initial_x @@ -439,7 +460,7 @@ local function apply_scrollbar_mouse_signal(container, w) if button_id ~= 1 then return end - mousegrabber.run(build_grabber(container, x, y, geo), "fleur") + mousegrabber.run(build_grabber(container, x, y, geo), 'fleur') end) end @@ -461,8 +482,8 @@ function overflow:set_scrollbar_widget(widget) self._private.scrollbar_widget = w - self:emit_signal("widget::layout_changed") - self:emit_signal("property::scrollbar_widget", widget) + self:emit_signal('widget::layout_changed') + self:emit_signal('property::scrollbar_widget', widget) end function overflow:get_scrollbar_widget() @@ -473,13 +494,13 @@ function overflow:reset() self._private.widgets = {} self._private.scroll_factor = 0 - local scrollbar_widget = separator({ shape = gshape.rectangle }) + local scrollbar_widget = separator { shape = gshape.rectangle } apply_scrollbar_mouse_signal(self, scrollbar_widget) self._private.scrollbar_widget = scrollbar_widget - self:emit_signal("widget::layout_changed") - self:emit_signal("widget::reset") - self:emit_signal("widget::reseted") + self:emit_signal('widget::layout_changed') + self:emit_signal('widget::reset') + self:emit_signal('widget::reseted') end local function new(dir, ...) @@ -500,9 +521,9 @@ local function new(dir, ...) ret._private.fill_space = true ret._private.scrollbar_width = 5 ret._private.scrollbar_enabled = true - ret._private.scrollbar_position = dir == "vertical" and "right" or "bottom" + ret._private.scrollbar_position = dir == 'vertical' and 'right' or 'bottom' - local scrollbar_widget = separator({ shape = gshape.rectangle }) + local scrollbar_widget = separator { shape = gshape.rectangle } apply_scrollbar_mouse_signal(ret, scrollbar_widget) ret._private.scrollbar_widget = scrollbar_widget @@ -525,7 +546,7 @@ end -- @tparam widget ... Widgets that should be added to the layout. -- @constructorfct wibox.layout.overflow.horizontal function overflow.horizontal(...) - return new("horizontal", ...) + return new('horizontal', ...) end --- Returns a new vertical overflow layout. @@ -536,7 +557,7 @@ end -- @tparam widget ... Widgets that should be added to the layout. -- @constructorfct wibox.layout.overflow.vertical function overflow.vertical(...) - return new("vertical", ...) + return new('vertical', ...) end return setmetatable(overflow, overflow.mt) diff --git a/awesome/src/modules/app_launcher/init.lua b/awesome/src/modules/app_launcher/init.lua index af5030c..6d2823a 100644 --- a/awesome/src/modules/app_launcher/init.lua +++ b/awesome/src/modules/app_launcher/init.lua @@ -1,3 +1,11 @@ +local ipairs = ipairs +local math = math +local pairs = pairs +local setmetatable = setmetatable +local table = table + +-- Awesome Libs +local Gio = require('lgi').Gio local abutton = require('awful.button') local akey = require('awful.key') local akeygrabber = require('awful.keygrabber') @@ -5,22 +13,22 @@ local aplacement = require('awful.placement') local apopup = require('awful.popup') local beautiful = require('beautiful') local dpi = beautiful.xresources.apply_dpi +local gcolor = require('gears.color') +local gfilesystem = require('gears.filesystem') +local gobject = require('gears.object') local gtable = require('gears.table') local gtimer = require('gears.timer') local wibox = require('wibox') -local gobject = require('gears.object') -local Gio = require('lgi').Gio -local gfilesystem = require('gears.filesystem') -local gcolor = require('gears.color') +-- Third Party Libs local fzy = require('fzy') -local hover = require('src.tools.hover') -local inputbox = require('src.modules.inputbox') +-- Local Libs local context_menu = require('src.modules.context_menu') -local config = require('src.tools.config') -local icon_lookup = require('src.tools.gio_icon_lookup') local dock = require('src.modules.crylia_bar.dock') +local hover = require('src.tools.hover') +local icon_lookup = require('src.tools.gio_icon_lookup') +local inputbox = require('src.modules.inputbox') local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/context_menu/' @@ -31,6 +39,12 @@ local capi = { local launcher = gobject {} +--- Fetches all applications and their information from Gio.AppInfo.get_all() +--- and generates a wibox widget for each application, containing the application's icon, name and launch command. +--- The generated wibox widget also includes a context menu that allows the user to launch, +--- add to desktop, or pin the application to the dock. +--- @param self The launcher table. +--- function launcher:fetch_apps() for _, app in ipairs(Gio.AppInfo.get_all()) do local app_id = app:get_id() @@ -190,54 +204,15 @@ function launcher:fetch_apps() end end -local function levenshtein_distance(str1, str2) - local len1 = string.len(str1) - local len2 = string.len(str2) - local matrix = {} - local cost = 0 - - if (len1 == 0) then - return len2 - elseif (len2 == 0) then - return len1 - elseif (str1 == str2) then - return 0 - end - - for i = 0, len1, 1 do - matrix[i] = {} - matrix[i][0] = i - end - for j = 0, len2, 1 do - matrix[0][j] = j - end - - for i = 1, len1, 1 do - for j = 1, len2, 1 do - if str1:byte(i) == str2:byte(j) then - cost = 0 - else - cost = 1 - end - - matrix[i][j] = math.min( - matrix[i - 1][j] + 1, - matrix[i][j - 1] + 1, - matrix[i - 1][j - 1] + cost - ) - end - end - - return matrix[len1][len2] -end - +---Reset the grid and add all apps that match to a filter using fzy scoring +---@param filter string Filter for the name, category and keywords function launcher:filter_apps(filter) filter = filter or '' self.grid:reset() local app_list = {} for _, app in pairs(self.app_table) do if filter == '' - or fzy.has_match(filter, app.name) + or fzy.has_match(filter, app.name or '') or fzy.has_match(filter, app.category or '') or fzy.has_match(filter, app.keywords or '') then @@ -245,17 +220,22 @@ function launcher:filter_apps(filter) end end table.sort(app_list, function(a, b) - return a.name < b.name - end) - --sort by lowest levenshtein distance - table.sort(app_list, function(a, b) - return levenshtein_distance(filter, a.name) < levenshtein_distance(filter, b.name) + local score_a = fzy.score(filter, a.name) + local score_b = fzy.score(filter, b.name) + + if score_a ~= score_b then + return score_a > score_b + else + return a.name < b.name + end end) for _, app in ipairs(app_list) do self.grid:add(app) end end +--- Toggle the visibility of the application launcher popup window. +--- @param screen number The screen where the launcher will be displayed. function launcher:toggle(screen) if not self.popup.visible then self.popup.screen = screen @@ -268,13 +248,20 @@ function launcher:toggle(screen) x = 1, y = 1, } self.popup.visible = false + collectgarbage('collect') end end +---Reset the border color of a widget at x,y +---@param x number Grid column +---@param y number Grid row function launcher:selection_remove(x, y) self.grid:get_widgets_at(y, x)[1].border_color = beautiful.colorscheme.border_color end +---Update the border color of a widget at x,y +---@param x number Grid column +---@param y number Grid row function launcher:selection_update(x, y) local w_old = self.grid:get_widgets_at(y, x)[1] local w_new = self.grid:get_widgets_at(self.cursor.y, self.cursor.x)[1] @@ -282,7 +269,10 @@ function launcher:selection_update(x, y) w_new.border_color = beautiful.colorscheme.bg_teal end +-- Offset to know when to scroll up/down local up_offset = 0 + +--- Move the cursor down function launcher:move_down() local row, _ = self.grid:get_dimension() if self.cursor.y < row then @@ -303,6 +293,7 @@ function launcher:move_down() end end +--- Move the cursor up function launcher:move_up() local row, _ = self.grid:get_dimension() if self.cursor.y > 1 then @@ -320,6 +311,7 @@ function launcher:move_up() end end +--- Move the cursor left function launcher:move_left() if self.cursor.x > 1 then self.cursor.x = self.cursor.x - 1 @@ -327,6 +319,7 @@ function launcher:move_left() end end +--- Move the cursor right function launcher:move_right() local _, col = self.grid:get_dimension() if self.cursor.x < col then @@ -336,11 +329,13 @@ function launcher:move_right() end end +--- Wrapper to focus the searchbar function launcher:focus_searchbar() self.searchbar:focus() self.popup.widget:get_children_by_id('searchbar_bg')[1].border_color = beautiful.colorscheme.bg_teal end +--- Wrapper to unfocus the searchbar function launcher:unfocus_searchbar() self.searchbar:unfocus() self.popup.widget:get_children_by_id('searchbar_bg')[1].border_color = beautiful.colorscheme.border_color @@ -450,6 +445,7 @@ if not instance then self:toggle(capi.mouse.screen) self.grid:get_widgets_at(self.cursor.x, self.cursor.y)[1].execute() self:filter_apps('') + self.searchbar:set_text('') elseif key == 'Down' then if not (self.keygrabber.running == akeygrabber.current_instance) then self:selection_update(1, 1) diff --git a/awesome/src/modules/bluetooth/device.lua b/awesome/src/modules/bluetooth/device.lua index 8da4b4f..bc04cf8 100644 --- a/awesome/src/modules/bluetooth/device.lua +++ b/awesome/src/modules/bluetooth/device.lua @@ -15,7 +15,7 @@ local lgi = require('lgi') local wibox = require('wibox') -- Own libs -local context_menu = require('src.modules.context_menu.init') +local context_menu = require('src.modules.context_menu') local hover = require('src.tools.hover') local input = require('src.modules.inputbox') diff --git a/awesome/src/modules/bluetooth/init.lua b/awesome/src/modules/bluetooth/init.lua index 026df24..d02cea8 100644 --- a/awesome/src/modules/bluetooth/init.lua +++ b/awesome/src/modules/bluetooth/init.lua @@ -413,84 +413,6 @@ function bluetooth.new(args) widget = wibox.container.margin, } - assert(type(ret) == 'table', 'bluetooth_controller: ret is not a table') - - -- Get a reference to the dnd button - local dnd = ret:get_children_by_id('dnd')[1]:get_widget() - - -- Toggle bluetooth on or off - dnd:connect_signal('dnd::toggle', function() - 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 = '/', - } - - -- 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', - } - - if not ret._private.Adapter1.Powered then return end - - -- 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] @@ -626,6 +548,14 @@ function bluetooth.new(args) end) --#endregion + -- Get a reference to the dnd button + local dnd = ret:get_children_by_id('dnd')[1]:get_widget() + + -- Toggle bluetooth on or off + dnd:connect_signal('dnd::toggle', function() + ret:toggle() + end) + -- Add buttons to the scan button ret:get_children_by_id('scan')[1]:buttons { abutton({}, 1, function() @@ -637,6 +567,74 @@ function bluetooth.new(args) hover.bg_hover { widget = connected_margin.connected_bg } hover.bg_hover { widget = discovered_bg } + 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 = '/', + } + + -- 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', + } + + if not ret._private.Adapter1.Powered then return ret end + + -- 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 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') + + -- 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') + + 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 + return ret end diff --git a/awesome/src/modules/calendar/init.lua b/awesome/src/modules/calendar/init.lua index 37b2cc5..28d2c9f 100644 --- a/awesome/src/modules/calendar/init.lua +++ b/awesome/src/modules/calendar/init.lua @@ -478,12 +478,14 @@ function calendar:create_calendar_widget() task_popup.x = capi.mouse.coords().x task_popup.y = capi.mouse.coords().y task_popup.visible = not task_popup.visible + collectgarbage('collect') end) ) ) tw:connect_signal('mouse::leave', function() task_popup.visible = false + collectgarbage('collect') end) hover.bg_hover { widget = tw } @@ -754,7 +756,7 @@ function calendar.new(args) { widget = wibox.widget.imagebox, resize = false, - image = gcolor.recolor_image(icondir .. 'add_ical.svg', beautiful.colorscheme.bg_red), + image = gcolor.recolor_image(icondir .. 'add_ical.svg', beautiful.colorscheme.bg), halign = 'center', valign = 'center', }, @@ -883,7 +885,7 @@ function calendar.new(args) border_width = dpi(2), border_strategy = 'inner', fg = beautiful.colorscheme.fg, - shape = beautiful.shape, + shape = beautiful.shape[12], }) ret:get_tasks() diff --git a/awesome/src/modules/context_menu/init.lua b/awesome/src/modules/context_menu/init.lua index fb215c7..3cbf646 100644 --- a/awesome/src/modules/context_menu/init.lua +++ b/awesome/src/modules/context_menu/init.lua @@ -104,7 +104,7 @@ function context_menu:make_entries(wtemplate, entries, spacing) widget = wibox.container.margin, }, bg = beautiful.colorscheme.bg, - fg = beautiful.colorscheme.bg_red, + fg = beautiful.colorscheme.fg, widget = wibox.container.background, } diff --git a/awesome/src/modules/crylia_bar/dock.lua b/awesome/src/modules/crylia_bar/dock.lua index 2b12ffa..080283b 100644 --- a/awesome/src/modules/crylia_bar/dock.lua +++ b/awesome/src/modules/crylia_bar/dock.lua @@ -74,27 +74,24 @@ function dock:toggle() self.popup.visible = not self.popup.visible end -function dock:write_elements_to_file_async(callback) +function dock:write_elements_to_file_async() --create a local copy of the elements["pinned"] table and only set the desktop_file key from its children local elements_copy = { pinned = {} } for _, element in ipairs(elements['pinned']) do table.insert(elements_copy['pinned'], { desktop_file = element.desktop_file }) end - config.write_json(gfilesystem.get_configuration_dir() .. 'src/config/dock_' .. self.screen.index .. '.json', elements_copy['pinned'], callback) + + config.write_json(gfilesystem.get_configuration_dir() .. 'src/config/dock_' .. self.screen.index .. '.json', elements_copy['pinned']) end ---Read the content of dock.json and get the content as a table ----@param callback function Called after the elements have been set, no values are passed -function dock:read_elements_from_file_async(callback) +function dock:read_elements_from_file_async() local data = config.read_json(gfilesystem.get_configuration_dir() .. 'src/config/dock_' .. self.screen.index .. '.json') -- Make sure to not set the running key to nil on accident for _, v in ipairs(data) do local w = self:get_element_widget(v.desktop_file) table.insert(elements['pinned'], w) end - if callback then - callback() - end end ---Creates a pinned widget for the dock and adds it into the elements table @@ -135,6 +132,7 @@ function dock:get_element_widget(desktop_file) bg = beautiful.colorscheme.bg1, shape = beautiful.shape[8], widget = wibox.container.background, + desktop_file = desktop_file, } local action_entries = {} diff --git a/awesome/src/modules/desktop/desktop.lua b/awesome/src/modules/desktop/desktop.lua index 4ce099d..514c52c 100644 --- a/awesome/src/modules/desktop/desktop.lua +++ b/awesome/src/modules/desktop/desktop.lua @@ -11,7 +11,7 @@ local wibox = require('wibox') local config = require('src.tools.config') local element = require('src.modules.desktop.element') -local cm = require('src.modules.context_menu.init') +local cm = require('src.modules.context_menu') local capi = { mouse = mouse, diff --git a/awesome/src/modules/init.lua b/awesome/src/modules/init.lua index f5f1a8f..31c6ede 100644 --- a/awesome/src/modules/init.lua +++ b/awesome/src/modules/init.lua @@ -1,6 +1,6 @@ -local tinsert = table.insert -local load = load local ipairs = ipairs +local load = load +local tinsert = table.insert -- Awesome Libs local awful = require('awful') @@ -20,12 +20,16 @@ if not instance then awful.tag({ '1', '2', '3', '4', '5', '6', '7', '8', '9' }, s, layouts[1]) require('src.modules.desktop.desktop') { screen = s } - require('src.modules.crylia_bar')(s) - --require('src.modules.crylia_wibox.init')(s) + if beautiful.user_config.crylia_bar then + require('src.modules.crylia_bar')(s) + else + require('src.modules.crylia_wibox.init')(s) + end require('src.modules.notification-center') { screen = s } - --require('src.modules.window_switcher.init') { screen = s } - require('src.modules.application_launcher') { screen = s } + require('src.modules.window_switcher')(s) + require('src.modules.app_launcher')(s) end) + require('src.modules.powermenu')() end, }) end diff --git a/awesome/src/modules/network_controller/access_point.lua b/awesome/src/modules/network_controller/access_point.lua index 82140f8..861eaee 100644 --- a/awesome/src/modules/network_controller/access_point.lua +++ b/awesome/src/modules/network_controller/access_point.lua @@ -20,7 +20,7 @@ local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy') -- Own libs local ap_form = require('src.modules.network_controller.ap_form') -local cm = require('src.modules.context_menu.init') +local cm = require('src.modules.context_menu') local hover = require('src.tools.hover') local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/network/' @@ -268,7 +268,7 @@ function access_point.new(args) ret.NetworkManagerAccessPointProperties:connect_signal(function(_, properties, data) if data.Strength then awesome.emit_signal('NM::AccessPointStrength', data.Strength) - if ret.is_ap_active(ret.NetworkManagerAccessPoint.object_path) then + if ret.is_ap_active(ret.NetworkManagerAccessPoint) then ret:get_children_by_id('icon')[1].image = gcolor.recolor_image( icondir .. 'wifi-strength-' .. math.floor(data.Strength / 25) + 1 .. '.svg', beautiful.colorscheme.bg) diff --git a/awesome/src/modules/network_controller/ap_form.lua b/awesome/src/modules/network_controller/ap_form.lua index 72224c4..19fa642 100644 --- a/awesome/src/modules/network_controller/ap_form.lua +++ b/awesome/src/modules/network_controller/ap_form.lua @@ -43,7 +43,7 @@ function ap_form.new(args) { widget = wibox.widget.textbox, text = NM.utils_ssid_to_utf8(args.NetworkManagerAccessPoint.Ssid), - font = beautiful.user_config.font.specify .. ',extra bold 16', + font = beautiful.user_config.font .. ' extra bold 16', halign = 'center', valign = 'center', }, diff --git a/awesome/src/modules/notification-center/widgets/notification_list.lua b/awesome/src/modules/notification-center/widgets/notification_list.lua index 1820132..70c8e45 100644 --- a/awesome/src/modules/notification-center/widgets/notification_list.lua +++ b/awesome/src/modules/notification-center/widgets/notification_list.lua @@ -1,23 +1,24 @@ -------------------------------------- --- This is the notification-center -- -------------------------------------- +local os = os +local setmetatable = setmetatable -- Awesome Libs -local dpi = require('beautiful').xresources.apply_dpi -local wibox = require('wibox') -local naughty = require('naughty') -local gtimer = require('gears.timer') +local abutton = require('awful.button') local beautiful = require('beautiful') +local dpi = beautiful.xresources.apply_dpi local gcolor = require('gears.color') local gfilesystem = require('gears.filesystem') local gtable = require('gears.table') -local abutton = require('awful.button') +local gtimer = require('gears.timer') +local naughty = require('naughty') +local wibox = require('wibox') +-- Local Libs local hover = require('src.tools.hover') local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/notifications/' -return setmetatable({}, { +local instance = nil +instance = setmetatable({}, { __call = function() local ret = wibox.widget { layout = require('src.lib.overflow_widget.overflow').vertical, @@ -61,13 +62,13 @@ return setmetatable({}, { notification = n, widget = naughty.widget.title, markup = [[]] .. (n.app_name or - 'Unknown App') .. [[ | ]] .. (n.title or 'System Notification') .. [[]], + beautiful.colorscheme.bg .. [[" font="]] .. beautiful.user_config.font .. ' bold 12' .. [[">]] .. (n.app_name or + 'Unknown App') .. [[ | ]] .. (n.title or 'System Notification') .. [[]], halign = 'left', valign = 'center', }, widget = wibox.container.constraint, - width = dpi(430), + width = dpi(250), height = dpi(35), strategy = 'max', }, @@ -83,7 +84,7 @@ return setmetatable({}, { { -- Clock widget = wibox.widget.textbox, test = 'now', - font = 'JetBrainsMono Nerd Font, Bold 12', + font = beautiful.user_config.font .. ' bold 12', fg = beautiful.colorscheme.bg, halign = 'center', valign = 'center', @@ -159,7 +160,7 @@ return setmetatable({}, { { notification = n, widget = naughty.widget.message, - font = 'JetBrainsMono Nerd Font, Regular 10', + font = beautiful.user_config.font .. ' regular 10', halign = 'left', valign = 'center', }, @@ -170,15 +171,6 @@ return setmetatable({}, { spacing = dpi(15), layout = wibox.layout.fixed.horizontal, }, - { -- Spacer - { - widget = wibox.container.background, - bg = beautiful.colorscheme.bg, - }, - widget = wibox.container.constraint, - strategy = 'exact', - height = dpi(2), - }, spacing = dpi(15), id = 'main_layout', layout = wibox.layout.fixed.vertical, @@ -244,3 +236,4 @@ return setmetatable({}, { return ret end, }) +return instance diff --git a/awesome/src/modules/powermenu/init.lua b/awesome/src/modules/powermenu/init.lua index a0bd8e2..ef91cbc 100644 --- a/awesome/src/modules/powermenu/init.lua +++ b/awesome/src/modules/powermenu/init.lua @@ -1,6 +1,4 @@ --------------------------------- --- This is the network widget -- --------------------------------- +local setmetatable = setmetatable -- Awesome Libs local abutton = require('awful.button') @@ -106,110 +104,106 @@ end function powermenu:toggle() self.keygrabber:start() - self.visible = not self.visible -end - -function powermenu.new() - local w = wibox { - widget = { - { - { - { - { - image = icondir .. 'defaultpfp.svg', - resize = true, - clip_shape = beautiful.shape[30], - valign = 'center', - halign = 'center', - id = 'icon_role', - widget = wibox.widget.imagebox, - }, - widget = wibox.container.constraint, - width = dpi(200), - height = dpi(200), - strategy = 'exact', - }, - { - halign = 'center', - valign = 'center', - font = 'JetBrains Mono Bold 30', - id = 'text_role', - widget = wibox.widget.textbox, - }, - spacing = dpi(50), - layout = wibox.layout.fixed.vertical, - }, - { - { - get_button('shutdown'), - get_button('reboot'), - get_button('logout'), - get_button('lock'), - get_button('suspend'), - spacing = dpi(30), - layout = wibox.layout.fixed.horizontal, - }, - widget = wibox.container.place, - }, - spacing = dpi(50), - layout = wibox.layout.fixed.vertical, - }, - widget = wibox.container.place, - }, - screen = capi.screen.primary, - type = 'splash', - visible = false, - ontop = true, - bg = beautiful.colorscheme.bg .. '88', - height = capi.screen.primary.geometry.height, - width = capi.screen.primary.geometry.width, - x = capi.screen.primary.geometry.x, - y = capi.screen.primary.geometry.y, - } - - gtable.crush(w, powermenu, true) - - w:buttons { gtable.join( - abutton({}, 3, function() - w:toggle() - w.keygrabber:stop() - end) - ), } - - w.keygrabber = akeygrabber { - autostart = false, - stop_event = 'release', - stop_key = 'Escape', - keybindings = { - akey { - modifiers = {}, - key = 'Escape', - on_press = function() - w:toggle() - end, - }, - }, - } - - -- 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 - aspawn.easy_async_with_shell("./.config/awesome/src/scripts/pfp.sh 'userPfp'", function(stdout) - if stdout then - w:get_children_by_id('icon_role')[1].image = stdout:gsub('\n', '') - else - w:get_children_by_id('icon_role')[1].image = icondir .. 'defaultpfp.svg' - end - end) - - aspawn.easy_async_with_shell("./.config/awesome/src/scripts/pfp.sh 'userName' '" .. beautiful.user_config.namestyle .. "'", function(stdout) - w:get_children_by_id('text_role')[1].text = stdout:gsub('\n', '') - end) - - return w + self.w.visible = not self.w.visible end if instance == nil then - instance = powermenu.new() + instance = setmetatable(powermenu, { + __call = function(self) + self.w = wibox { + widget = { + { + { + { + { + image = icondir .. 'defaultpfp.svg', + resize = true, + clip_shape = beautiful.shape[30], + valign = 'center', + halign = 'center', + id = 'icon_role', + widget = wibox.widget.imagebox, + }, + widget = wibox.container.constraint, + width = dpi(200), + height = dpi(200), + strategy = 'exact', + }, + { + halign = 'center', + valign = 'center', + font = 'JetBrains Mono Bold 30', + id = 'text_role', + widget = wibox.widget.textbox, + }, + spacing = dpi(50), + layout = wibox.layout.fixed.vertical, + }, + { + { + get_button('shutdown'), + get_button('reboot'), + get_button('logout'), + get_button('lock'), + get_button('suspend'), + spacing = dpi(30), + layout = wibox.layout.fixed.horizontal, + }, + widget = wibox.container.place, + }, + spacing = dpi(50), + layout = wibox.layout.fixed.vertical, + }, + widget = wibox.container.place, + }, + screen = capi.screen.primary, + type = 'splash', + visible = false, + ontop = true, + bg = beautiful.colorscheme.bg .. '88', + height = capi.screen.primary.geometry.height, + width = capi.screen.primary.geometry.width, + x = capi.screen.primary.geometry.x, + y = capi.screen.primary.geometry.y, + } + + self.w:buttons { gtable.join( + abutton({}, 3, function() + self:toggle() + self.keygrabber:stop() + end) + ), } + + self.keygrabber = akeygrabber { + autostart = false, + stop_event = 'release', + stop_key = 'Escape', + keybindings = { + akey { + modifiers = {}, + key = 'Escape', + on_press = function() + self:toggle() + end, + }, + }, + } + + -- 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 + aspawn.easy_async_with_shell("./.config/awesome/src/scripts/pfp.sh 'userPfp'", function(stdout) + if stdout then + self.w:get_children_by_id('icon_role')[1].image = stdout:gsub('\n', '') + else + self.w:get_children_by_id('icon_role')[1].image = icondir .. 'defaultpfp.svg' + end + end) + + aspawn.easy_async_with_shell("./.config/awesome/src/scripts/pfp.sh 'userName' '" .. beautiful.user_config.namestyle .. "'", function(stdout) + self.w:get_children_by_id('text_role')[1].text = stdout:gsub('\n', '') + end) + end, + }) end return instance diff --git a/awesome/src/modules/window_switcher/init.lua b/awesome/src/modules/window_switcher/init.lua index 11d8f19..36ff20c 100644 --- a/awesome/src/modules/window_switcher/init.lua +++ b/awesome/src/modules/window_switcher/init.lua @@ -17,139 +17,117 @@ local base = require('wibox.widget.base') local gtimer = require('gears.timer') local cairo = require('lgi').cairo local awidget = require('awful.widget') - -local capi = { - awesome = awesome, - client = client, - mouse = mouse, -} - ---local window_elements = require("src.modules.window_switcher.window_elements")() - ---[[ return function(s) - - local window_switcher_list = wibox.widget { - window_elements, - margins = dpi(20), - widget = wibox.container.margin - } - - local window_switcher_container = awful.popup { - widget = wibox.container.background, - ontop = true, - visible = false, - stretch = false, - screen = s, - shape = function(cr, width, height) - gears.shape.rounded_rect(cr, width, height, dpi(12)) - end, - placement = awful.placement.centered, - bg = beautiful.colorscheme.bg, - border_color = beautiful.colorscheme.border_color, - border_width = dpi(2) - } - - window_switcher_container:setup { - window_switcher_list, - layout = wibox.layout.fixed.vertical - } - - capi.awesome.connect_signal( - "toggle_window_switcher", - function() - if capi.mouse.screen == s then - window_switcher_container.visible = not window_switcher_container.visible - end - end - ) -end ]] +local ascreenshot = require('awful.screenshot') +local wtemplate = require('wibox.template') +local akeygrabber = require('awful.keygrabber') +local akey = require('awful.key') +local abutton = require('awful.button') +local aclient = require('awful.client') +local awful = require('awful') local client_preview = {} +local instance = nil +if not instance then + instance = setmetatable(client_preview, { + __call = function(self, s) -function client_preview:toggle() - self.visible = not self.visible -end - -return setmetatable(client_preview, { - __call = function(...) - local args = ... - - local w = gobject {} - - gtable.crush(w, client_preview, true) - - --[[ local tl = awidget.tasklist { - screen = 1, - layout = wibox.layout.fixed.horizontal, - filter = awidget.tasklist.filter.alltags, - update_function = function(widget, _, _, _, clients) - widget:reset() - - for _, c in ipairs(clients) do - local tw = wibox.widget { + self.popup = apopup { + widget = awidget.tasklist { + screen = 1, + layout = wibox.layout.fixed.horizontal, + filter = awidget.tasklist.filter.alltags, + style = { + font = beautiful.user_config.font .. ' regular 12', + }, + widget_template = wibox.template { { { { { - widget = wibox.widget.imagebox, - resize = true, - id = c.instance, + { + { -- icon and text + { + { + widget = wibox.widget.imagebox, + valign = 'center', + halign = 'center', + id = 'icon_role', + }, + { + widget = wibox.widget.textbox, + id = 'text_role', + }, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal, + }, + widget = wibox.container.constraint, + height = dpi(32), + width = dpi(256), + }, + { -- preview + id = 'screenshot', + width = dpi(256), + widget = wibox.container.constraint, + }, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical, + }, + widget = wibox.container.place, }, - widget = wibox.container.constraint, - height = dpi(256), - strategy = 'exact', + widget = wibox.container.margin, + margins = dpi(20), }, - widget = wibox.container.place, + widget = wibox.container.background, + border_color = beautiful.colorscheme.border_color, + id = 'border', + border_width = dpi(2), + bg = beautiful.colorscheme.bg1, + shape = beautiful.shape[8], }, widget = wibox.container.margin, margins = dpi(20), }, + bg = beautiful.colorscheme.bg, widget = wibox.container.background, - bg = '#414141', - id = c.pid, - shape = gshape.rounded_rect, - } - - gtimer { - timeout = 1 / 24, - autostart = true, - callback = function() - local content = gsurface(c.content) - local cr = cairo.Context(content) - local x, y, w, h = cr:clip_extents() - local img = cairo.ImageSurface.create(cairo.Format.ARGB32, w - x, h - y) - cr = cairo.Context(img) - cr:set_source_surface(content, 0, 0) - cr.operator = cairo.Operator.SOURCE - cr:paint() - local cont = tw:get_children_by_id('icon_role')[1] - if cont then - cont.image = gsurface.load(img) - return + create_callback = function(sself, c) + local ss = ascreenshot { + client = c, + } + ss:refresh() + local ib = ss.content_widget + ib.clip_shape = beautiful.shape[12] + ib.valign = 'center' + ib.halign = 'center' + sself:get_widget():get_children_by_id('screenshot')[1].widget = ib + end, + update_callback = function(sself, c) + if c.active and self.popup.visible then + local ss = ascreenshot { + client = c, + } + ss:refresh() + local ib = ss.content_widget + ib.clip_shape = beautiful.shape[12] + ib.valign = 'center' + ib.halign = 'center' + sself:get_widget():get_children_by_id('screenshot')[1].widget = ib + sself:get_widget():get_children_by_id('border')[1].border_color = beautiful.colorscheme.bg_purple + else + sself:get_widget():get_children_by_id('border')[1].border_color = beautiful.colorscheme.border_color end end, - } - - widget:add(tw) - end - - return widget - end, - } ]] - - w.popup = apopup { - widget = {}, - ontop = true, - visible = true, - screen = args.screen, - placement = aplacement.centered, - bg = beautiful.colorscheme.bg, - border_color = beautiful.colorscheme.border_color, - border_width = dpi(2), - } - - - return w - end, -}) + }, + }, + ontop = true, + visible = false, + screen = s, + bg = beautiful.colorscheme.bg, + border_color = beautiful.colorscheme.border_color, + border_width = dpi(2), + placement = aplacement.centered, + } + end, + }) +end +return instance diff --git a/awesome/src/modules/window_switcher/window_elements.lua b/awesome/src/modules/window_switcher/window_elements.lua deleted file mode 100644 index 68381a9..0000000 --- a/awesome/src/modules/window_switcher/window_elements.lua +++ /dev/null @@ -1,252 +0,0 @@ ---------------------------------- --- This is the window_switcher -- ---------------------------------- - --- Awesome Libs -local awful = require('awful') -local beautiful = require('beautiful') -local dpi = require('beautiful').xresources.apply_dpi -local gears = require('gears') -local wibox = require('wibox') - -local color = require('src.lib.color') -local rubato = require('src.lib.rubato') - -local capi = { - awesome = awesome, - client = client, -} - -return function() - - local elements = wibox.widget { - layout = wibox.layout.fixed.horizontal, - spacing = dpi(20), - id = 'switcher', - } - - local selected = 0 - - local function create_elements(fn) - fn = fn or '' - - elements:reset() - - local clients = capi.client.get() - local clients_sorted = {} - - if capi.client.focus then - clients_sorted[1] = capi.client.focus - end - - for _, client in ipairs(clients) do - if client ~= clients_sorted[1] then - table.insert(clients_sorted, client) - end - end - - selected = selected - - for _, client in ipairs(clients_sorted) do - local window_element = wibox.widget { - { - { - { - { -- Icon - { - id = 'icon', - --!ADD FALLBACK ICON!-- - image = gears.surface(client.icon), - valign = 'center', - halign = 'center', - widget = wibox.widget.imagebox, - }, - width = dpi(100), - height = dpi(100), - id = 'icon_const', - strategy = 'exact', - widget = wibox.container.constraint, - }, - { - { - text = client.name, - id = 'label', - widget = wibox.widget.textbox, - }, - id = 'place', - valign = 'center', - halign = 'center', - widget = wibox.container.place, - }, - id = 'layout1', - spacing = dpi(10), - layout = wibox.layout.fixed.vertical, - }, - id = 'box', - width = dpi(150), - height = dpi(150), - strategy = 'exact', - widget = wibox.container.constraint, - }, - id = 'margin', - margins = dpi(20), - widget = wibox.container.margin, - }, - shape = beautiful.shape[12], - border_color = beautiful.colorscheme.border_color, - border_width = dpi(2), - bg = beautiful.colorscheme.bg, - fg = beautiful.colorscheme.bg_green, - widget = wibox.container.background, - } - - elements:add(window_element) - end - - if fn == 'next' then - if selected >= #clients_sorted then - selected = 1 - else - selected = selected + 1 - end - - for i, element in ipairs(elements.children) do - - -- Background rubato init - local r_timed_bg = rubato.timed { duration = 0.5 } - local g_timed_bg = rubato.timed { duration = 0.5 } - local b_timed_bg = rubato.timed { duration = 0.5 } - - -- starting color - r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg) - - - -- Foreground rubato init - local r_timed_fg = rubato.timed { duration = 0.5 } - local g_timed_fg = rubato.timed { duration = 0.5 } - local b_timed_fg = rubato.timed { duration = 0.5 } - - -- starting color - r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg_green) - - -- Border rubato init - local r_timed_border = rubato.timed { duration = 0.5 } - local g_timed_border = rubato.timed { duration = 0.5 } - local b_timed_border = rubato.timed { duration = 0.5 } - - -- starting color - r_timed_border.pos, g_timed_border.pos, b_timed_border.pos = color.utils.hex_to_rgba(beautiful.colorscheme - .border_color) - - local function set_bg(newbg) - r_timed_bg.target, g_timed_bg.target, b_timed_bg.target = color.utils.hex_to_rgba(newbg) - end - - local function set_fg(newfg) - r_timed_fg.target, g_timed_fg.target, b_timed_fg.target = color.utils.hex_to_rgba(newfg) - end - - local function set_border(newborder) - r_timed_border.target, g_timed_border.target, b_timed_border.target = color.utils.hex_to_rgba(newborder) - end - - local function update_bg() - element:set_bg('#' .. color.utils.rgba_to_hex { r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos }) - end - - local function update_fg() - element:set_fg('#' .. color.utils.rgba_to_hex { r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos }) - end - - local function update_border() - element.border_color = '#' .. - color.utils.rgba_to_hex { r_timed_border.pos, g_timed_border.pos, b_timed_border.pos } - end - - -- Subscribe to the function bg and fg - r_timed_bg:subscribe(update_bg) - g_timed_bg:subscribe(update_bg) - b_timed_bg:subscribe(update_bg) - r_timed_fg:subscribe(update_fg) - g_timed_fg:subscribe(update_fg) - b_timed_fg:subscribe(update_fg) - r_timed_border:subscribe(update_border) - g_timed_border:subscribe(update_border) - b_timed_border:subscribe(update_border) - - if i == selected then - r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg) - r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg_green) - r_timed_border.pos, g_timed_border.pos, b_timed_border.pos = color.utils.hex_to_rgba(beautiful.colorscheme.border_color) - set_border(beautiful.colorscheme.bg_purple) - set_fg(beautiful.colorscheme.fg) - set_bg(beautiful.colorscheme.bg1) - elseif i == selected - 1 or (selected == 1 and i == #clients_sorted) then - r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg1) - r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.fg) - r_timed_border.pos, g_timed_border.pos, b_timed_border.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg_purple) - set_border(beautiful.colorscheme.border_color) - set_fg(beautiful.colorscheme.bg_green) - set_bg(beautiful.colorscheme.bg) - else - r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg) - r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos = color.utils.hex_to_rgba(beautiful.colorscheme.bg_green) - r_timed_border.pos, g_timed_border.pos, b_timed_border.pos = color.utils.hex_to_rgba(beautiful.colorscheme.border_color) - set_border(beautiful.colorscheme.border_color) - set_fg(beautiful.colorscheme.bg_green) - set_bg(beautiful.colorscheme.bg) - end - end - elseif fn == 'raise' then - local c = clients_sorted[selected] - if not c:isvisible() and c.first_tag then - c.first_tag:view_only() - end - c:emit_signal('request::activate') - c:raise() - - --reset selected - selected = 0 - end - return elements - end - - elements = create_elements() - - capi.awesome.connect_signal( - 'window_switcher::select_next', - function() - elements = create_elements('next') - end - ) - - capi.awesome.connect_signal( - 'window_switcher::raise', - function() - elements = create_elements('raise') - end - ) - - capi.client.connect_signal( - 'manage', - function() - elements = create_elements() - end - ) - - capi.client.connect_signal( - 'unmanage', - function() - elements = create_elements() - end - ) - - capi.awesome.connect_signal( - 'window_switcher::update', - function() - elements = create_elements() - end - ) - - return elements -end diff --git a/awesome/src/theme/init.lua b/awesome/src/theme/init.lua index 8a1c628..69d788f 100644 --- a/awesome/src/theme/init.lua +++ b/awesome/src/theme/init.lua @@ -1,3 +1,7 @@ +local setmetatable = setmetatable +local print = print +local type = type + -------------------------------------------------- -- ██████╗██████╗ ██╗ ██╗██╗ ██╗ █████╗ -- -- ██╔════╝██╔══██╗╚██╗ ██╔╝██║ ██║██╔══██╗ -- @@ -6,6 +10,7 @@ -- ╚██████╗██║ ██║ ██║ ███████╗██║██║ ██║ -- -- ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝╚═╝ ╚═╝ -- -------------------------------------------------- + local awful = require('awful') local beautiful = require('beautiful') local dpi = beautiful.xresources.apply_dpi @@ -19,116 +24,122 @@ local capi = { screen = screen, } -local function get_userconfig() - local data = config.read_json(gfilesystem.get_xdg_config_home() .. 'crylia_theme/crylia_theme.json') - if not data then - print('Warning: No crylia_theme.json found, using default config') +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function() + local function get_userconfig() + local data = config.read_json(gfilesystem.get_xdg_config_home() .. 'crylia_theme/crylia_theme.json') + if not data then + print('Warning: No crylia_theme.json found, using default config') - data = config.read_json('/etc/crylia_theme/crylia_theme.json') - end + data = config.read_json('/etc/crylia_theme/crylia_theme.json') + end - assert(type(data) == 'table', 'Invalid config file (not a table)!') + assert(type(data) == 'table', 'Invalid config file (not a table)!') - return data + return data + end + + local function get_colorscheme() + local data = config.read_json(gfilesystem.get_xdg_config_home() .. 'crylia_theme/one_dark.json') + if not data then + print('Warning: No theme.json found, using default config') + + data = config.read_json('/etc/crylia_theme/theme.json') + end + + assert(type(data) == 'table', 'Invalid config file (not a table)!') + + return data + end + + local theme = {} + + awesome.set_preferred_icon_size(128) + + theme.user_config = get_userconfig() + theme.colorscheme = get_colorscheme() + + theme.shape = {} + for i = 2, 30, 2 do + theme.shape[i] = function(w, h, cr) + gshape.rounded_rect(w, h, cr, dpi(i)) + end + end + + -- Default font, change it in user_config, not here. + theme.font = theme.user_config.font .. ' bold ' .. 16 + + --#region Client variables + theme.useless_gap = dpi(5) + theme.border_width = dpi(2) + theme.border_normal = theme.colorscheme.bg_1 + theme.border_marked = theme.colorscheme.bg_red + --#endregion + + --#region Tooltip variables + theme.tooltip_border_color = theme.colorscheme.border_color + theme.tooltip_bg = theme.colorscheme.bg + theme.tooltip_fg = theme.colorscheme.bg_teal + theme.tooltip_border_width = dpi(2) + theme.tooltip_gaps = dpi(15) + --#endregion + + --#region Hotkeys variables + theme.hotkeys_bg = theme.colorscheme.bg + theme.hotkeys_fg = theme.colorscheme.fg + theme.hotkeys_border_width = dpi(2) + theme.hotkeys_border_color = theme.colorscheme.border_color + theme.hotkeys_modifiers_fg = theme.colorscheme.bg_teal + theme.hotkeys_description_font = theme.user_config.font + theme.hotkeys_font = theme.user_config.font + theme.hotkeys_group_margin = dpi(20) + theme.hotkeys_label_bg = theme.colorscheme.bg_teal + theme.hotkeys_label_fg = theme.colorscheme.bg + --#endregion + + --#region Layout icons + local layout_path = gfilesystem.get_configuration_dir() .. 'src/assets/layout/' + theme.layout_cornerne = layout_path .. 'cornerne.png' + theme.layout_cornernw = layout_path .. 'cornernw.png' + theme.layout_cornerse = layout_path .. 'cornerse.png' + theme.layout_cornersw = layout_path .. 'cornersw.png' + theme.layout_dwindle = layout_path .. 'dwindle.png' + theme.layout_fairh = layout_path .. 'fairh.png' + theme.layout_fairv = layout_path .. 'fairv.png' + theme.layout_floating = layout_path .. 'floating.png' + theme.layout_fullscreen = layout_path .. 'fullscreen.png' + theme.layout_magnifier = layout_path .. 'magnifier.png' + theme.layout_max = layout_path .. 'max.png' + theme.layout_spiral = layout_path .. 'spiral.png' + theme.layout_tile = layout_path .. 'tile.png' + theme.layout_tilebottom = layout_path .. 'tilebottom.png' + theme.layout_tileleft = layout_path .. 'tileleft.png' + theme.layout_tiletop = layout_path .. 'tiletop.png' + --#endregion + + theme.notification_spacing = dpi(20) + theme.bg_systray = theme.colorscheme.bg1 + theme.systray_icon_spacing = dpi(10) + + -- Wallpaper + beautiful.wallpaper = theme.user_config['wallpaper'] + capi.screen.connect_signal('request::wallpaper', function(s) + if beautiful.wallpaper then + if type(beautiful.wallpaper) == 'string' then + gwallpaper.maximized(beautiful.wallpaper, s) + else + beautiful.wallpaper(s) + end + end + end) + + beautiful.init(theme) + + -- Load titlebar + require('src.core.titlebar')() + end, + }) end - -local function get_colorscheme() - local data = config.read_json(gfilesystem.get_xdg_config_home() .. 'crylia_theme/one_dark.json') - if not data then - print('Warning: No theme.json found, using default config') - - data = config.read_json('/etc/crylia_theme/theme.json') - end - - assert(type(data) == 'table', 'Invalid config file (not a table)!') - - return data -end - -local theme = {} - -awesome.set_preferred_icon_size(128) - -theme.user_config = get_userconfig() -theme.colorscheme = get_colorscheme() - -theme.shape = {} -for i = 2, 30, 2 do - theme.shape[i] = function(w, h, cr) - gshape.rounded_rect(w, h, cr, dpi(i)) - end -end - --- Default font, change it in user_config, not here. -theme.font = theme.user_config.font .. ' bold ' .. dpi(16) - ---#region Client variables -theme.useless_gap = dpi(5) -theme.border_width = dpi(2) -theme.border_normal = theme.colorscheme.bg_1 -theme.border_marked = theme.colorscheme.bg_red ---#endregion - ---#region Tooltip variables -theme.tooltip_border_color = theme.colorscheme.border_color -theme.tooltip_bg = theme.colorscheme.bg -theme.tooltip_fg = theme.colorscheme.bg_teal -theme.tooltip_border_width = dpi(2) -theme.tooltip_gaps = dpi(15) ---#endregion - ---#region Hotkeys variables -theme.hotkeys_bg = theme.colorscheme.bg -theme.hotkeys_fg = theme.colorscheme.fg -theme.hotkeys_border_width = dpi(2) -theme.hotkeys_border_color = theme.colorscheme.border_color -theme.hotkeys_modifiers_fg = theme.colorscheme.bg_teal -theme.hotkeys_description_font = theme.user_config.font -theme.hotkeys_font = theme.user_config.font -theme.hotkeys_group_margin = dpi(20) -theme.hotkeys_label_bg = theme.colorscheme.bg_teal -theme.hotkeys_label_fg = theme.colorscheme.bg ---#endregion - ---#region Layout icons -local layout_path = gfilesystem.get_configuration_dir() .. 'src/assets/layout/' - -theme.layout_cornerne = layout_path .. 'cornerne.png' -theme.layout_cornernw = layout_path .. 'cornernw.png' -theme.layout_cornerse = layout_path .. 'cornerse.png' -theme.layout_cornersw = layout_path .. 'cornersw.png' -theme.layout_dwindle = layout_path .. 'dwindle.png' -theme.layout_fairh = layout_path .. 'fairh.png' -theme.layout_fairv = layout_path .. 'fairv.png' -theme.layout_floating = layout_path .. 'floating.png' -theme.layout_fullscreen = layout_path .. 'fullscreen.png' -theme.layout_magnifier = layout_path .. 'magnifier.png' -theme.layout_max = layout_path .. 'max.png' -theme.layout_spiral = layout_path .. 'spiral.png' -theme.layout_tile = layout_path .. 'tile.png' -theme.layout_tilebottom = layout_path .. 'tilebottom.png' -theme.layout_tileleft = layout_path .. 'tileleft.png' -theme.layout_tiletop = layout_path .. 'tiletop.png' ---#endregion - -theme.notification_spacing = dpi(20) --- Systray theme variables -theme.bg_systray = theme.colorscheme.bg1 -theme.systray_icon_spacing = dpi(10) - --- Wallpaper -beautiful.wallpaper = theme.user_config['wallpaper'] -capi.screen.connect_signal('request::wallpaper', function(s) - if beautiful.wallpaper then - if type(beautiful.wallpaper) == 'string' then - gwallpaper.maximized(beautiful.wallpaper, s) - else - beautiful.wallpaper(s) - end - end -end) - -beautiful.init(theme) - --- Load titlebar ---require('src.core.titlebar')() +return instance diff --git a/awesome/src/tools/parse_ical.lua b/awesome/src/tools/parse_ical.lua index 259cd08..e4f6bc9 100644 --- a/awesome/src/tools/parse_ical.lua +++ b/awesome/src/tools/parse_ical.lua @@ -8,18 +8,17 @@ local ical_calendar_cache = {} local date_time = {} setmetatable(date_time, { - __call = function(args) - local dt = table.copy(date_time) + __call = function(self, args) - dt.day = args.day or 1 - dt.month = args.month or 1 - dt.year = args.year or 1970 + self.day = args.day or 1 + self.month = args.month or 1 + self.year = args.year or 1970 - dt.hour = args.hour or 0 - dt.minute = args.minute or 0 - dt.second = args.second or 0 + self.hour = args.hour or 0 + self.minute = args.minute or 0 + self.second = args.second or 0 - return dt + return self end, __newindex = function(self, ...) if ... == 'weeknum' then @@ -29,53 +28,135 @@ setmetatable(date_time, { return self.weeknum end end, - __add = function(a, b) - local dt = table.copy(date_time) - if type(a) == 'table' and type(b) == 'table' then - - elseif type(a) == 'table' and type(b) == 'number' then - - else - error('Cannot add number with date') - end - end, - __sub = function(a, b) - - end, - __mul = function(a, b) - - end, - __div = function(a, b) - + __tostring = function(self) + return string.format('%d-%d-%d %d:%d:%d', self.year, self.month, self.day, self.hour, self.minute, self.second) end, }); local parser = {} -local instance = nil +function parser.VCALENDAR(handler) + local parse = {} + local line + while true do + line = handler:read('*l') + if not line then break end + local key, value = line:match('^(%w+):(.*)$') -function parser:VEVENT() + if key == 'END' then + return parse + end + if key == 'BEGIN' then + if value == 'VEVENT' then + parse[value] = parser.VEVENT(handler) + elseif value == 'VTIMEZONE' then + parse[value] = parser.VTIMEZONE(handler) + end + elseif key == 'VERSION' then + parse[key] = value + elseif key == 'PRODID' then + parse[key] = value + elseif key == 'CALSCALE' then + parse[key] = value + elseif key == 'METHOD' then + parse[key] = value + elseif key == 'X-WR-CALNAME' then + parse[key] = value + elseif key == 'X-WR-TIMEZONE' then + parse[key] = value + elseif key == 'X-WR-CALDESC' then + parse[key] = value + end + end end ----Start parsing a new calendar ----@param path string path to .ical file -function parser.parse(path) +function parser.VTIMEZONE(handler) + local parse = {} + local line + while true do + line = handler:read('*l') + if not line then break end + local key, value = line:match('^(%w+):(.*)$') - local ical_name = path + if key == 'END' then + return parse + end - -- Check if the calendar has been parsed previously - if ical_calendar_cache[ical_name] then - return ical_calendar_cache[ical_name] - else - -- If not create a new one in the cache - ical_calendar_cache[ical_name] = {} + if key == 'BEGIN' then + if value == 'DAYLIGHT' or value == 'STANDARD' then + parse[value] = parser.TZ(handler) + end + elseif key == 'TZID' then + parse[key] = value + elseif key == 'LAST-MODIFIED' then + parse[key] = value + elseif key == 'X-LIC-LOCATION' then + parse[key] = value + end end +end - return ical_calendar_cache[ical_name] +function parser.TZ(handler) + local parse = {} + local line + while true do + line = handler:read('*l') + if not line then break end + local key, value = line:match('^(%w+):(.*)$') + + if key == 'END' then + return parse + end + + if key == 'TZNAME' then + parse[key] = value + elseif key == 'TZOFFSETFROM' then + parse[key] = value + elseif key == 'TZOFFSETTO' then + parse[key] = value + elseif key == 'DTSTART' then + parse[key] = parse.DT(value) + elseif key == 'RRULE' then + parse[key] = parse.RRULE(value) + end + end +end + +function parser.VEVENT(handler) + local parse = {} + local line + + while true do + line = handler:read('*l') + if not line then break end + local key, value = line:match('^(%w+):(.*)$') + + if key == 'END' then + return parse + end + + if key == 'UID' then + parse[key] = value + elseif key == 'SEQUENCE' then + parse[key] = value + elseif key == 'SUMMARY' then + parse[key] = value + elseif key == 'LOCATION' then + parse[key] = value + elseif key == 'STATUS' then + parse[key] = value + elseif key == 'RRULE' then + parse[key] = parser.RRULE(value) + end + + + + end end function parser.new(path) + local cal = {} -- Get the file from the path local ical_name = path @@ -85,12 +166,27 @@ function parser.new(path) return ical_calendar_cache[ical_name] end - -- If not create a new one in the cache - ical_calendar_cache[ical_name] = { mt = {} } + local handler = io.open(path, 'r') + if not handler then return end + + while true do + local line = handler:read('*l') + if not line then break end + + local key, value = line:match('^(%w+):(.*)$') + if key and value then + if key == 'BEGIN' and value == 'VCALENDAR' then + cal[value] = parser.VCALENDAR(handler) + end + end + end + + handler:close() return ical_calendar_cache[ical_name] end +local instance = nil if not instance then instance = setmetatable(parser, { -- If this module is called load all cached calendars from the cache diff --git a/awesome/src/widgets/date.lua b/awesome/src/widgets/date.lua index 9c4c2fe..1b0137b 100644 --- a/awesome/src/widgets/date.lua +++ b/awesome/src/widgets/date.lua @@ -81,6 +81,7 @@ return setmetatable({}, { __call = function(_, screen) calendar_popup.x = geo.x - (calendar_popup.width / 2) end calendar_popup.visible = not calendar_popup.visible + collectgarbage('collect') end) ), }