Files
crylia-theme/awesome/src/modules/application_launcher/application.lua

313 lines
11 KiB
Lua

--------------------------------------
-- This is the application launcher --
--------------------------------------
-- Awesome Libs
local awful = require("awful")
local Gio = require("lgi").Gio
local gfilesystem = require("gears").filesystem
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
local json = require("src.lib.json-lua.json-lua")
local cm = require("src.modules.context_menu")
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/context_menu/"
return function(s)
local application_grid = wibox.widget {
homogenous = true,
expand = false,
spacing = dpi(10),
id = "grid",
-- 200 is the application element width + 10 spacing
forced_num_cols = math.floor((capi.mouse.screen.geometry.width / 100 * 60) / (200)),
forced_num_rows = 7,
orientation = "vertical",
layout = wibox.layout.grid
}
-- Selected application position, default is first at 1,1
-- The typo *might* be intentional
local curser = {
x = 1,
y = 1
}
local filter = ""
---Executes only once to create a widget from each desktop file
---@return table widgets Unsorted widget table
local function get_applications_from_file()
local list = {}
local app_info = Gio.AppInfo
local apps = app_info.get_all()
for _, app in ipairs(apps) do
if app.should_show(app) then -- check no display
local desktop_app_info = Gio.DesktopAppInfo.new(app_info.get_id(app))
local app_widget = wibox.widget {
{
{
{
{
{ -- Icon
valign = "center",
halign = "center",
image = Get_gicon_path(app_info.get_icon(app)),
resize = true,
widget = wibox.widget.imagebox
},
height = dpi(64),
width = dpi(64),
strategy = "exact",
widget = wibox.container.constraint
},
{
{ -- Name
text = app_info.get_name(app),
align = "center",
valign = "center",
widget = wibox.widget.textbox
},
strategy = "exact",
width = dpi(170),
-- Prevents widget from overflowing
height = dpi(40),
widget = wibox.container.constraint
},
layout = wibox.layout.fixed.vertical
},
halign = "center",
valign = "center",
widget = wibox.container.place
},
margins = dpi(10),
widget = wibox.container.margin
},
name = app_info.get_name(app),
comment = Gio.DesktopAppInfo.get_string(desktop_app_info, "Comment") or "",
exec = Gio.DesktopAppInfo.get_string(desktop_app_info, "Exec"),
keywords = Gio.DesktopAppInfo.get_string(desktop_app_info, "Keywords") or "",
categories = Gio.DesktopAppInfo.get_categories(desktop_app_info) or "",
terminal = Gio.DesktopAppInfo.get_string(desktop_app_info, "Terminal") == "true",
actions = Gio.DesktopAppInfo.list_actions(desktop_app_info),
border_color = Theme_config.application_launcher.application.border_color,
border_width = Theme_config.application_launcher.application.border_width,
bg = Theme_config.application_launcher.application.bg,
fg = Theme_config.application_launcher.application.fg,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
widget = wibox.container.background
}
local context_menu = cm({
entries = {
{
name = "Execute as sudo",
icon = gears.color.recolor_image(icondir .. "launch.svg", Theme_config.context_menu.icon_color),
callback = function()
capi.awesome.emit_signal("application_launcher::show")
awful.spawn("/home/crylia/.config/awesome/src/scripts/start_as_admin.sh " .. app_widget.exec)
end
},
{
name = "Pin to dock",
icon = gears.color.recolor_image(icondir .. "pin.svg", Theme_config.context_menu.icon_color),
callback = function()
local dir = gears.filesystem.get_configuration_dir() .. "src/config"
gfilesystem.make_directories(dir)
if not gfilesystem.file_readable(dir) then
os.execute("touch " .. dir .. "/dock.json")
end
local handler = io.open("/home/crylia/.config/awesome/src/config/dock.json", "r")
if not handler then
return
end
local dock_table = json:decode(handler:read("a")) or {}
handler:close()
---@diagnostic disable-next-line: param-type-mismatch
table.insert(dock_table, {
name = app_widget.name or "",
icon = Get_gicon_path(app_info.get_icon(app)) or "",
comment = app_widget.comment or "",
exec = app_widget.exec or "",
keywords = app_widget.keywords or "",
categories = app_widget.categories or "",
terminal = app_widget.terminal or "",
actions = app_widget.actions or "",
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or ""
})
local dock_encoded = json:encode(dock_table)
handler = io.open("/home/crylia/.config/awesome/src/config/dock.json", "w")
if not handler then
return
end
handler:write(dock_encoded)
handler:close()
capi.awesome.emit_signal("dock::changed")
end
},
{
name = "Add to desktop",
icon = gears.color.recolor_image(icondir .. "desktop.svg", Theme_config.context_menu.icon_color),
callback = function()
capi.awesome.emit_signal("application_launcher::show")
--!TODO: Add to desktop
end
}
}
})
-- Execute command on left click and hide launcher
app_widget:buttons(
gears.table.join(
awful.button({
modifiers = {},
button = 1,
on_release = function()
Gio.AppInfo.launch_uris_async(app)
capi.awesome.emit_signal("application_launcher::show")
end
}),
awful.button({
modifiers = {},
button = 3,
on_release = function()
if not context_menu then
return
end
-- add offset so mouse is above widget, this is so the mouse::leave event triggers always
context_menu.x = capi.mouse.coords().x - 10
context_menu.y = capi.mouse.coords().y - 10
context_menu.visible = not context_menu.visible
end
})
)
)
Hover_signal(app_widget)
table.insert(list, app_widget)
end
end
return list
end
-- Table to hold all application widgets unsorted
local application_list = get_applications_from_file()
---Function to filter the applications and sort them into a widget grid
---@param search_filter string Filter string from the searchbar
---@return wibox.layout.grid wibox.layout.grid Sorted grid with all applications matching the filter
local function get_applications(search_filter)
filter = search_filter or filter
--Clear grid from previous widgets
application_grid:reset()
-- Reset to first position
curser = {
x = 1,
y = 1
}
for _, application in ipairs(application_list) do
-- Match the filter
if string.match(string.lower(application.name), string.lower(filter)) or
string.match(string.lower(application.categories), string.lower(filter)) or
string.match(string.lower(application.keywords), string.lower(filter)) then
application_grid:add(application)
-- Get the current position in the grid of the application as a table
local pos = application_grid:get_widget_position(application)
-- Check if the curser is currently at the same position as the application
capi.awesome.connect_signal(
"update::selected",
function()
if curser.y == pos.row and curser.x == pos.col then
application.border_color = Theme_config.application_launcher.application.border_color_active
else
application.border_color = Theme_config.application_launcher.application.border_color
end
end
)
capi.awesome.emit_signal("update::selected")
end
end
return application_grid
end
application_grid = get_applications(filter)
capi.awesome.connect_signal(
"application::left",
function()
curser.x = curser.x - 1
if curser.x < 1 then
curser.x = 1
end
capi.awesome.emit_signal("update::selected")
end
)
capi.awesome.connect_signal(
"application::right",
function()
curser.x = curser.x + 1
local _, grid_cols = application_grid:get_dimension()
if curser.x > grid_cols then
curser.x = grid_cols
end
capi.awesome.emit_signal("update::selected")
end
)
capi.awesome.connect_signal(
"application::up",
function()
curser.y = curser.y - 1
if curser.y < 1 then
curser.y = 1
end
capi.awesome.emit_signal("update::selected")
end
)
capi.awesome.connect_signal(
"application::down",
function()
curser.y = curser.y + 1
local grid_rows, _ = application_grid:get_dimension()
if curser.y > grid_rows then
curser.y = grid_rows
end
capi.awesome.emit_signal("update::selected")
end
)
capi.awesome.connect_signal(
"update::application_list",
function(f)
application_grid = get_applications(f)
end
)
capi.awesome.connect_signal(
"application_launcher::execute",
function()
capi.awesome.emit_signal("searchbar::stop")
local selected_widget = application_grid:get_widgets_at(curser.y, curser.x)[1]
Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0))
end
)
return application_grid
end