|
| 1 | + |
| 2 | +--[[ |
| 3 | + |
| 4 | + Awesome-Freedesktop |
| 5 | + Freedesktop.org compliant desktop entries and menu |
| 6 | + |
| 7 | + Desktop section |
| 8 | + |
| 9 | + Licensed under GNU General Public License v2 |
| 10 | + * (c) 2016, Luke Bonham |
| 11 | + * (c) 2009-2015, Antonio Terceiro |
| 12 | + |
| 13 | +--]] |
| 14 | + |
| 15 | +local awful = require("awful") |
| 16 | +local theme = require("beautiful") |
| 17 | +local utils = require("menubar.utils") |
| 18 | +local wibox = require("wibox") |
| 19 | + |
| 20 | +local capi = { screen = screen } |
| 21 | +local ipairs = ipairs |
| 22 | +local mouse = mouse |
| 23 | +local os = os |
| 24 | +local string = { format = string.format } |
| 25 | +local table = table |
| 26 | + |
| 27 | +local desktop = { |
| 28 | + baseicons = { |
| 29 | + [1] = { |
| 30 | + label = "This PC", |
| 31 | + icon = "computer", |
| 32 | + onclick = "computer://" |
| 33 | + }, |
| 34 | + [2] = { |
| 35 | + label = "Home", |
| 36 | + icon = "user-home", |
| 37 | + onclick = os.getenv("HOME") |
| 38 | + }, |
| 39 | + [3] = { |
| 40 | + label = "Trash", |
| 41 | + icon = "user-trash", |
| 42 | + onclick = "trash://" |
| 43 | + } |
| 44 | + }, |
| 45 | + iconsize = { width = 48, height = 48 }, |
| 46 | + labelsize = { width = 140, height = 20 }, |
| 47 | + margin = { x = 20, y = 20 }, |
| 48 | +} |
| 49 | + |
| 50 | +local mime_types = {} |
| 51 | +local desktop_current_pos = {} |
| 52 | + |
| 53 | +local function pipelines(...) |
| 54 | + local f = assert(io.popen(...)) |
| 55 | + return function () -- iterator |
| 56 | + local data = f:read() |
| 57 | + if data == nil then f:close() end |
| 58 | + return data |
| 59 | + end |
| 60 | +end |
| 61 | + |
| 62 | +function desktop.add_icon(args, label, icon, onclick) |
| 63 | + local s = args.screen |
| 64 | + |
| 65 | + if not desktop_current_pos[s] then |
| 66 | + desktop_current_pos[s] = { x = (capi.screen[s].geometry.x + args.iconsize.width + args.margin.x), y = 40 } |
| 67 | + end |
| 68 | + |
| 69 | + local totheight = (icon and args.iconsize.height or 0) + (label and args.labelsize.height or 0) |
| 70 | + if totheight == 0 then return end |
| 71 | + |
| 72 | + if desktop_current_pos[s].y + totheight > capi.screen[s].geometry.height - 40 then |
| 73 | + desktop_current_pos[s].x = desktop_current_pos[s].x + args.labelsize.width + args.iconsize.width + args.margin.x |
| 74 | + desktop_current_pos[s].y = 40 |
| 75 | + end |
| 76 | + |
| 77 | + local common = { screen = s, bg = "#00000000", visible = true, type = "desktop" } |
| 78 | + |
| 79 | + if icon then |
| 80 | + icon = awful.widget.button({ image = icon }) |
| 81 | + icon:buttons(awful.button({ }, 1, nil, onclick)) |
| 82 | + common.width = args.iconsize.width |
| 83 | + common.height = args.iconsize.height |
| 84 | + common.x = desktop_current_pos[s].x |
| 85 | + common.y = desktop_current_pos[s].y |
| 86 | + icon_container = wibox(common) |
| 87 | + icon_container:set_widget(icon) |
| 88 | + desktop_current_pos[s].y = desktop_current_pos[s].y + args.iconsize.height + 5 |
| 89 | + end |
| 90 | + |
| 91 | + if label then |
| 92 | + caption = wibox.widget.textbox() |
| 93 | + caption:fit(args.labelsize.width, args.labelsize.height) |
| 94 | + caption:set_align("center") |
| 95 | + caption:set_ellipsize("middle") |
| 96 | + caption:set_text(label) |
| 97 | + caption:buttons(awful.button({ }, 1, onclick)) |
| 98 | + common.width = args.labelsize.width |
| 99 | + common.height = args.labelsize.height |
| 100 | + common.x = desktop_current_pos[s].x - (args.labelsize.width/2) + args.iconsize.width/2 |
| 101 | + common.y = desktop_current_pos[s].y |
| 102 | + caption_container = wibox(common) |
| 103 | + caption_container:set_widget(caption) |
| 104 | + end |
| 105 | + |
| 106 | + desktop_current_pos[s].y = desktop_current_pos[s].y + args.labelsize.height + args.margin.y |
| 107 | +end |
| 108 | + |
| 109 | +function desktop.add_base_icons(args) |
| 110 | + for _,base in ipairs(args.baseicons) do |
| 111 | + desktop.add_icon(args, base.label, utils.lookup_icon(base.icon), function() |
| 112 | + awful.util.spawn(string.format("%s '%s'", args.open_width, base.onclick)) |
| 113 | + end) |
| 114 | + end |
| 115 | +end |
| 116 | + |
| 117 | +function desktop.lookup_file_icon(filename) |
| 118 | + -- load system MIME types |
| 119 | + if #mime_types == 0 then |
| 120 | + for line in io.lines("/etc/mime.types") do |
| 121 | + if not line:find("^#") then |
| 122 | + local parsed = {} |
| 123 | + for w in line:gmatch("[^%s]+") do |
| 124 | + table.insert(parsed, w) |
| 125 | + end |
| 126 | + if #parsed > 1 then |
| 127 | + for i = 2, #parsed do |
| 128 | + mime_types[parsed[i]] = parsed[1]:gsub("/", "-") |
| 129 | + end |
| 130 | + end |
| 131 | + end |
| 132 | + end |
| 133 | + end |
| 134 | + |
| 135 | + local extension = filename:match("%a+$") |
| 136 | + local mime = mime_types[extension] or "" |
| 137 | + local mime_family = mime:match("^%a+") or "" |
| 138 | + |
| 139 | + local possible_filenames = { |
| 140 | + mime, "gnome-mime-" .. mime, |
| 141 | + mime_family, "gnome-mime-" .. mime_family, |
| 142 | + extension |
| 143 | + } |
| 144 | + |
| 145 | + for i, filename in ipairs(possible_filenames) do |
| 146 | + local icon = utils.lookup_icon(filename) |
| 147 | + if icon then return icon end |
| 148 | + end |
| 149 | + |
| 150 | + -- if we don"t find ad icon, then pretend is a plain text file |
| 151 | + return utils.lookup_icon("text-x-generic") |
| 152 | +end |
| 153 | + |
| 154 | +function desktop.parse_dirs_and_files(dir) |
| 155 | + local files = {} |
| 156 | + local paths = pipelines('find '..dir..' -maxdepth 1 -type d | tail -1') |
| 157 | + for path in paths do |
| 158 | + if path:match("[^/]+$") then |
| 159 | + local file = {} |
| 160 | + file.filename = path:match("[^/]+$") |
| 161 | + file.path = path |
| 162 | + file.show = true |
| 163 | + file.icon = utils.lookup_icon("folder") |
| 164 | + table.insert(files, file) |
| 165 | + end |
| 166 | + end |
| 167 | + local paths = pipelines('find '..dir..' -maxdepth 1 -type f') |
| 168 | + for path in paths do |
| 169 | + if not path:find("%.desktop$") then |
| 170 | + local file = {} |
| 171 | + file.filename = path:match("[^/]+$") |
| 172 | + file.path = path |
| 173 | + file.show = true |
| 174 | + file.icon = desktop.lookup_file_icon(file.filename) |
| 175 | + table.insert(files, file) |
| 176 | + end |
| 177 | + end |
| 178 | + return files |
| 179 | +end |
| 180 | + |
| 181 | +function desktop.add_dirs_and_files_icons(args) |
| 182 | + for _, file in ipairs(desktop.parse_dirs_and_files(args.dir)) do |
| 183 | + if file.show then |
| 184 | + local label = args.showlabels and file.filename or nil |
| 185 | + local onclick = function () awful.util.spawn(string.format("%s '%s'", args.open_with, file.path)) end |
| 186 | + desktop.add_icon(args, label, file.icon, onclick) |
| 187 | + end |
| 188 | + end |
| 189 | +end |
| 190 | + |
| 191 | +function desktop.add_icons(args) |
| 192 | + args = args or {} |
| 193 | + args.screen = args.screen or mouse.screen |
| 194 | + args.dir = args.dir or os.getenv("HOME") .. "/Desktop" |
| 195 | + args.showlabels = args.showlabel or true |
| 196 | + args.open_with = args.open_with or "xdg_open" |
| 197 | + args.baseicons = args.baseicons or desktop.baseicons |
| 198 | + args.iconsize = args.iconsize or desktop.iconsize |
| 199 | + args.labelsize = args.labelsize or desktop.labelsize |
| 200 | + args.margin = args.margin or desktop.margin |
| 201 | + |
| 202 | + if not theme.icon_theme then |
| 203 | + theme.icon_theme = args.icon_theme or "Adwaita" |
| 204 | + end |
| 205 | + |
| 206 | + desktop.add_base_icons(args) |
| 207 | + desktop.add_dirs_and_files_icons(args) |
| 208 | +end |
| 209 | + |
| 210 | +return desktop |
0 commit comments