Okay, the second try.

I skimmed through Freedesktop's standards about .desktop files and icons themes/locations and added the respective notices in the utils.lua. About JPG icons: jpg format is not supported by the specification. Only png, xpf and svg; but svg is not supported by Awesome so this leaves us only with two of them.

I left utils.lua where it was. If someone decides to write something that uses it then with the context of his work we could put make it more general. Now I can't think of a place to move it to.

Best regards,
Alexander
>From adef4a4b5fa2ddfb7911fe590d3978fb259b3db1 Mon Sep 17 00:00:00 2001
From: Alexander Yakushev <[email protected]>
Date: Thu, 1 Mar 2012 19:01:23 +0200
Subject: [PATCH 1/3] awful.prompt: Move update() out of the keygrabber.run
 callback

It is required to be able to call the update() function from any point
of the keygrabber.run callback.
---
 lib/awful/prompt.lua.in |   18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/lib/awful/prompt.lua.in b/lib/awful/prompt.lua.in
index 61f777b..5d294ae 100644
--- a/lib/awful/prompt.lua.in
+++ b/lib/awful/prompt.lua.in
@@ -202,6 +202,15 @@ function run(args, textbox, exe_callback, completion_callback, history_path, his
         if done_callback then done_callback() end
     end
 
+    -- Update textbox
+    local function update()
+        textbox:set_font(font)
+        textbox:set_markup(prompt_text_with_cursor{
+                               text = command, text_color = inv_col, cursor_color = cur_col,
+                               cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
+                               prompt = prettyprompt })
+    end
+
     capi.keygrabber.run(
     function (modifiers, key, event)
         if event ~= "press" then return end
@@ -406,15 +415,6 @@ function run(args, textbox, exe_callback, completion_callback, history_path, his
             selectall = nil
         end
 
-        -- Update textbox
-        local function update()
-            textbox:set_font(font)
-            textbox:set_markup(prompt_text_with_cursor{
-                text = command, text_color = inv_col, cursor_color = cur_col,
-                cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
-                prompt = prettyprompt })
-        end
-
         local success = pcall(update)
         while not success do
             -- TODO UGLY HACK TODO
-- 
1.7.9.2

>From 0ec307b3626d954ae08faf526e20d8a0025f509f Mon Sep 17 00:00:00 2001
From: Alexander Yakushev <[email protected]>
Date: Thu, 1 Mar 2012 19:33:22 +0200
Subject: [PATCH 2/3] awful.prompt: Introduce changed_callback and
 keypressed_callback to prompt.run

changed_callback allows to execute arbitrary code any time the
command string changes.
keypressed_callback allows to intercept keypresses before
awful.prompt.run code handles them and run arbitrary code depending on
the key pressed and modificators.
---
 lib/awful/prompt.lua.in |   34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/lib/awful/prompt.lua.in b/lib/awful/prompt.lua.in
index 5d294ae..fd4c0ee 100644
--- a/lib/awful/prompt.lua.in
+++ b/lib/awful/prompt.lua.in
@@ -163,7 +163,9 @@ end
 -- @param history_path Optional parameter: file path where the history should be saved, set nil to disable history
 -- @param history_max Optional parameter: set the maximum entries in history file, 50 by default
 -- @param done_callback Optional parameter: the callback function to always call without arguments, regardless of whether the prompt was cancelled.
-function run(args, textbox, exe_callback, completion_callback, history_path, history_max, done_callback)
+-- @param changed_callback Optional parameter: the callback function to call with command as argument when a command was changed.
+-- @param keypressed_callback Optional parameter: the callback function to call with mod table, key and command as arguments when a key was pressed.
+function run(args, textbox, exe_callback, completion_callback, history_path, history_max, done_callback, changed_callback, keypressed_callback)
     local theme = beautiful.get()
     if not args then args = {} end
     local command = args.text or ""
@@ -217,6 +219,31 @@ function run(args, textbox, exe_callback, completion_callback, history_path, his
         -- Convert index array to hash table
         local mod = {}
         for k, v in ipairs(modifiers) do mod[v] = true end
+
+        -- Call the user specified callback. If it returns true as
+        -- the first result then return from the function. Treat the
+        -- second and third results as a new command and new prompt
+        -- to be set (if provided)
+        if keypressed_callback then
+            local user_catched, new_command, new_prompt =
+                keypressed_callback(mod, key, command)
+            if new_command or new_prompt then
+                if new_command then
+                    command = new_command
+                end
+                if new_prompt then
+                    prettyprompt = new_prompt
+                end
+                update()
+            end
+            if user_catched then
+                if changed_callback then
+                    changed_callback(command)
+                end
+                return true
+            end
+        end
+
         -- Get out cases
         if (mod.Control and (key == "c" or key == "g"))
             or (not mod.Control and key == "Escape") then
@@ -430,6 +457,11 @@ function run(args, textbox, exe_callback, completion_callback, history_path, his
             cur_pos = cur_pos - 1
             success = pcall(update)
         end
+
+        if changed_callback then
+            changed_callback(command)
+        end
+        return true
     end)
 end
 
-- 
1.7.9.2

>From b968f89a3b726210842262f1f705bf315650f7c1 Mon Sep 17 00:00:00 2001
From: Alexander Yakushev <[email protected]>
Date: Sun, 4 Mar 2012 16:14:33 +0200
Subject: [PATCH 3/3] menubar: Introduce menubar extension

Menubar is a dmenu-like applications menu extension for Awesome. It
parses .desktop files in the user-specified folders and builds a menu
from them.
---
 awesomerc.lua.in            |    5 +-
 lib/menubar/init.lua.in     |  272 +++++++++++++++++++++++++++++++++++++++++++
 lib/menubar/menu_gen.lua.in |  117 +++++++++++++++++++
 lib/menubar/utils.lua.in    |  190 ++++++++++++++++++++++++++++++
 4 files changed, 583 insertions(+), 1 deletion(-)
 create mode 100644 lib/menubar/init.lua.in
 create mode 100644 lib/menubar/menu_gen.lua.in
 create mode 100644 lib/menubar/utils.lua.in

diff --git a/awesomerc.lua.in b/awesomerc.lua.in
index ceac430..efa3cc9 100644
--- a/awesomerc.lua.in
+++ b/awesomerc.lua.in
@@ -8,6 +8,7 @@ require("wibox")
 require("beautiful")
 -- Notification library
 require("naughty")
+require("menubar")
 
 -- {{{ Error handling
 -- Check if awesome encountered an error during startup and fell back to
@@ -251,7 +252,9 @@ globalkeys = awful.util.table.join(
                   mypromptbox[mouse.screen].widget,
                   awful.util.eval, nil,
                   awful.util.getdir("cache") .. "/history_eval")
-              end)
+              end),
+    -- Menubar
+    awful.key({ modkey }, "p", function() menubar.show() end)
 )
 
 clientkeys = awful.util.table.join(
diff --git a/lib/menubar/init.lua.in b/lib/menubar/init.lua.in
new file mode 100644
index 0000000..a47e715
--- /dev/null
+++ b/lib/menubar/init.lua.in
@@ -0,0 +1,272 @@
+---------------------------------------------------------------------------
+-- @author Alexander Yakushev &lt;[email protected]&gt;
+-- @copyright 2011-2012 Alexander Yakushev
+-- @release @AWESOME_VERSION@
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local capi = { client = client,
+               screen = screen }
+local setmetatable = setmetatable
+local ipairs = ipairs
+local table = table
+local theme = require("beautiful")
+local menu_gen = require("menubar.menu_gen")
+local prompt = require("awful.prompt")
+local awful = require("awful")
+local common = require("awful.widget.common")
+local tonumber = tonumber
+local string = string
+local mouse = mouse
+local math = math
+local keygrabber = keygrabber
+local wibox = require("wibox")
+
+-- Menubar is a dmenu-like applications menu extension for Awesome.
+module("menubar")
+
+-- Options section
+
+-- When true the .desktop files will be reparsed only when the
+-- extension is initialized. Use this if menubar takes much time to
+-- open.
+cache_entries = true
+
+-- When true the categories will be shown alongside application
+-- entries.
+show_categories = true
+
+-- Specifies the size and position of the menubar.
+geometry = { width = nil,
+             height = 20,
+             x = nil,
+             y = nil }
+
+-- Private section
+local current_item = 1
+local previous_item = nil
+local current_category = nil
+local shownitems = nil
+local instance = { prompt = nil,
+                   widget = nil,
+                   wibox = nil }
+
+common_args = { w = wibox.layout.fixed.horizontal(),
+                data = setmetatable({}, { __mode = 'kv' }) }
+
+-- Wrap the text with the color span tag.
+-- @param s The text.
+-- @param c The desired text color.
+-- @return the text wrapped in a span tag.
+local function colortext(s, c)
+    return "<span color='" .. c .. "'>" .. s .. "</span>"
+end
+
+-- Generate a pattern matching expression that ignores case.
+-- @param s Original pattern matching expresion.
+local function nocase (s)
+    s = string.gsub(s, "%a",
+                    function (c)
+                        return string.format("[%s%s]", string.lower(c),
+                                             string.upper(c))
+                    end)
+    return s
+end
+
+-- Get how the menu item should be displayed.
+-- @param o The menu item.
+-- @return item name, item background color, background image, item icon.
+local function label(o)
+    if o.focused then
+        local color = awful.util.color_strip_alpha(theme.fg_focus)
+        return colortext(o.name, color), theme.bg_focus, nil, o.icon
+    else
+        return o.name, theme.bg_normal, nil, o.icon
+    end
+end
+
+-- Perform an action for the given menu item.
+-- @param o The menu item.
+-- @return if the function processed the callback, new awful.prompt command, new awful.prompt prompt text.
+local function perform_action(o)
+    if not o or o.empty then
+        return true
+    end
+    if o.cat_id then
+        current_category = o.cat_id
+        local new_prompt = shownitems[current_item].name .. ": "
+        previous_item = current_item
+        current_item = 1
+        return true, "", new_prompt
+    elseif shownitems[current_item].cmdline then
+        awful.util.spawn(shownitems[current_item].cmdline)
+        hide()
+        return true
+    end
+end
+
+-- Update the menubar according to the command entered by user.
+-- @param query The text to filter entries by.
+local function menulist_update(query)
+    local query = query or ""
+    shownitems = {}
+    local match_inside = {}
+
+    -- First we add entries which names match the command from the
+    -- beginning to the table shownitems, and the ones that contain
+    -- command in the middle to the table match_inside.
+
+    -- Add the categories
+    if show_categories then
+        for i, v in ipairs(menu_gen.all_categories) do
+            v.focused = false
+            if not current_category and v.use then
+                if string.match(v.name, nocase(query)) then
+                    if string.match(v.name, "^" .. nocase(query)) then
+                        table.insert(shownitems, v)
+                    else
+                        table.insert(match_inside, v)
+                    end
+                end
+            end
+        end
+    end
+
+    -- Add the applications
+    for i, v in ipairs(menu_entries) do
+        v.focused = false
+        if not current_category or v.category == current_category then
+            if string.match(v.name, nocase(query)) then
+                if string.match(v.name, "^" .. nocase(query)) then
+                    table.insert(shownitems, v)
+                else
+                    table.insert(match_inside, v)
+                end
+            end
+        end
+    end
+
+    -- Now add items from match_inside to shownitems
+    for i, v in ipairs(match_inside) do
+        table.insert(shownitems, v)
+    end
+
+    if #shownitems > 0 then
+        if current_item > #shownitems then
+            current_item = #shownitems
+        end
+        shownitems[current_item].focused = true
+    else
+        table.insert(shownitems, { name = "&lt;no matches&gt;", icon = nil,
+                                   empty = true })
+    end
+
+    common.list_update(common_args.w, nil, label,
+                       common_args.data,
+                       shownitems)
+end
+
+-- Create the menubar wibox and widgets.
+local function initialize()
+    instance.wibox = wibox({})
+    instance.widget = get()
+    instance.wibox.ontop = true
+    instance.prompt = awful.widget.prompt()
+    local layout = wibox.layout.fixed.horizontal()
+    layout:add(instance.prompt)
+    layout:add(instance.widget)
+    instance.wibox:set_widget(layout)
+end
+
+--- Refresh menubar's cache by reloading .desktop files.
+function refresh()
+    menu_entries = menu_gen.generate()
+end
+
+-- Awful.prompt keypressed callback to be used when the user presses a key.
+-- @param mod Table of key combination modifiers (Control, Shift).
+-- @param key The key that was pressed.
+-- @param comm The current command in the prompt.
+-- @return if the function processed the callback, new awful.prompt command, new awful.prompt prompt text.
+local function prompt_keypressed_callback(mod, key, comm)
+    if key == "Left" or (mod.Control and key == "j") then
+        current_item = math.max(current_item - 1, 1)
+        return true
+    elseif key == "Right" or (mod.Control and key == "k") then
+        current_item = current_item + 1
+        return true
+    elseif key == "BackSpace" then
+        if comm == "" and current_category then
+            current_category = nil
+            current_item = previous_item
+            return true, nil, "Run app: "
+        end
+    elseif key == "Escape" then
+        if current_category then
+            current_category = nil
+            current_item = previous_item
+            return true, nil, "Run app: "
+        end
+    elseif key == "Return" then
+        return perform_action(shownitems[current_item])
+    end
+    return false
+end
+
+--- Show the menubar on the given screen.
+-- @param scr Screen number.
+function show(scr)
+    if not instance.wibox then
+        initialize()
+    elseif instance.wibox.visible then -- Menu already shown, exit
+        return
+    elseif not cache_entries then
+        refresh()
+    end
+
+    -- Set position and size
+    local scrgeom = capi.screen[scr or 1].workarea
+    local x = geometry.x or scrgeom.x
+    local y = geometry.y or scrgeom.y
+    instance.wibox.height = geometry.height or 20
+    instance.wibox.width = geometry.width or scrgeom.width
+    instance.wibox:geometry({x = x, y = y})
+
+    current_item = 1
+    current_category = nil
+    menulist_update()
+    prompt.run({ prompt = "Run app: " }, instance.prompt.widget, function(s) end,
+               nil, awful.util.getdir("cache") .. "/history_menu", nil, hide,
+               menulist_update,
+               prompt_keypressed_callback)
+    instance.wibox.visible = true
+end
+
+--- Hide the menubar.
+function hide()
+    keygrabber.stop()
+    instance.wibox.visible = false
+end
+
+--- Get a menubar wibox.
+-- @return menubar wibox.
+function get()
+    if app_folders then
+        menu_gen.all_menu_dirs = app_folders
+    end
+    refresh()
+    -- Load categories icons and add IDs to them
+    for i, v in ipairs(menu_gen.all_categories) do
+        v.cat_id = i
+    end
+    return common_args.w
+end
+
+--- Set the current system icon theme.
+-- @param theme_name The icon theme's name.
+function set_icon_theme(theme_name)
+    utils.icon_theme = theme_name
+    menu_gen.lookup_category_icons()
+end
+
+setmetatable(_M, { __call = function(_, ...) return get(...) end })
\ No newline at end of file
diff --git a/lib/menubar/menu_gen.lua.in b/lib/menubar/menu_gen.lua.in
new file mode 100644
index 0000000..fcf22ef
--- /dev/null
+++ b/lib/menubar/menu_gen.lua.in
@@ -0,0 +1,117 @@
+---------------------------------------------------------------------------
+-- @author Antonio Terceiro
+-- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev
+-- @release @AWESOME_VERSION@
+---------------------------------------------------------------------------
+
+-- Grab environment
+local utils = require("menubar.utils")
+local ipairs = ipairs
+local string = string
+local table = table
+
+-- Menu generation module for menubar
+module("menubar.menu_gen")
+
+-- Options section
+
+-- Specifies all directories where menubar should look for .desktop
+-- files. The search is not recursive.
+all_menu_dirs = { '/usr/share/applications/' }
+
+-- Specify the mapping of .desktop Categories section to the
+-- categories in the menubar. If Use flag is set to false then any of
+-- the applications that fall only to this category will not be shown.
+all_categories = {
+    { app_type = "AudioVideo", name = "Multimedia",
+      icon_name = "applications-multimedia.png", use = true },
+    { app_type = "Development", name = "Development",
+      icon_name = "applications-development.png", use = true },
+    { app_type = "Education", name = "Education",
+      icon_name = "applications-science.png", use = false },
+    { app_type = "Game", name = "Games",
+      icon_name = "applications-games.png", use = true },
+    { app_type = "Graphics", name = "Graphics",
+      icon_name = "applications-graphics.png", use = true },
+    { app_type = "Office", name = "Office",
+      icon_name = "applications-office.png", use = true },
+    { app_type = "Network", name = "Internet",
+      icon_name = "applications-internet.png", use = true },
+    { app_type = "Settings", name = "Settings",
+      icon_name = "applications-utilities.png", use = false },
+    { app_type = "System", name = "System Tools",
+      icon_name = "applications-system.png", use = true },
+    { app_type = "Utility", name = "Accessories",
+      icon_name = "applications-accessories.png", use = true }
+}
+
+--- Find icons for category entries.
+function lookup_category_icons()
+    for i, v in ipairs(all_categories) do
+        v.icon = utils.lookup_icon(v.icon_name)
+    end
+end
+
+lookup_category_icons()
+
+-- Get category number and whether it is used by its app_type.
+-- @param app_type Application category as written in .desktop file.
+-- @return category position in all_categories, whether the category is used
+local function get_category_number_and_usage_by_type(app_type)
+    for i, v in ipairs(all_categories) do
+        if app_type == v.app_type then
+            return i, v.use
+        end
+    end
+end
+
+-- Remove non-printable characters from the end of the string.
+-- @param s string to trim
+local function trim(s)
+    if s then
+        -- Check CR/LF newlines
+        if string.byte(s, #s) == 13 then
+            return string.sub(s, 1, #s - 1)
+        end
+        return s
+    end
+end
+
+--- Generate an array of all visible menu entries.
+-- @return all menu entries.
+function generate()
+    local result = {}
+
+    for _, dir in ipairs(all_menu_dirs) do
+        local entries = utils.parse_dir(dir)
+        for _, program in ipairs(entries) do
+            -- Check whether to include program in the menu
+            if program.show and program.Name and program.cmdline then
+                local target_category = nil
+                -- Check if the program falls at least to one of the
+                -- usable categories. Set target_category to be the id
+                -- of the first category it finds.
+                if program.categories then
+                    for _, category in ipairs(program.categories) do
+                        local cat_id, cat_use =
+                            get_category_number_and_usage_by_type(category)
+                        if cat_id and cat_use then
+                            target_category = cat_id
+                            break
+                        end
+                    end
+                end
+                if target_category then
+                    local name = trim(program.Name) or ""
+                    local cmdline = trim(program.cmdline) or ""
+                    local icon = utils.lookup_icon(trim(program.icon_path)) or nil
+                    table.insert(result, { name = name,
+                                           cmdline = cmdline,
+                                           icon = icon,
+                                           category = target_category })
+                end
+            end
+        end
+    end
+    return result
+end
\ No newline at end of file
diff --git a/lib/menubar/utils.lua.in b/lib/menubar/utils.lua.in
new file mode 100644
index 0000000..e297725
--- /dev/null
+++ b/lib/menubar/utils.lua.in
@@ -0,0 +1,190 @@
+---------------------------------------------------------------------------
+-- @author Antonio Terceiro
+-- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev
+-- @release @AWESOME_VERSION@
+---------------------------------------------------------------------------
+
+-- Grab environment
+local io = io
+local table = table
+local ipairs = ipairs
+local string = string
+local awful_util = require("awful.util")
+
+-- Utility module for menubar
+module("menubar.utils")
+
+-- NOTE: This icons/desktop files module was written according to the
+-- following freedesktop.org specifications:
+-- Icons: http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-0.11.html
+-- Desktop files: http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
+
+-- Options section
+
+-- Terminal which applications that need terminal would open in.
+terminal = 'xterm'
+
+-- The default icon for applications that don't provide any icon in
+-- their .desktop files.
+default_icon = nil
+
+-- Name of the icon theme you want to use for the application icons.
+icon_theme = nil
+
+-- Name of the WM for the OnlyShownIn entry in the .desktop file.
+wm_name = "awesome"
+
+-- Private section
+local all_icon_sizes = {
+    '128x128' ,
+    '96x96',
+    '72x72',
+    '64x64',
+    '48x48',
+    '36x36',
+    '32x32',
+    '24x24',
+    '22x22',
+    '16x16'
+}
+
+local icon_sizes = {}
+
+-- List of supported icon formats. Ignore SVG because Awesome doesn't
+-- support it.
+local icon_formats = { ".png", ".xpm" }
+
+-- Check whether the icon format is supported.
+-- @param icon_file Filename of the icon.
+-- @return true if format is supported, false otherwise.
+local function is_format_supported(icon_file)
+    for _, f in ipairs(icon_formats) do
+        if icon_file:match('.+' .. f) then
+            return true
+        end
+    end
+    return false
+end
+
+--- Lookup an icon in different folders of the filesystem.
+-- @param icon_file Short or full name of the icon.
+-- @return full name of the icon.
+function lookup_icon(icon_file)
+    if not icon_file or icon_file == "" then
+        return default_icon
+    end
+
+    if icon_file:sub(1, 1) == '/' and is_format_supported(icon_file) then
+        -- If the path to the icon is absolute and its format is
+        -- supported, do not perform a lookup.
+        return icon_file
+    else
+        local icon_path = {}
+        local icon_theme_paths = {}
+        if icon_theme then
+            table.insert(icon_theme_paths, '/usr/share/icons/' .. icon_theme .. '/')
+            -- TODO also look in parent icon themes, as in freedesktop.org specification
+        end
+        table.insert(icon_theme_paths, '/usr/share/icons/hicolor/') -- fallback theme
+
+        for i, icon_theme_directory in ipairs(icon_theme_paths) do
+            for j, size in ipairs(all_icon_sizes) do
+                table.insert(icon_path, icon_theme_directory .. size .. '/apps/')
+                table.insert(icon_path, icon_theme_directory .. size .. '/actions/')
+                table.insert(icon_path, icon_theme_directory .. size .. '/devices/')
+                table.insert(icon_path, icon_theme_directory .. size .. '/places/')
+                table.insert(icon_path, icon_theme_directory .. size .. '/categories/')
+                table.insert(icon_path, icon_theme_directory .. size .. '/status/')
+            end
+        end
+        -- lowest priority fallbacks
+        table.insert(icon_path, '/usr/share/pixmaps/')
+        table.insert(icon_path, '/usr/share/icons/')
+
+        for i, directory in ipairs(icon_path) do
+            if is_format_supported(icon_file) and awful_util.file_readable(directory .. icon_file) then
+                return directory .. icon_file
+            else
+                -- Icon is probably specified without path and format,
+                -- like 'firefox'. Try to add supported extensions to
+                -- it and see if such file exists.
+                for _, format in ipairs(icon_formats) do
+                    local possible_file = directory .. icon_file .. format
+                    if awful_util.file_readable(possible_file) then
+                        return possible_file
+                    end
+                end
+            end
+        end
+        return default_icon
+    end
+end
+
+--- Parse a .desktop file.
+-- @param file The .desktop file.
+-- @return A table with file entries.
+function parse(file)
+    local program = { show = true, file = file }
+    for line in io.lines(file) do
+        for key, value in line:gmatch("(%w+)=(.+)") do
+            program[key] = value
+        end
+    end
+
+    -- Don't show program if NoDisplay attribute is false
+    if program.NoDisplay and string.lower(program.NoDisplay) == "true" then
+        program.show = false
+    end
+
+    -- Only show the program if there is no OnlyShowIn attribute
+    -- or if it's equal to 'awesome'
+    if program.OnlyShowIn ~= nil and program.OnlyShowIn ~= wm_name then
+        program.show = false
+    end
+
+    -- Look up for a icon.
+    if program.Icon then
+        program.icon_path = lookup_icon(program.Icon)
+    end
+
+    -- Split categories into a table. Categories are written in one
+    -- line separated by semicolon.
+    if program.Categories then
+        program.categories = {}
+        for category in program.Categories:gfind('[^;]+') do
+            table.insert(program.categories, category)
+        end
+    end
+
+    if program.Exec then
+        -- Substitute Exec special codes as specified in
+        -- http://standards.freedesktop.org/desktop-entry-spec/1.1/ar01s06.html
+        local cmdline = program.Exec:gsub('%%c', program.Name)
+        cmdline = cmdline:gsub('%%[fuFU]', '')
+        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_dir(dir)
+    local programs = {}
+    local files = io.popen('find '.. dir ..' -maxdepth 1 -name "*.desktop"'):lines()
+    for file in files do
+        table.insert(programs, parse(file))
+    end
+    return programs
+end
-- 
1.7.9.2

Reply via email to