-- This file is part of Reno desktop. -- -- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -- -- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . -- Asynchronous XDG data aggregator local start_human = os.time() local start_computer = os.clock() local menu_utils = require("menubar.utils") local menu_gen = require("menubar.menu_gen") local awful = require("awful") local gears = require("gears") local json = require("dkjson") menu_utils.wm_name = "" -- Directories to scan for .desktop files local desktop_dirs = {} local desktop_dirs_complete = 0 local _ = ((table.concat(gears.filesystem.get_xdg_data_dirs(),":") or "/usr/share:/usr/local/share")..":"..os.getenv("HOME").."/.local/share"):gsub("[^:]*",function(path) if gears.filesystem.dir_readable(path.."/applications") then table.insert(desktop_dirs, path.."/applications") end end) -- Global xdg data struct _G.xdg = { directory_integrity = {}, directory_listings = {}, apps = {}, categories = { Other = { icon = "applications-other", apps = {} }, Wine = { icon = "wine", apps = {} } } } -- Load cached applications local cache_file = io.open(gears.filesystem.get_xdg_cache_home()..".reno_xdg_cache.json","r") local cache if cache_file then cache = json.decode(cache_file:read("*a")) cache_file:close() end -- Add missing category entries as defined by awesome for _,v in pairs(menu_gen.all_categories) do xdg.categories[v.app_type] = { name = v.name, icon = v.icon_name, apps = {} } end -- Asynchronous scanning process for _,v in pairs(desktop_dirs) do xdg.directory_listings[v] = {} awful.spawn.with_line_callback("find "..tostring(v).." -maxdepth 1 -name *.desktop",{ stdout = function(line) -- Assume the cache is valid for a listed file if cache and cache.directory_listings[v][line] then xdg.directory_listings[v][line] = true xdg.apps[line] = cache.apps[line] xdg.categories[cache.apps[line].category].apps[line] = cache.apps[line] return end local data = menu_utils.parse_desktop_file(line) if data.NoDisplay then return end local appdata = { name = data.Name, category = "Other", exec = data.Exec, icon = (data.Icon and menu_utils.lookup_icon(data.Icon)), description = data.Comment } -- Match first available cateogry for sorting for _,vv in pairs(data.Categories or {"Other"}) do if xdg.categories[vv] then appdata.category = vv break end -- Oh how do I love those Wine applications and their categories if vv:match("^Wine") then appdata.category = "Wine" break end end -- Open terminal apps in the terminal (duh) if data.Terminal then appdata.exec = global.terminal.." -e "..appdata.exec end -- Just for you, Wine - special case because you're being a shit if (appdata.exec and appdata.exec:find("%W?wine ")) then appdata.category = "Wine" end xdg.apps[line] = appdata xdg.categories[appdata.category].apps[line] = appdata -- Add the file to the listing of cached ones xdg.directory_listings[v][line] = true end, output_done = function() -- Save directory listing hash desktop_dirs_complete = desktop_dirs_complete + 1 -- Call a global signal awesome.emit_signal("xdg::dir_finished",v) end }) end local count = function(t) local n = 0 for _,_ in pairs(t) do n = n + 1 end return n end awesome.connect_signal("xdg::dir_finished",function(dir) -- We only send the all_finished signal when all directories finished processing if desktop_dirs_complete == #desktop_dirs then -- Clean up empty categories for k,v in pairs(xdg.categories) do if count(v.apps) == 0 then xdg.categories[k] = nil end end -- Save the cache if it doesn't exist yet io.open(gears.filesystem.get_xdg_cache_home()..".reno_xdg_cache.json","w"):write(json.encode(xdg)):close() require("naughty").notify({title = "Human time: "..tostring(os.time()-start_human),text = "Computer time: "..tostring(os.clock()-start_computer)}) -- Finally, call the all_finished signal awesome.emit_signal("xdg::all_finished") end end)