2013-08-04 21:39:49 +00:00
-- Grab environment
local io = io
local os = os
local table = table
local type = type
local ipairs = ipairs
local pairs = pairs
2013-08-18 21:26:03 +00:00
local lgi = require ( ' lgi ' )
local Gtk = lgi.Gtk
2013-08-04 21:39:49 +00:00
module ( " freedesktop.utils " )
terminal = ' xterm '
icon_theme = nil
2013-08-18 21:26:03 +00:00
local gtk_icon_theme = Gtk.IconTheme . get_default ( )
2013-08-04 21:39:49 +00:00
all_icon_sizes = {
' 128x128 ' ,
' 96x96 ' ,
' 72x72 ' ,
' 64x64 ' ,
' 48x48 ' ,
' 36x36 ' ,
' 32x32 ' ,
' 24x24 ' ,
' 22x22 ' ,
2013-08-18 21:26:03 +00:00
' 16x16 ' ,
' 8x8 ' ,
' scalable '
2013-08-04 21:39:49 +00:00
}
all_icon_types = {
' apps ' ,
' actions ' ,
' devices ' ,
' places ' ,
' categories ' ,
' status ' ,
' mimetypes '
}
all_icon_paths = { os.getenv ( " HOME " ) .. ' /.icons/ ' , ' /usr/share/icons/ ' }
icon_sizes = { }
local mime_types = { }
function get_lines ( ... )
local f = io.popen ( ... )
return function ( ) -- iterator
local data = f : read ( )
if data == nil then f : close ( ) end
return data
end
end
function file_exists ( filename )
local file = io.open ( filename , ' r ' )
local result = ( file ~= nil )
if result then
file : close ( )
end
return result
end
function lookup_icon ( arg )
2013-08-18 21:26:03 +00:00
if arg.icon : sub ( 1 , 1 ) == ' / ' and ( arg.icon : find ( ' .+%.png ' ) or arg.icon : find ( ' .+%.xpm ' ) or arg.icon : find ( ' .+%.svg ' ) ) then
2013-08-04 21:39:49 +00:00
-- icons with absolute path and supported (AFAICT) formats
return arg.icon
else
2013-08-18 21:26:03 +00:00
local gtk_icon_info = Gtk.IconTheme . lookup_icon ( gtk_icon_theme , arg.icon , 48 , 0 )
if gtk_icon_info then
filename = Gtk.IconInfo . get_filename ( gtk_icon_info )
if filename then return filename end
end
2013-08-04 21:39:49 +00:00
local icon_path = { }
local icon_themes = { }
local icon_theme_paths = { }
if icon_theme and type ( icon_theme ) == ' table ' then
icon_themes = icon_theme
elseif icon_theme then
icon_themes = { icon_theme }
end
for i , theme in ipairs ( icon_themes ) do
for j , path in ipairs ( all_icon_paths ) do
table.insert ( icon_theme_paths , path .. theme .. ' / ' )
end
-- TODO also look in parent icon themes, as in freedesktop.org specification
end
table.insert ( icon_theme_paths , ' /usr/share/icons/hicolor/ ' ) -- fallback theme cf spec
local isizes = icon_sizes
for i , sz in ipairs ( all_icon_sizes ) do
table.insert ( isizes , sz )
end
for i , icon_theme_directory in ipairs ( icon_theme_paths ) do
for j , size in ipairs ( arg.icon_sizes or isizes ) do
for k , icon_type in ipairs ( all_icon_types ) do
table.insert ( icon_path , icon_theme_directory .. size .. ' / ' .. icon_type .. ' / ' )
end
end
end
-- lowest priority fallbacks
table.insert ( icon_path , ' /usr/share/pixmaps/ ' )
table.insert ( icon_path , ' /usr/share/icons/ ' )
table.insert ( icon_path , ' /usr/share/app-install/icons/ ' )
for i , directory in ipairs ( icon_path ) do
2013-08-18 21:26:03 +00:00
if ( arg.icon : find ( ' .+%.png ' ) or arg.icon : find ( ' .+%.xpm ' ) or arg.icon : find ( ' .+%.svg ' ) ) and file_exists ( directory .. arg.icon ) then
2013-08-04 21:39:49 +00:00
return directory .. arg.icon
elseif file_exists ( directory .. arg.icon .. ' .png ' ) then
return directory .. arg.icon .. ' .png '
elseif file_exists ( directory .. arg.icon .. ' .xpm ' ) then
return directory .. arg.icon .. ' .xpm '
2013-08-18 21:26:03 +00:00
elseif file_exists ( directory .. arg.icon .. ' .svg ' ) then
return directory .. arg.icon .. ' .svg '
2013-08-04 21:39:49 +00:00
end
end
end
end
function lookup_file_icon ( arg )
load_mime_types ( )
local extension = arg.filename : match ( ' %a+$ ' )
local mime = mime_types [ extension ] or ' '
local mime_family = mime : match ( ' ^%a+ ' ) or ' '
-- possible icons in a typical gnome theme (i.e. Tango icons)
local possible_filenames = {
mime ,
' gnome-mime- ' .. mime ,
mime_family ,
' gnome-mime- ' .. mime_family ,
extension
}
for i , filename in ipairs ( possible_filenames ) do
local icon = lookup_icon ( { icon = filename , icon_sizes = ( arg.icon_sizes or all_icon_sizes ) } )
if icon then
return icon
end
end
-- If we don't find ad icon, then pretend is a plain text file
return lookup_icon ( { icon = ' txt ' , icon_sizes = arg.icon_sizes or all_icon_sizes } )
end
--- Load system MIME types
-- @return A table with file extension <--> MIME type mapping
function load_mime_types ( )
if # mime_types == 0 then
for line in io.lines ( ' /etc/mime.types ' ) do
if not line : find ( ' ^# ' ) then
local parsed = { }
for w in line : gmatch ( ' [^%s]+ ' ) do
table.insert ( parsed , w )
end
if # parsed > 1 then
for i = 2 , # parsed do
mime_types [ parsed [ i ] ] = parsed [ 1 ] : gsub ( ' / ' , ' - ' )
end
end
end
end
end
end
--- Parse a .desktop file
-- @param file The .desktop file
-- @param requested_icon_sizes A list of icon sizes (optional). If this list is given, it will be used as a priority list for icon sizes when looking up for icons. If you want large icons, for example, you can put '128x128' as the first item in the list.
-- @return A table with file entries.
function parse_desktop_file ( arg )
local program = { show = true , file = arg.file }
for line in io.lines ( arg.file ) do
for key , value in line : gmatch ( " (%w+)=(.+) " ) do
program [ key ] = value
end
end
-- Don't show the program if NoDisplay is true
-- Only show the program if there is not OnlyShowIn attribute
-- or if it's equal to 'awesome'
if program.NoDisplay == " true " or program.OnlyShowIn ~= nil and program.OnlyShowIn ~= " awesome " then
program.show = false
end
-- Look up for a icon.
if program.Icon then
program.icon_path = lookup_icon ( { icon = program.Icon , icon_sizes = ( arg.icon_sizes or all_icon_sizes ) } )
if program.icon_path ~= nil and not file_exists ( program.icon_path ) then
program.icon_path = nil
end
end
-- Split categories into a table.
if program.Categories then
program.categories = { }
for category in program.Categories : gmatch ( ' [^;]+ ' ) do
table.insert ( program.categories , category )
end
end
if program.Exec then
local cmdline = program.Exec : gsub ( ' %%c ' , program.Name )
cmdline = cmdline : gsub ( ' %%[fmuFMU] ' , ' ' )
cmdline = cmdline : gsub ( ' %%k ' , program.file )
if program.icon_path then
cmdline = cmdline : gsub ( ' %%i ' , ' --icon ' .. program.icon_path )
else
cmdline = cmdline : gsub ( ' %%i ' , ' ' )
end
if program.Terminal == " true " then
cmdline = terminal .. ' -e ' .. cmdline
end
program.cmdline = cmdline
end
return program
end
--- Parse a directory with .desktop files
-- @param dir The directory.
-- @param icons_size, The icons sizes, optional.
-- @return A table with all .desktop entries.
function parse_desktop_files ( arg )
local programs = { }
local files = get_lines ( ' find ' .. arg.dir .. ' -name "*.desktop" 2>/dev/null ' )
for file in files do
arg.file = file
table.insert ( programs , parse_desktop_file ( arg ) )
end
return programs
end
--- Parse a directory files and subdirs
-- @param dir The directory.
-- @param icons_size, The icons sizes, optional.
-- @return A table with all .desktop entries.
function parse_dirs_and_files ( arg )
local files = { }
local paths = get_lines ( ' find ' .. arg.dir .. ' -maxdepth 1 -type d ' )
for path in paths do
if path : match ( " [^/]+$ " ) then
local file = { }
file.filename = path : match ( " [^/]+$ " )
file.path = path
file.show = true
file.icon = lookup_icon ( { icon = " folder " , icon_sizes = ( arg.icon_sizes or all_icon_sizes ) } )
table.insert ( files , file )
end
end
local paths = get_lines ( ' find ' .. arg.dir .. ' -maxdepth 1 -type f ' )
for path in paths do
if not path : find ( " %.desktop$ " ) then
local file = { }
file.filename = path : match ( " [^/]+$ " )
file.path = path
file.show = true
file.icon = lookup_file_icon ( { filename = file.filename , icon_sizes = ( arg.icon_sizes or all_icon_sizes ) } )
table.insert ( files , file )
end
end
return files
end