According to FS#1057[1] menubar incorrectly handles .desktop files with multiple sections in it. Since the .desktop parsing algorithm was pretty weak, it took only the last value for each key thus replacing former "Exec" values with the last one.

With the patch provided menubar treats each section as a separate application launcher (as it originally should). When done in such way, different Ubuntu actions, for instance, are still parsed but not displayed since they have OnlyShowIn=Unity lines inside. On the other hand there might exist such .desktop files that user might want to see in the menubar.

Thoughts on this one are welcome.

Kind regards,

[1] https://awesome.naquadah.org/bugs/index.php?do=details&task_id=1057&project=1&order=dateopened&sort=desc

--
Alexander Yakushev

"GDB is deterrence strategy debugger. With GDB programmer is just more
careful while coding so that use of GDB is not necessary."
   -- Branimir Karadžić

>From 7fcb8bd535eddf8532922ec4c51a9d1df0ff44db Mon Sep 17 00:00:00 2001
From: Alexander Yakushev <a...@bytopia.org>
Date: Wed, 28 Nov 2012 15:12:05 +0200
Subject: [PATCH] menubar: Handle .desktop files with multiple sections

Desktop file standard allows multiple sections to be specified in one
file. The implemented modification treats each section as a separate
launcher that should be displayed on the menubar.

Signed-off-by: Alexander Yakushev <a...@bytopia.org>
---
 lib/menubar/menu_gen.lua.in | 57 ++++++++++++++---------------
 lib/menubar/utils.lua.in    | 88 +++++++++++++++++++++++++--------------------
 2 files changed, 79 insertions(+), 66 deletions(-)

diff --git a/lib/menubar/menu_gen.lua.in b/lib/menubar/menu_gen.lua.in
index e82e2b4..8833f34 100644
--- a/lib/menubar/menu_gen.lua.in
+++ b/lib/menubar/menu_gen.lua.in
@@ -84,34 +84,35 @@ function menu_gen.generate()
     local result = {}
 
     for _, dir in ipairs(menu_gen.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 pairs(program.categories) do
-                        local cat_key, cat_use =
-                            get_category_name_and_usage_by_type(category)
-                        if cat_key and cat_use then
-                            target_category = cat_key
-                            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
+        for _, program_launchers in ipairs(utils.parse_dir(dir)) do
+           for _, launcher in ipairs(program_launchers) do
+               -- Check whether to include launcher in the menu
+               if launcher.show and launcher.Name and launcher.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 launcher.categories then
+                       for _, category in pairs(launcher.categories) do
+                           local cat_key, cat_use =
+                               get_category_name_and_usage_by_type(category)
+                           if cat_key and cat_use then
+                               target_category = cat_key
+                               break
+                           end
+                       end
+                   end
+                   if target_category then
+                       local name = trim(launcher.Name) or ""
+                       local cmdline = trim(launcher.cmdline) or ""
+                       local icon = utils.lookup_icon(trim(launcher.icon_path)) or nil
+                       table.insert(result, { name = name,
+                                              cmdline = cmdline,
+                                              icon = icon,
+                                              category = target_category })
+                   end
+               end
+           end
         end
     end
     return result
diff --git a/lib/menubar/utils.lua.in b/lib/menubar/utils.lua.in
index e45a8bc..d109206 100644
--- a/lib/menubar/utils.lua.in
+++ b/lib/menubar/utils.lua.in
@@ -121,61 +121,73 @@ end
 
 --- Parse a .desktop file.
 -- @param file The .desktop file.
--- @return A table with file entries.
+-- @return A list of tables with file entries. Each table represents
+-- either a direct application launcher or a specific action for this
+-- application.
 function utils.parse(file)
     local program = { show = true, file = file }
+    local current_launcher, launcher_name, launchers = nil, nil, {}
     for line in io.lines(file) do
+        -- Lines like [Desktop File] mark a start of a new subentry.
+        _, _, launcher_name = string.find(line, "^%[([^%]]+)%]$")
+        if launcher_name then
+            current_launcher = { launcher_name = launcher_name, show = true,
+                                 file = file }
+            table.insert(launchers, current_launcher)
+        end
         for key, value in line:gmatch("(%w+)=(.+)") do
-            program[key] = value
+            current_launcher[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 utils.wm_name
-    if program.OnlyShowIn ~= nil and program.OnlyShowIn ~= utils.wm_name then
-        program.show = false
-    end
+    for _, launcher in ipairs(launchers) do
+        -- Don't show launcher if NoDisplay attribute is false
+        if launcher.NoDisplay and string.lower(launcher.NoDisplay) == "true" then
+            launcher.show = false
+        end
 
-    -- Look up for a icon.
-    if program.Icon then
-        program.icon_path = utils.lookup_icon(program.Icon)
-    end
+        -- Only show the launcher if there is no OnlyShowIn attribute
+        -- or if it's equal to wm_name
+        if launcher.OnlyShowIn ~= nil and launcher.OnlyShowIn ~= wm_name then
+            launcher.show = false
+        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)
+        -- Look up for a icon.
+        if launcher.Icon then
+            launcher.icon_path = utils.lookup_icon(launcher.Icon)
         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', '')
+        -- Split categories into a table. Categories are written in one
+        -- line separated by semicolon.
+        if launcher.Categories then
+            launcher.categories = {}
+            for category in launcher.Categories:gfind('[^;]+') do
+                table.insert(launcher.categories, category)
+            end
         end
-        if program.Terminal == "true" then
-            cmdline = utils.terminal .. ' -e ' .. cmdline
+
+        if launcher.Exec then
+            -- Substitute Exec special codes as specified in
+            -- http://standards.freedesktop.org/desktop-entry-spec/1.1/ar01s06.html
+            local cmdline = launcher.Exec:gsub('%%c', launcher.Name)
+            cmdline = cmdline:gsub('%%[fuFU]', '')
+            cmdline = cmdline:gsub('%%k', launcher.file)
+            if launcher.icon_path then
+                cmdline = cmdline:gsub('%%i', '--icon ' .. launcher.icon_path)
+            else
+                cmdline = cmdline:gsub('%%i', '')
+            end
+            if launcher.Terminal == "true" then
+                cmdline = utils.terminal .. ' -e ' .. cmdline
+            end
+            launcher.cmdline = cmdline
         end
-        program.cmdline = cmdline
     end
 
-    return program
+    return launchers
 end
 
---- Parse a directory with .desktop files
+--- Parse a directory with .desktop files.
 -- @param dir The directory.
 -- @param icons_size, The icons sizes, optional.
 -- @return A table with all .desktop entries.
-- 
1.8.0.1

Reply via email to