Finished work on application launcher and fixed some bugs + cleanup and documentation

This commit is contained in:
2022-11-28 05:43:47 +01:00
parent 10f56a7273
commit be25a16e3c
2 changed files with 254 additions and 236 deletions

View File

@@ -2,16 +2,18 @@
-- This is the application launcher -- -- This is the application launcher --
-------------------------------------- --------------------------------------
-- Awesome Libs -- Awesome libs
local awful = require("awful") local abutton = require("awful.button")
local Gio = require("lgi").Gio local aspawn = require("awful.spawn")
local gfilesystem = require("gears").filesystem
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local base = require("wibox.widget.base") local base = require("wibox.widget.base")
local dpi = require("beautiful").xresources.apply_dpi
local gcolor = require("gears.color")
local gfilesystem = require("gears").filesystem
local Gio = require("lgi").Gio
local gtable = require("gears.table") local gtable = require("gears.table")
local wibox = require("wibox")
-- Third party libs
local json = require("src.lib.json-lua.json-lua") local json = require("src.lib.json-lua.json-lua")
local cm = require("src.modules.context_menu.init") local cm = require("src.modules.context_menu.init")
@@ -20,10 +22,24 @@ local capi = {
mouse = mouse, mouse = mouse,
} }
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/context_menu/" local icondir = gfilesystem.get_configuration_dir() .. "src/assets/icons/context_menu/"
local application_grid = { mt = {} } local application_grid = { mt = {} }
--[[
Make sure that the config folder exists and the applications.json
This is done here once because it would be unnecessary to do it for every instance
]]
do
local dir = gfilesystem.get_configuration_dir() .. "src/config"
gfilesystem.make_directories(dir)
dir = dir .. "/applications.json"
if not gfilesystem.file_readable(dir) then
aspawn("touch " .. dir)
end
end
--#region wibox.widget.base boilerplate
function application_grid:layout(_, width, height) function application_grid:layout(_, width, height)
if self._private.widget then if self._private.widget then
return { base.place_widget_at(self._private.widget, 0, 0, width, height) } return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
@@ -44,6 +60,12 @@ function application_grid:get_widget()
return self._private.widget return self._private.widget
end end
--#endregion
--[[
Calculate the levenshtein distance between two strings to determine how similar they are
I stole this from a random github gist
]]
local function levenshtein_distance(str1, str2) local function levenshtein_distance(str1, str2)
local len1 = string.len(str1) local len1 = string.len(str1)
local len2 = string.len(str2) local len2 = string.len(str2)
@@ -85,12 +107,17 @@ local function levenshtein_distance(str1, str2)
return matrix[len1][len2] return matrix[len1][len2]
end end
function application_grid:get_applications_from_file() ---Gets all .desktop files found and filters them based on their visibility
---It used Gio.AppInfo and Gio.DesktopAppInfo to get the information
---@return table
local function get_applications_from_file()
local list = {} local list = {}
local app_info = Gio.AppInfo local app_info = Gio.AppInfo
--Get all .desktop files
local apps = app_info.get_all() local apps = app_info.get_all()
for _, app in ipairs(apps) do for _, app in ipairs(apps) do
if app.should_show(app) then -- check no display if app.should_show(app) then -- check no display
--Create a new .desktop object
local desktop_app_info = Gio.DesktopAppInfo.new(app_info.get_id(app)) local desktop_app_info = Gio.DesktopAppInfo.new(app_info.get_id(app))
local app_widget = wibox.widget { local app_widget = wibox.widget {
{ {
@@ -100,7 +127,9 @@ function application_grid:get_applications_from_file()
{ -- Icon { -- Icon
valign = "center", valign = "center",
halign = "center", halign = "center",
image = Get_gicon_path(app_info.get_icon(app)), image = Get_gicon_path(app_info.get_icon(app)) or
Get_gicon_path(app_info.get_icon(app),
Gio.DesktopAppInfo.get_string(desktop_app_info, "X-AppImage-Old-Icon")) or "",
resize = true, resize = true,
widget = wibox.widget.imagebox widget = wibox.widget.imagebox
}, },
@@ -138,17 +167,14 @@ function application_grid:get_applications_from_file()
categories = Gio.DesktopAppInfo.get_categories(desktop_app_info) or "", categories = Gio.DesktopAppInfo.get_categories(desktop_app_info) or "",
terminal = Gio.DesktopAppInfo.get_string(desktop_app_info, "Terminal") == "true", terminal = Gio.DesktopAppInfo.get_string(desktop_app_info, "Terminal") == "true",
actions = Gio.DesktopAppInfo.list_actions(desktop_app_info), actions = Gio.DesktopAppInfo.list_actions(desktop_app_info),
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "",
border_color = Theme_config.application_launcher.application.border_color, border_color = Theme_config.application_launcher.application.border_color,
border_width = Theme_config.application_launcher.application.border_width, border_width = Theme_config.application_launcher.application.border_width,
bg = Theme_config.application_launcher.application.bg, bg = Theme_config.application_launcher.application.bg,
fg = Theme_config.application_launcher.application.fg, fg = Theme_config.application_launcher.application.fg,
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "", shape = Theme_config.application_launcher.application.shape,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
widget = wibox.container.background widget = wibox.container.background
} }
local context_menu = cm { local context_menu = cm {
widget_template = wibox.widget { widget_template = wibox.widget {
{ {
@@ -183,34 +209,33 @@ function application_grid:get_applications_from_file()
entries = { entries = {
{ {
name = "Execute as sudo", name = "Execute as sudo",
icon = gears.color.recolor_image(icondir .. "launch.svg", icon = gcolor.recolor_image(icondir .. "launch.svg",
Theme_config.application_launcher.application.cm_icon_color), Theme_config.application_launcher.application.cm_icon_color),
callback = function() callback = function()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
awful.spawn("/home/crylia/.config/awesome/src/scripts/start_as_admin.sh " .. app_widget.exec) aspawn("/home/crylia/.config/awesome/src/scripts/start_as_admin.sh " .. app_widget.exec)
end end
}, },
{ {
name = "Pin to dock", name = "Pin to dock",
icon = gears.color.recolor_image(icondir .. "pin.svg", icon = gcolor.recolor_image(icondir .. "pin.svg",
Theme_config.application_launcher.application.cm_icon_color), Theme_config.application_launcher.application.cm_icon_color),
callback = function() callback = function()
local dir = gears.filesystem.get_configuration_dir() .. "src/config" -- Open dock.js and read all its content into a table, add the new app into the table and write it back
gfilesystem.make_directories(dir) local file_path = gfilesystem.get_configuration_dir() .. "src/config/dock.json"
if not gfilesystem.file_readable(dir) then local handler = io.open(file_path, "r")
os.execute("touch " .. dir .. "/dock.json") if not handler then return end
end
local handler = io.open(dir .. "/dock.json", "r") local dock_table = json:decode(handler:read("a")) or {}
if not handler then
return handler:close()
end assert(type(dock_table) == "table", "dock_table is not a table")
local dock_table = json:decode(handler:read("a")) or {}
handler:close()
---@diagnostic disable-next-line: param-type-mismatch
table.insert(dock_table, { table.insert(dock_table, {
name = app_widget.name or "", name = app_widget.name or "",
icon = Get_gicon_path(app_info.get_icon(app)) or "", icon = Get_gicon_path(app_info.get_icon(app)) or
Get_gicon_path(app_info.get_icon(app),
Gio.DesktopAppInfo.get_string(desktop_app_info, "X-AppImage-Old-Icon")) or "",
comment = app_widget.comment or "", comment = app_widget.comment or "",
exec = app_widget.exec or "", exec = app_widget.exec or "",
keywords = app_widget.keywords or "", keywords = app_widget.keywords or "",
@@ -219,11 +244,12 @@ function application_grid:get_applications_from_file()
actions = app_widget.actions or "", actions = app_widget.actions or "",
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "" desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or ""
}) })
local dock_encoded = json:encode(dock_table) local dock_encoded = json:encode(dock_table)
handler = io.open("/home/crylia/.config/awesome/src/config/dock.json", "w") handler = io.open(file_path, "w")
if not handler then
return if not handler then return end
end
handler:write(dock_encoded) handler:write(dock_encoded)
handler:close() handler:close()
capi.awesome.emit_signal("dock::changed") capi.awesome.emit_signal("dock::changed")
@@ -231,7 +257,7 @@ function application_grid:get_applications_from_file()
}, },
{ {
name = "Add to desktop", name = "Add to desktop",
icon = gears.color.recolor_image(icondir .. "desktop.svg", icon = grecolor_image(icondir .. "desktop.svg",
Theme_config.application_launcher.application.cm_icon_color), Theme_config.application_launcher.application.cm_icon_color),
callback = function() callback = function()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
@@ -246,23 +272,23 @@ function application_grid:get_applications_from_file()
} }
} }
-- Hide context menu when the mouse leaves it
context_menu:connect_signal("mouse::leave", function() context_menu:connect_signal("mouse::leave", function()
context_menu.visible = false context_menu.visible = false
end) end)
-- Execute command on left click and hide launcher -- Execute command on left click and hide launcher, right click to show context menu
app_widget:buttons( app_widget:buttons(
gears.table.join( gtable.join(
awful.button({ abutton({
modifiers = {}, modifiers = {},
button = 1, button = 1,
on_release = function() on_release = function()
Gio.AppInfo.launch_uris_async(app) Gio.AppInfo.launch_uris_async(app)
--!Change!
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
end end
}), }),
awful.button({ abutton({
modifiers = {}, modifiers = {},
button = 3, button = 3,
on_release = function() on_release = function()
@@ -271,13 +297,16 @@ function application_grid:get_applications_from_file()
}) })
) )
) )
Hover_signal(app_widget) Hover_signal(app_widget)
table.insert(list, app_widget) table.insert(list, app_widget)
end end
end end
self.app_list = list return list
end end
---Takes the search filter and returns a list of applications in the correct order
---@param search_filter any
function application_grid:set_applications(search_filter) function application_grid:set_applications(search_filter)
local filter = search_filter or self.filter or "" local filter = search_filter or self.filter or ""
-- Reset to first position -- Reset to first position
@@ -292,30 +321,34 @@ function application_grid:set_applications(search_filter)
spacing = dpi(10), spacing = dpi(10),
id = "grid", id = "grid",
-- 200 is the application element width + 10 spacing -- 200 is the application element width + 10 spacing
forced_num_cols = math.floor((capi.mouse.screen.geometry.width / 100 * 60) / (200)), forced_num_cols = math.floor((capi.mouse.screen.geometry.width / 100 * 60) / 200),
forced_num_rows = 7, forced_num_rows = 7,
orientation = "vertical", orientation = "vertical",
layout = wibox.layout.grid layout = wibox.layout.grid
} }
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json" -- Read the dock.json file and get all apps, these are needed to read/write the launch count
if not gfilesystem.file_readable(dir) then return end local handler = io.open(gfilesystem.get_configuration_dir() .. "src/config/applications.json", "r")
local handler = io.open(dir, "r")
if not handler then return end if not handler then return end
local dock_encoded = handler:read("a") or "{}" local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded) local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
assert(type(dock) == "table", "dock is not a table")
local mylist = {} local mylist = {}
for _, application in ipairs(self.app_list) do for _, application in ipairs(self.app_list) do
-- Match the filter -- Match the filter for the name, categories and keywords
if string.match(string.lower(application.name or ""), string.lower(filter)) or if string.match(string.lower(application.name or ""), string.lower(filter)) or
string.match(string.lower(application.categories or ""), string.lower(filter)) or string.match(string.lower(application.categories or ""), string.lower(filter)) or
string.match(string.lower(application.keywords or ""), string.lower(filter)) then string.match(string.lower(application.keywords or ""), string.lower(filter)) then
-- If there are no elements in the table, set everything to 0
if #dock == 0 then if #dock == 0 then
application.counter = 0 application.counter = 0
end end
-- Read the counter for the matching app
for _, app in ipairs(dock) do for _, app in ipairs(dock) do
if app.desktop_file == application.desktop_file then if app.desktop_file == application.desktop_file then
application.counter = app.counter or 0 application.counter = app.counter or 0
@@ -329,14 +362,16 @@ function application_grid:set_applications(search_filter)
end end
end end
-- Sort the applications using the levenshtein algorithm
table.sort(mylist, function(a, b) table.sort(mylist, function(a, b)
return levenshtein_distance(filter, a.name) < levenshtein_distance(filter, b.name) return levenshtein_distance(filter, a.name) < levenshtein_distance(filter, b.name)
end) end)
--sort mytable by counter --Sort the applications using the counter
table.sort(mylist, function(a, b) table.sort(mylist, function(a, b)
return a.counter > b.counter return a.counter > b.counter
end) end)
-- Add the apps one by one into the grid and read its position
for _, app in ipairs(mylist) do for _, app in ipairs(mylist) do
grid:add(app) grid:add(app)
@@ -360,6 +395,7 @@ function application_grid:set_applications(search_filter)
self:set_widget(grid) self:set_widget(grid)
end end
-- Move the curser up by one, making sure it doesn't go out of bounds
function application_grid:move_up() function application_grid:move_up()
self._private.curser.y = self._private.curser.y - 1 self._private.curser.y = self._private.curser.y - 1
if self._private.curser.y < 1 then if self._private.curser.y < 1 then
@@ -368,6 +404,7 @@ function application_grid:move_up()
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
end end
-- Move the curser down by one, making sure it doesn't go out of bounds
function application_grid:move_down() function application_grid:move_down()
self._private.curser.y = self._private.curser.y + 1 self._private.curser.y = self._private.curser.y + 1
local grid_rows, _ = self:get_widget():get_dimension() local grid_rows, _ = self:get_widget():get_dimension()
@@ -377,6 +414,7 @@ function application_grid:move_down()
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
end end
-- Move the curser left by one, making sure it doesn't go out of bounds
function application_grid:move_left() function application_grid:move_left()
self._private.curser.x = self._private.curser.x - 1 self._private.curser.x = self._private.curser.x - 1
if self._private.curser.x < 1 then if self._private.curser.x < 1 then
@@ -385,6 +423,7 @@ function application_grid:move_left()
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
end end
-- Move the curser right by one, making sure it doesn't go out of bounds
function application_grid:move_right() function application_grid:move_right()
self._private.curser.x = self._private.curser.x + 1 self._private.curser.x = self._private.curser.x + 1
local _, grid_cols = self:get_widget():get_dimension() local _, grid_cols = self:get_widget():get_dimension()
@@ -394,22 +433,28 @@ function application_grid:move_right()
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
end end
--- Execute the currently selected app and add to the launch count
function application_grid:execute() function application_grid:execute()
-- Get the app at the current x,y
local selected_widget = self:get_widget():get_widgets_at(self._private.curser.y, local selected_widget = self:get_widget():get_widgets_at(self._private.curser.y,
self._private.curser.x)[1] self._private.curser.x)[1]
-- Launch the application async
Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0)) Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0))
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json" local file_path = gfilesystem.get_configuration_dir() .. "src/config/applications.json"
if not gfilesystem.file_readable(dir) then return end local handler = io.open(file_path, "r")
local handler = io.open(dir, "r")
if not handler then return end if not handler then return end
local dock_encoded = handler:read("a") or "{}" local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded) local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
assert(type(dock) == "table", "dock is not a table")
-- Increase the counter by one then rewrite to the file, its a bit hacky but it works
for _, prog in ipairs(dock) do for _, prog in ipairs(dock) do
if prog.desktop_file:match(selected_widget.desktop_file) then if prog.desktop_file:match(selected_widget.desktop_file) then
prog.counter = prog.counter + 1 prog.counter = prog.counter + 1
-- I don't like goto's, but its the easiest way here(PR is welcome).
goto continue goto continue
end end
end end
@@ -423,12 +468,13 @@ function application_grid:execute()
end end
::continue:: ::continue::
handler:close() handler:close()
handler = io.open(dir, "w") handler = io.open(file_path, "w")
if not handler then return end if not handler then return end
handler:write(json:encode_pretty(dock)) handler:write(json:encode_pretty(dock))
handler:close() handler:close()
end end
-- Reset the grid cursor
function application_grid:reset() function application_grid:reset()
self._private.curser = { self._private.curser = {
x = 1, x = 1,
@@ -444,20 +490,7 @@ function application_grid.new(args)
gtable.crush(w, application_grid, true) gtable.crush(w, application_grid, true)
w._private.curser = { w.app_list = get_applications_from_file()
x = 1,
y = 1
}
-- Create folder and file if it doesn't exist
local dir = gfilesystem.get_configuration_dir() .. "src/config"
gfilesystem.make_directories(dir)
dir = dir .. "/applications.json"
if not gfilesystem.file_readable(dir) then
os.execute("touch " .. dir)
end
w:get_applications_from_file()
w:set_applications() w:set_applications()
return w return w

View File

@@ -3,47 +3,98 @@
-------------------------------------- --------------------------------------
-- Awesome Libs -- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local gshape = require("gears.shape")
local gtable = require("gears.table")
local gobject = require("gears.object")
local abutton = require("awful.button") local abutton = require("awful.button")
local akeygrabber = require("awful.keygrabber")
local aplacement = require("awful.placement")
local apopup = require("awful.popup")
local awidget = require("awful.widget")
local dpi = require("beautiful").xresources.apply_dpi
local gtable = require("gears.table")
local wibox = require("wibox")
-- Own libs
local app_grid = require("src.modules.application_launcher.application")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
mouse = mouse, mouse = mouse,
} }
-- This grid object is shared to avoid having multipe unnecessary instances
local application_grid = app_grid {}
local application_launcher = { mt = {} } local application_launcher = { mt = {} }
application_launcher.application_grid = require("src.modules.application_launcher.application") {}
function application_launcher.new(args) function application_launcher.new(args)
args = args or {} args = args or {}
local ret = gobject { enable_properties = true } -- Create a new inputbox
local searchbar = awidget.inputbox {
gtable.crush(ret, application_launcher, true)
local searchbar = awful.widget.inputbox {
hint_text = "Search...", hint_text = "Search...",
valign = "center", valign = "center",
halign = "left", halign = "left",
} }
searchbar:buttons( -- Application launcher popup
gtable.join { local application_container = apopup {
widget = {
{
{
{
{
{
searchbar,
widget = wibox.container.margin,
margins = 5,
},
widget = wibox.container.constraint,
strategy = "exact",
height = dpi(50),
},
widget = wibox.container.background,
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
shape = Theme_config.application_launcher.searchbar.shape,
id = "searchbar_bg"
},
{
application_grid,
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
step = dpi(100),
},
spacing = dpi(10),
layout = wibox.layout.fixed.vertical
},
margins = dpi(20),
widget = wibox.container.margin
},
height = args.screen.geometry.height / 100 * 60,
strategy = "exact",
widget = wibox.container.constraint,
},
ontop = true,
visible = false,
stretch = false,
screen = args.screen,
placement = aplacement.centered,
bg = Theme_config.application_launcher.bg,
border_color = Theme_config.application_launcher.border_color,
border_width = Theme_config.application_launcher.border_width
}
gtable.crush(application_container, application_launcher, true)
-- Focus the searchbar when its left clicked
searchbar:buttons(gtable.join {
abutton({}, 1, function() abutton({}, 1, function()
searchbar:focus() searchbar:focus()
end) end)
} })
)
--#region Hover signals to change the cursor to a text cursor
local old_cursor, old_wibox local old_cursor, old_wibox
searchbar:connect_signal("mouse::enter", function() searchbar:connect_signal("mouse::enter", function()
local wid = capi.mouse.current_wibox local wid = capi.mouse.current_wibox
@@ -56,168 +107,102 @@ function application_launcher.new(args)
old_wibox.cursor = old_cursor old_wibox.cursor = old_cursor
old_wibox = nil old_wibox = nil
end) end)
--#endregion
local applicaton_launcher = wibox.widget { -- Get a reference to the searchbar background value
{ local searchbar_bg = application_container.widget:get_children_by_id("searchbar_bg")[1]
{
{
{
{
searchbar,
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
shape = gshape.rounded_rect,
id = "searchbar_bg"
},
{
ret.application_grid,
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
step = dpi(100),
id = "scroll_bar",
},
spacing = dpi(10),
layout = wibox.layout.fixed.vertical
},
margins = dpi(20),
widget = wibox.container.margin
},
height = args.screen.geometry.height / 100 * 60,
--width = s.geometry.width / 100 * 60,
strategy = "exact",
widget = wibox.container.constraint
}
ret.application_container = awful.popup { -- Toggle visible for the application launcher and init the searchbar
widget = applicaton_launcher, capi.awesome.connect_signal("application_launcher::show", function()
ontop = true, if capi.mouse.screen == args.screen then
visible = false,
stretch = false,
screen = args.screen,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end,
placement = awful.placement.centered,
bg = Theme_config.application_launcher.bg,
border_color = Theme_config.application_launcher.border_color,
border_width = Theme_config.application_launcher.border_width
}
local searchbar_bg = applicaton_launcher:get_children_by_id("searchbar_bg")[1]
capi.awesome.connect_signal(
"application_launcher::show",
function()
capi.awesome.emit_signal("update::selected") capi.awesome.emit_signal("update::selected")
if capi.mouse.screen == args.screen then if capi.mouse.screen == args.screen then
ret.application_container.visible = not ret.application_container.visible application_container.visible = not application_container.visible
end end
if ret.application_container.visible then if application_container.visible then
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar:focus() searchbar:focus()
else else
searchbar:set_text("") searchbar:set_text("")
awful.keygrabber.stop() akeygrabber.stop()
end end
end end
) end)
searchbar:connect_signal( -- Execute the currently selected application, reset the searchbar and hide the launcher
"submit", searchbar:connect_signal("submit", function(_, text)
function(_, text) application_grid:execute()
ret.application_grid:execute()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text()) application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end)
)
searchbar:connect_signal( -- Hide the application launcher when the keygrabber stops and reset the searchbar
"stopped", searchbar:connect_signal("stopped", function(_, stop_key)
function(_, stop_key)
if stop_key == "Escape" then if stop_key == "Escape" then
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
end end
searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text()) application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end)
)
searchbar:connect_signal( -- When started change the background for the searchbar
"started", searchbar:connect_signal("started", function()
function()
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
end end)
)
searchbar:connect_signal( -- On every keypress in the searchbar check for certain inputs
"inputbox::key_pressed", searchbar:connect_signal("inputbox::key_pressed", function(_, modkey, key)
function(_, modkey, key) if key == "Escape" then -- Escape to stop the keygrabber, hide the launcher and reset the searchbar
if key == "Escape" then
searchbar:stop() searchbar:stop()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() application_grid:reset()
searchbar:set_text("") searchbar:set_text("")
elseif key == "Down" or key == "Right" then elseif key == "Down" or key == "Right" then --If down or right is pressed initiate the grid navigation
if key == "Down" then if key == "Down" then
ret.application_grid:move_down() application_grid:move_down()
elseif key == "Right" then elseif key == "Right" then
ret.application_grid:move_right() application_grid:move_right()
end end
searchbar:stop() searchbar:stop()
awful.keygrabber.run(function(mod, key2, event) --New keygrabber to allow for key navigation
akeygrabber.run(function(mod, key2, event)
if event == "press" then if event == "press" then
if key2 == "Down" then if key2 == "Down" then
ret.application_grid:move_down() application_grid:move_down()
elseif key2 == "Up" then elseif key2 == "Up" then
local old_y = ret.application_grid._private.curser.y local old_y = application_grid._private.curser.y
ret.application_grid:move_up() application_grid:move_up()
if old_y - ret.application_grid._private.curser.y == 0 then if old_y - application_grid._private.curser.y == 0 then
searchbar:focus() searchbar:focus()
end end
elseif key2 == "Left" then elseif key2 == "Left" then
ret.application_grid:move_left() application_grid:move_left()
elseif key2 == "Right" then elseif key2 == "Right" then
ret.application_grid:move_right() application_grid:move_right()
elseif key2 == "Return" then elseif key2 == "Return" then
awful.keygrabber.stop() akeygrabber.stop()
ret.application_grid:execute() application_grid:execute()
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() application_grid:reset()
searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text()) application_grid:set_applications(searchbar:get_text())
elseif key2 == "Escape" then elseif key2 == "Escape" then
capi.awesome.emit_signal("application_launcher::show") capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset() application_grid:reset()
searchbar:set_text("") searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text()) application_grid:set_applications(searchbar:get_text())
awful.keygrabber.stop() akeygrabber.stop()
end end
end end
end) end)
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end end
ret.application_grid:set_applications(searchbar:get_text()) -- Update the applications in the grid
end application_grid:set_applications(searchbar:get_text())
) end)
return ret
end end
function application_launcher.mt:__call(...) function application_launcher.mt:__call(...)