-------------------------------------- -- This is the application launcher -- -------------------------------------- -- Awesome Libs local awful = require("awful") local dpi = require("beautiful").xresources.apply_dpi local gears = require("gears") local wibox = require("wibox") local ical_parser = require("src.tools.ical_parser") local capi = { awesome = awesome, mouse = mouse, } local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/calendar/" --- Month name lookup table local months_table = { "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February", } --- Table to easily shift back every month by two months local month_convert = { 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, } --- Weekdays name lookup table local weekdays_table = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", } --- Create a date object from the current date local os_date = os.date("%d%m%Y") local date = { day = math.floor(os_date:sub(1, 2)), month = month_convert[math.floor(os_date:sub(3, 4))], year = math.floor(os_date:sub(5, 8)) } ---Calculates the weekday of a given date ---@param day number|string? as number, usually from date.da ---@param month number|string? as number, usually from date.month ---@param year number|string? as number, usually from date.year ---@return number|nil weekday as number local function get_date_weekday(day, month, year) if not (day and month and year) then return end if (month == 11) or (month == 12) then year = year - 1 end -- No idea how the algorithm works, but since it works -> don't touch it! local w = ((day + math.floor(2.6 * month - 0.2) - 2 * tonumber(tostring(year):match("([0-9]+)[0-9][0-9]")) + tonumber(tostring(year):match("[0-9][0-9]([0-9]+)")) + math.floor(tonumber(tostring(year):match("[0-9][0-9]([0-9]+)")) / 4) + math.floor(tonumber(tostring(year):match("([0-9]+)[0-9][0-9]")) / 4)) % 7) --TODO: Add user variable to choose between Sunday and Monday weekstart if w == 0 then w = 7 end return w end ---Returns the length of the month from a lookup table and also check for leap years ---@param month number? as number, usually from date.month, can also be a string ---@param year number? as number, usually from date.year, can also be a string ---@return integer|nil month_length as integer local function get_last_day_of_month(month, year) if not (month and year) then return end month = tonumber(month) local last_day = { 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, } --In this calculcation February is the 12th of last year if (month == 12) and (math.floor(year % 4) == 0) then return 29 else return last_day[month] end end ---Simple function to calculate how many weeks will need to be displayed in a calendar ---@param month number? as number, usually from date.month, can also be a string ---@param year number? as number, usually from date.year, can also be a string ---@return number|nil weeks ammount of weeks between 4-6 local function get_weeks_in_month(month, year) if not (month and year) then return end return math.ceil((get_last_day_of_month(month, year) + get_date_weekday(1, month, year) - 1) / 7) end ---Gets the last month and accounts for year changes ---@param d table date object ---@return table|nil date returns a date object local function get_last_month(d) if not (d) then return end if d.month == 1 then return { month = 12, year = d.year - 1 } else return { month = d.month - 1, year = d.year } end end ---Simple function to create a widget 7x for each day of the week ---@return table weeks_widget All weekdays names as a widget local function create_weekdays() local weekdays = { layout = wibox.layout.flex.horizontal } for i = 1, 7 do table.insert(weekdays, wibox.widget { { text = weekdays_table[i], align = "center", valign = "center", widget = wibox.widget.textbox, }, bg = Theme_config.calendar.weekdays.bg, fg = Theme_config.calendar.weekdays.fg, widget = wibox.container.background, }) end return weekdays end ---Create tasks from ical object ---@return table|nil tasks All tasks as a table local function create_tasks() if not ical_parser or not ical_parser.VCALENDAR then return end local tasks = {} --TODO: Initialize the timezone from ical.VCALENDAR.VTIMEZONE and make sure the time is correct -- Sort every VEVENT in ical by date into the tasks table. for _, calendar in ipairs(ical_parser.VCALENDAR) do for _, event in ipairs(calendar.VEVENT) do local start_time = event.DTSTART.DTSTART start_time.month = month_convert[start_time.month] local end_time if event.DTEND then end_time = event.DTEND.DTEND end_time.month = month_convert[end_time.month] end if event.RRULE then if event.RRULE.FREQ == "DAILY" then elseif event.RRULE.FREQ == "WEEKLY" then -- An event will always start on the day it first occurs. local event_start = start_time local event_end = event.RRULE.UNTIL local year_counter = event_start.year local month_counter = event_start.month if month_counter == 11 then year_counter = year_counter - 1 elseif month_counter == 12 then year_counter = year_counter - 1 end local day_counter = event_start.day local task = {} while (year_counter <= event_end.year) or (month_counter <= event_end.month) or (day_counter <= event_end.day) do -- First event will always be right since we start on its starting day task = { date_start = { year = year_counter, month = month_counter, day = day_counter, hour = event_start.hour or 0, minute = event_start.minute or 0, second = event_start.second or 0 }, date_end = { year = year_counter, month = month_counter, day = day_counter, hour = end_time.hour or 0, minute = end_time.minute or 0, second = end_time.second or 0 }, summary = event.SUMMARY, location = event.LOCATION, } if event.VALARM then task.alarm = { time = event.VALARM.TRIGGER.TRIGGER } local alarm_time = task.alarm.time:match("([-]?%d+)") local alarm_unit = task.alarm.time:match("(%a)") if alarm_unit == "W" then alarm_time = alarm_time * 604800 elseif alarm_unit == "D" then alarm_time = alarm_time * 86400 elseif alarm_unit == "H" then alarm_time = alarm_time * 3600 elseif alarm_unit == "M" then alarm_time = alarm_time * 60 end --[[ gears.timer { autostart = true, callback = function() if alarm_time then require("naughty").notification { app_name = "Task Alarm", title = task.summary, message = task.description, urgency = "normal", timeout = 5, icon = icondir .. "/alarm.png", } gears.timer:stop() end end } ]] end table.insert(tasks, task) day_counter = day_counter + 7 local month_length = get_last_day_of_month(month_counter, year_counter) if day_counter > month_length then day_counter = day_counter - month_length month_counter = month_counter + 1 end if month_counter == 11 then year_counter = year_counter + 1 end if month_counter > 13 then month_counter = 1 end end elseif event.RRULE.FREQ == "MONTHLY" then elseif event.RRULE.FREQ == "YEARLY" then if not end_time then end_time = { year = start_time.year + 1000, } end local task = {} for i = start_time.year, end_time.year, 1 do task = { date_start = { year = i, month = start_time.month, day = start_time.day, hour = start_time.hour or 0, minute = start_time.minute or 0, second = start_time.second or 0 }, date_end = { year = i, month = start_time.month, day = start_time.day, hour = end_time.hour or 0, minute = end_time.minute or 0, second = end_time.second or 0 }, summary = event.SUMMARY, location = event.LOCATION, description = event.DESCRIPTION, url = event.URL, } if event.VALARM then task.alarm = { time = event.VALARM.TRIGGER.TRIGGER } local alarm_time = task.alarm.time:match("([-]?%d+)") local alarm_unit = task.alarm.time:match("(%a)") if alarm_unit == "W" then alarm_time = alarm_time * 604800 elseif alarm_unit == "D" then alarm_time = alarm_time * 86400 elseif alarm_unit == "H" then alarm_time = alarm_time * 3600 elseif alarm_unit == "M" then alarm_time = alarm_time * 60 end --[[ gears.timer { timeout = os.time(task.date_start) - os.time() + alarm_time, autostart = true, callback = function() require("naughty").notification { app_name = "Task Alarm", title = task.summary, message = task.description, urgency = "normal", timeout = 5, icon = icondir .. "/alarm.png", } end } ]] end table.insert(tasks, task) end end else local task = { date_start = { year = start_time.year, month = start_time.month, day = start_time.day, hour = start_time.hour or 0, minute = start_time.minute or 0, second = start_time.second or 0 }, date_end = { year = start_time.year, month = start_time.month, day = start_time.day, hour = start_time.hour or 0, minute = start_time.minute or 0, second = start_time.second or 0 }, summary = event.SUMMARY, location = event.LOCATION, description = event.DESCRIPTION, url = event.URL, } if event.VALARM then task.alarm = { time = event.VALARM.TRIGGER.TRIGGER } local alarm_time = task.alarm.time:match("([-]?%d+)") local alarm_unit = task.alarm.time:match("(%a)") if alarm_unit == "W" then alarm_time = alarm_time * 604800 elseif alarm_unit == "D" then alarm_time = alarm_time * 86400 elseif alarm_unit == "H" then alarm_time = alarm_time * 3600 elseif alarm_unit == "M" then alarm_time = alarm_time * 60 end --[[ gears.timer { timeout = os.time(task.date_start) - os.time() + alarm_time, autostart = true, callback = function() require("naughty").notification { app_name = "Task Alarm", title = task.summary, message = task.description, urgency = "normal", timeout = 5, icon = icondir .. "/alarm.png", } end } ]] end table.insert(tasks, task) end end end return tasks end local tasks = create_tasks() local selected_day = { year = date.year, month = date.month, day = date.day, col = 1, row = 1, } return function(s) -- The calendar grid local calendar_matrix = wibox.widget { layout = wibox.layout.grid, spacing = dpi(2) } local weeks = wibox.widget { layout = wibox.layout.fixed.vertical } ---Main function to create the calendar widget ---Probably needs some refractor at some point since it's a bit messy ---@return wibox.widget calendar_widget local function create_calendar() calendar_matrix:reset() --- Months table holds every month with their starting week day, length(30/31 or 28/29), the last week day and the name local months = {} for m_num, month in ipairs(months_table) do months[m_num] = { name = month, first_day = get_date_weekday("01", m_num, date.year), length = get_last_day_of_month(m_num, date.year), last_day = get_date_weekday(get_last_day_of_month(m_num, date.year), m_num, date.year), weeks = get_weeks_in_month(m_num, date.year) } end local function get_tasks_for_day(day, month, year) if not tasks or #tasks == 0 then return end local tasks_layout = { layout = require("src.lib.overflow_widget.overflow").vertical, scrollbar_width = 0, step = dpi(50), spacing = dpi(2) } for _, task in ipairs(tasks) do if (task.date_start.year == year) and (task.date_start.month == month) and (task.date_start.day == day) then table.insert(tasks_layout, wibox.widget { { { text = task.summary, align = "left", halign = "center", font = "JetBrainsMono Nerd Font, bold 10", widget = wibox.widget.textbox }, margins = dpi(2), widget = wibox.container.margin }, fg = Theme_config.calendar.task.fg, bg = Theme_config.calendar.task.bg, shape = Theme_config.calendar.task.shape, forced_height = dpi(20), widget = wibox.container.background }) end end return tasks_layout end if months[date.month].first_day ~= 1 then -- Fill previous month days, i doubles as the day local column = 1 local last_month = get_last_month(date) local prev_month = date.month local prev_year = date.year if date.month == 1 then prev_month = 12 last_month = months[12].length else last_month = months[date.month - 1].length end if date.month == 11 then prev_year = date.year - 1 end prev_month = prev_month - 1 for i = last_month - months[date.month].first_day + 2, last_month, 1 do local border = Theme_config.calendar.day.border_color local bg = Theme_config.calendar.day.bg_unfocus local fg = Theme_config.calendar.day.fg_unfocus if column == selected_day.col and 1 == selected_day.row then border = Theme_config.calendar.day.today_border_color bg = Theme_config.calendar.day.today_bg_focus fg = Theme_config.calendar.day.today_fg_focus end local y = tonumber(os.date("%Y")) local m = month_convert[tonumber(os.date("%m"))] if m == 1 then m = 12 end if (i == date.day) and (m == prev_month) and (date.year == y) then bg = Theme_config.calendar.day.bg_focus fg = Theme_config.calendar.day.fg_focus end local day = wibox.widget { { { { { { { { -- Day widget = wibox.widget.textbox, align = "center", valign = "center", text = math.floor(i), id = "day_text", }, widget = wibox.container.margin, margins = dpi(2), }, id = "day_bg", widget = wibox.container.background, bg = bg, shape = Theme_config.calendar.day.shape, fg = fg, }, widget = wibox.container.place, valign = "center", halign = "center", }, { get_tasks_for_day(math.floor(i), prev_month, prev_year), widget = wibox.container.margin, margins = dpi(4) }, id = "tasks", spacing = dpi(4), layout = wibox.layout.fixed.vertical }, widget = wibox.container.margin, top = dpi(4) }, id = "background", widget = wibox.container.background, bg = Theme_config.calendar.day.bg_unfocus, fg = Theme_config.calendar.day.fg_unfocus, border_color = border, border_width = Theme_config.calendar.day.border_width, shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, dpi(8)) end }, widget = wibox.container.constraint, width = dpi(100), height = dpi(120), strategy = "exact" } -- update selected_day if the day is clicked day:buttons( gears.table.join( awful.button({}, 1, function() selected_day.col = column selected_day.row = 1 day:emit_signal("day::update_selected") end) ) ) day:connect_signal("day::update_selected", function() if column == selected_day.col and 1 == selected_day.row then capi.awesome.emit_signal("day::reset_border") day.background.border_color = Theme_config.calendar.day.today_border_color end end) capi.awesome.connect_signal("day::reset_border", function() day.background.border_color = Theme_config.calendar.day.border_color end) calendar_matrix:add_widget_at(day, 1, column) column = column + 1 end end --Actual month days local row = 1 local col = months[date.month].first_day for i = 1, months[date.month].length, 1 do local border = Theme_config.calendar.day.border_color local fg = Theme_config.calendar.day.fg local bg = Theme_config.calendar.day.bg if col == selected_day.col and row == selected_day.row then border = Theme_config.calendar.day.today_border_color end local m = month_convert[tonumber(os.date("%m"))] local y = tonumber(os.date("%Y")) if (i == date.day) and (date.month == m) and (date.year == y) then bg = Theme_config.calendar.day.bg_focus fg = Theme_config.calendar.day.fg_focus end local day = wibox.widget { { { { { { { { -- Day widget = wibox.widget.textbox, align = "center", valign = "center", text = math.floor(i), id = "day_text", }, widget = wibox.container.margin, margins = dpi(2), }, id = "day_bg", widget = wibox.container.background, bg = bg, shape = Theme_config.calendar.day.shape, fg = fg, }, widget = wibox.container.place, valign = "center", halign = "center", }, { get_tasks_for_day(math.floor(i), date.month, date.year), widget = wibox.container.margin, margins = dpi(4) }, id = "tasks", spacing = dpi(4), layout = wibox.layout.fixed.vertical }, widget = wibox.container.margin, top = dpi(4) }, id = "background", widget = wibox.container.background, bg = Theme_config.calendar.day.bg, fg = Theme_config.calendar.day.fg, border_color = border, border_width = Theme_config.calendar.day.border_width, shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, dpi(8)) end }, widget = wibox.container.constraint, width = dpi(100), height = dpi(120), strategy = "exact" } -- update selected_day if the day is clicked day:buttons( gears.table.join( awful.button({}, 1, function() selected_day.col = col selected_day.row = row day:emit_signal("day::update_selected") end) ) ) day:connect_signal("day::update_selected", function() if col == selected_day.col and row == selected_day.row then capi.awesome.emit_signal("day::reset_border") day.background.border_color = Theme_config.calendar.day.today_border_color end end) capi.awesome.connect_signal("day::reset_border", function() day.background.border_color = Theme_config.calendar.day.border_color end) calendar_matrix:add_widget_at(day, row, col) col = col + 1 if col == 8 then col = 1 row = row + 1 end end --next month local next_month = date.month if date.month == 12 then next_month = 1 else next_month = next_month + 1 end if months[date.month].last_day ~= 7 then for i = 1, 7 - months[date.month].last_day, 1 do local border = Theme_config.calendar.day.border_color local fg = Theme_config.calendar.day.fg_unfocus local bg = Theme_config.calendar.day.bg_unfocus if i == selected_day.col and months[date.month].weeks == selected_day.row then border = Theme_config.calendar.day.today_border_color end local m = month_convert[tonumber(os.date("%m")) + 1] if m == 13 then m = 1 end local y = tonumber(os.date("%Y")) if (i == date.day) and (next_month == m) and (date.year == y) then bg = Theme_config.calendar.day.bg_focus fg = Theme_config.calendar.day.fg_focus end local day = wibox.widget { { { { { { { { -- Day widget = wibox.widget.textbox, align = "center", valign = "center", text = math.floor(i), id = "day_text", }, widget = wibox.container.margin, margins = dpi(2), }, id = "day_bg", widget = wibox.container.background, bg = bg, shape = Theme_config.calendar.day.shape, fg = fg, }, widget = wibox.container.place, valign = "center", halign = "center", }, { get_tasks_for_day(math.floor(i), next_month, date.year), widget = wibox.container.margin, margins = dpi(4) }, id = "tasks", spacing = dpi(4), layout = wibox.layout.fixed.vertical }, widget = wibox.container.margin, top = dpi(4) }, id = "background", widget = wibox.container.background, bg = Theme_config.calendar.day.bg_unfocus, fg = Theme_config.calendar.day.fg_unfocus, border_color = border, border_width = Theme_config.calendar.day.border_width, shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, dpi(8)) end }, widget = wibox.container.constraint, width = dpi(100), height = dpi(120), strategy = "exact" } -- update selected_day if the day is clicked day:buttons( gears.table.join( awful.button({}, 1, function() selected_day.col = i selected_day.row = months[date.month].weeks day:emit_signal("day::update_selected") end) ) ) day:connect_signal("day::update_selected", function() if i == selected_day.col and months[date.month].weeks == selected_day.row then capi.awesome.emit_signal("day::reset_border") day.background.border_color = Theme_config.calendar.day.today_border_color end end) capi.awesome.connect_signal("day::reset_border", function() day.background.border_color = Theme_config.calendar.day.border_color end) calendar_matrix:add_widget_at(day, months[date.month].weeks, months[date.month].last_day + i) end end return calendar_matrix end local function create_calendar_week_num() weeks:reset() local actual_fucking_date = date.month + 2 if date.month == 11 then actual_fucking_date = 1 elseif date.month == 12 then actual_fucking_date = 2 end local start_week = actual_fucking_date * 4 - 3 local weeknum = actual_fucking_date * 4 - 3 if get_date_weekday("01", date.month, date.year) ~= 1 then weeknum = weeknum - 1 end if actual_fucking_date == 1 then weeknum = 52 end for i = start_week, start_week + get_weeks_in_month(date.month, date.year) - 1, 1 do weeks:add(wibox.widget { { { text = weeknum, id = "num", align = "center", valign = "top", widget = wibox.widget.textbox, }, id = "background", fg = Theme_config.calendar.day.fg_unfocus, widget = wibox.container.background, }, strategy = "exact", height = dpi(120), width = dpi(40), widget = wibox.container.constraint }) if weeknum == 52 then weeknum = 1 else weeknum = weeknum + 1 end end return weeks end --- Calendar widget local calendar = wibox.widget { { { { { { { { widget = wibox.widget.imagebox, resize = false, image = gears.color.recolor_image(icondir .. "add_ical.svg", Theme_config.calendar.add_ical.fg_focus), halign = "center", valign = "center" }, id = "add_ical", shape = Theme_config.calendar.add_ical.shape, bg = Theme_config.calendar.add_ical.bg, widget = wibox.container.background }, widget = wibox.container.margin, margins = dpi(4) }, { { { widget = wibox.widget.imagebox, resize = false, image = gears.color.recolor_image(icondir .. "add_task.svg", Theme_config.calendar.add_task.fg), halign = "center", valign = "center" }, id = "add_task", shape = Theme_config.calendar.add_task.shape, bg = Theme_config.calendar.add_task.bg, widget = wibox.container.background }, widget = wibox.container.margin, margins = dpi(4) }, layout = wibox.layout.fixed.vertical }, widget = wibox.container.constraint, strategy = "exact", height = dpi(75) }, create_calendar_week_num(), id = "weekdaysnum", layout = wibox.layout.fixed.vertical }, { { { --Header { -- Month switcher { -- Prev arrow widget = wibox.widget.imagebox, resize = true, image = icondir .. "chevron-left.svg", valign = "center", halign = "center", id = "prev_month", }, { { -- Month widget = wibox.widget.textbox, text = months_table[date.month], id = "month", valign = "center", align = "center" }, widget = wibox.container.constraint, strategy = "exact", width = dpi(150) }, { -- Next arrow widget = wibox.widget.imagebox, resize = true, image = icondir .. "chevron-right.svg", valign = "center", halign = "center", id = "next_month", }, layout = wibox.layout.fixed.horizontal }, nil, { -- Year switcher { -- Prev arrow widget = wibox.widget.imagebox, resize = true, image = icondir .. "chevron-left.svg", valign = "center", halign = "center", id = "prev_year" }, { { -- Month widget = wibox.widget.textbox, text = date.year, id = "year", valign = "center", align = "center" }, widget = wibox.container.constraint, strategy = "exact", width = dpi(150) }, { -- Next arrow widget = wibox.widget.imagebox, resize = true, image = icondir .. "chevron-right.svg", valign = "center", halign = "center", id = "next_year" }, layout = wibox.layout.fixed.horizontal }, layout = wibox.layout.align.horizontal }, widget = wibox.container.constraint, height = dpi(40), strategy = "exact" }, { -- Weekdays create_weekdays(), widget = wibox.container.background }, create_calendar(), id = "calendar", spacing = dpi(5), layout = wibox.layout.fixed.vertical }, id = "lay1", layout = wibox.layout.fixed.horizontal, }, widget = wibox.container.background, bg = Theme_config.calendar.bg, border_color = Theme_config.calendar.border_color, border_width = Theme_config.calendar.border_width, border_strategy = "inner", fg = Theme_config.calendar.fg, shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, dpi(4)) end } local add_ical = calendar:get_children_by_id("add_ical")[1] local add_task = calendar:get_children_by_id("add_task")[1] add_ical:buttons( gears.table.join( awful.button({}, 1, function() awful.spawn.easy_async_with_shell( "zenity --file-selection --title='Select an iCalendar file' --file-filter='iCalendar File | *.ics'", function(path_to_file) path_to_file = string.gsub(path_to_file, "\n", "") if not path_to_file then return end ical_parser.new(path_to_file) tasks = create_tasks() calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num() calendar:get_children_by_id("calendar")[1].children[3] = create_calendar() end ) end) ) ) Hover_signal(add_ical) Hover_signal(add_task) --- Popup that contains the calendar local cal_popup = awful.popup { widget = calendar, screen = s, ontop = true, bg = "#00000000", visible = false } --- Calendar switch month back calendar:get_children_by_id("prev_month")[1]:buttons( gears.table.join( awful.button({}, 1, function() date.month = date.month - 1 if date.month == 0 then date.month = 12 end if date.month == 10 then date.year = date.year - 1 end calendar:get_children_by_id("month")[1].text = months_table[date.month] calendar:get_children_by_id("year")[1].text = date.year calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num() calendar:get_children_by_id("calendar")[1].children[3] = create_calendar() end) ) ) --- Calendar switch month forward calendar:get_children_by_id("next_month")[1]:buttons( gears.table.join( awful.button({}, 1, function() date.month = date.month + 1 if date.month == 13 then date.month = 1 end if date.month == 11 then date.year = date.year + 1 end calendar:get_children_by_id("month")[1].text = months_table[date.month] calendar:get_children_by_id("year")[1].text = date.year calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num() calendar:get_children_by_id("calendar")[1].children[3] = create_calendar() end) ) ) --- Calendar switch year back calendar:get_children_by_id("prev_year")[1]:buttons( gears.table.join( awful.button({}, 1, function() date.year = date.year - 1 calendar:get_children_by_id("year")[1].text = date.year calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num() calendar:get_children_by_id("calendar")[1].children[3] = create_calendar() end) ) ) --- Calendar switch year forward calendar:get_children_by_id("next_year")[1]:buttons( gears.table.join( awful.button({}, 1, function() date.year = date.year + 1 calendar:get_children_by_id("year")[1].text = date.year calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num() calendar:get_children_by_id("calendar")[1].children[3] = create_calendar() end) ) ) --- Toggle calendar visibility capi.awesome.connect_signal("calendar::toggle", function(widget) if s == capi.mouse.screen then cal_popup.x = 3765 cal_popup.y = 60 cal_popup.visible = not cal_popup.visible end end) end