diff options
Diffstat (limited to 'awesome/lib/menubar')
-rw-r--r-- | awesome/lib/menubar/icon_theme.lua | 251 | ||||
-rw-r--r-- | awesome/lib/menubar/index_theme.lua | 164 | ||||
-rw-r--r-- | awesome/lib/menubar/init.lua | 480 | ||||
-rw-r--r-- | awesome/lib/menubar/menu_gen.lua | 141 | ||||
-rw-r--r-- | awesome/lib/menubar/utils.lua | 316 |
5 files changed, 0 insertions, 1352 deletions
diff --git a/awesome/lib/menubar/icon_theme.lua b/awesome/lib/menubar/icon_theme.lua deleted file mode 100644 index f76252f..0000000 --- a/awesome/lib/menubar/icon_theme.lua +++ /dev/null @@ -1,251 +0,0 @@ ---------------------------------------------------------------------------- ---- Class module for icon lookup for menubar --- --- @author Kazunobu Kuriyama --- @copyright 2015 Kazunobu Kuriyama --- @classmod menubar.icon_theme ---------------------------------------------------------------------------- - --- This implementation is based on the specifications: --- Icon Theme Specification 0.12 --- http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-0.12.html - -local beautiful = require("beautiful") -local awful_util = require("awful.util") -local GLib = require("lgi").GLib -local index_theme = require("menubar.index_theme") - -local ipairs = ipairs -local setmetatable = setmetatable -local string = string -local table = table -local math = math - -local get_pragmatic_base_directories = function() - local dirs = {} - - local dir = GLib.build_filenamev({GLib.get_home_dir(), ".icons"}) - if awful_util.dir_readable(dir) then - table.insert(dirs, dir) - end - - dir = GLib.build_filenamev({GLib.get_user_data_dir(), "icons"}) - if awful_util.dir_readable(dir) then - table.insert(dirs, dir) - end - - for _, v in ipairs(GLib.get_system_data_dirs()) do - dir = GLib.build_filenamev({v, "icons"}) - if awful_util.dir_readable(dir) then - table.insert(dirs, dir) - end - end - - local need_usr_share_pixmaps = true - for _, v in ipairs(GLib.get_system_data_dirs()) do - dir = GLib.build_filenamev({v, "pixmaps"}) - if awful_util.dir_readable(dir) then - table.insert(dirs, dir) - end - if dir == "/usr/share/pixmaps" then - need_usr_share_pixmaps = false - end - end - - dir = "/usr/share/pixmaps" - if need_usr_share_pixmaps and awful_util.dir_readable(dir) then - table.insert(dirs, dir) - end - - return dirs -end - -local get_default_icon_theme_name = function() - local icon_theme_names = { "Adwaita", "gnome", "hicolor" } - for _, dir in ipairs(get_pragmatic_base_directories()) do - for _, icon_theme_name in ipairs(icon_theme_names) do - local filename = string.format("%s/%s/index.theme", dir, icon_theme_name) - if awful_util.file_readable(filename) then - return icon_theme_name - end - end - end - return nil -end - -local icon_theme = { mt = {} } - -local index_theme_cache = {} - ---- Class constructor of `icon_theme` --- @tparam string icon_theme_name Internal name of icon theme --- @tparam table base_directories Paths used for lookup --- @treturn table An instance of the class `icon_theme` -icon_theme.new = function(icon_theme_name, base_directories) - icon_theme_name = icon_theme_name or beautiful.icon_theme or get_default_icon_theme_name() - base_directories = base_directories or get_pragmatic_base_directories() - - local self = {} - self.icon_theme_name = icon_theme_name - self.base_directories = base_directories - self.extensions = { "png", "svg", "xpm" } - - -- Instantiate index_theme (cached). - if not index_theme_cache[self.icon_theme_name] then - index_theme_cache[self.icon_theme_name] = {} - end - local cache_key = table.concat(self.base_directories, ':') - if not index_theme_cache[self.icon_theme_name][cache_key] then - index_theme_cache[self.icon_theme_name][cache_key] = index_theme( - self.icon_theme_name, - self.base_directories) - end - self.index_theme = index_theme_cache[self.icon_theme_name][cache_key] - - return setmetatable(self, { __index = icon_theme }) -end - -local directory_matches_size = function(self, subdirectory, icon_size) - local kind, size, min_size, max_size, threshold = self.index_theme:get_per_directory_keys(subdirectory) - - if kind == "Fixed" then - return icon_size == size - elseif kind == "Scalable" then - return icon_size >= min_size and icon_size <= max_size - elseif kind == "Threshold" then - return icon_size >= size - threshold and icon_size <= size + threshold - end - - return false -end - -local directory_size_distance = function(self, subdirectory, icon_size) - local kind, size, min_size, max_size, threshold = self.index_theme:get_per_directory_keys(subdirectory) - - if kind == "Fixed" then - return math.abs(icon_size - size) - elseif kind == "Scalable" then - if icon_size < min_size then - return min_size - icon_size - elseif icon_size > max_size then - return icon_size - max_size - end - return 0 - elseif kind == "Threshold" then - if icon_size < size - threshold then - return min_size - icon_size - elseif icon_size > size + threshold then - return icon_size - max_size - end - return 0 - end - - return 0xffffffff -- Any large number will do. -end - -local lookup_icon = function(self, icon_name, icon_size) - local checked_already = {} - for _, subdir in ipairs(self.index_theme:get_subdirectories()) do - for _, basedir in ipairs(self.base_directories) do - for _, ext in ipairs(self.extensions) do - if directory_matches_size(self, subdir, icon_size) then - local filename = string.format("%s/%s/%s/%s.%s", - basedir, self.icon_theme_name, subdir, - icon_name, ext) - if awful_util.file_readable(filename) then - return filename - else - checked_already[filename] = true - end - end - end - end - end - - local minimal_size = 0xffffffff -- Any large number will do. - local closest_filename = nil - for _, subdir in ipairs(self.index_theme:get_subdirectories()) do - local dist = directory_size_distance(self, subdir, icon_size) - if dist < minimal_size then - for _, basedir in ipairs(self.base_directories) do - for _, ext in ipairs(self.extensions) do - local filename = string.format("%s/%s/%s/%s.%s", - basedir, self.icon_theme_name, subdir, - icon_name, ext) - if not checked_already[filename] then - if awful_util.file_readable(filename) then - closest_filename = filename - minimal_size = dist - end - end - end - end - end - end - return closest_filename -end - -local find_icon_path_helper -- Gets called recursively. -find_icon_path_helper = function(self, icon_name, icon_size) - local filename = lookup_icon(self, icon_name, icon_size) - if filename then - return filename - end - - for _, parent in ipairs(self.index_theme:get_inherits()) do - local parent_icon_theme = icon_theme(parent, self.base_directories) - filename = find_icon_path_helper(parent_icon_theme, icon_name, icon_size) - if filename then - return filename - end - end - - return nil -end - -local lookup_fallback_icon = function(self, icon_name) - for _, dir in ipairs(self.base_directories) do - for _, ext in ipairs(self.extensions) do - local filename = string.format("%s/%s.%s", - dir, - icon_name, ext) - if awful_util.file_readable(filename) then - return filename - end - end - end - return nil -end - ---- Look up an image file based on a given icon name and/or a preferable size. --- @tparam string icon_name Icon name to be looked up --- @tparam number icon_size Prefereable icon size --- @treturn string Absolute path to the icon file, or nil if not found -function icon_theme:find_icon_path(icon_name, icon_size) - icon_size = icon_size or 16 - if not icon_name or icon_name == "" then - return nil - end - - local filename = find_icon_path_helper(self, icon_name, icon_size) - if filename then - return filename - end - - if self.icon_theme_name ~= "hicolor" then - filename = find_icon_path_helper(icon_theme("hicolor", self.base_directories), icon_name, icon_size) - if filename then - return filename - end - end - - return lookup_fallback_icon(self, icon_name) -end - -icon_theme.mt.__call = function(_, ...) - return icon_theme.new(...) -end - -return setmetatable(icon_theme, icon_theme.mt) - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/awesome/lib/menubar/index_theme.lua b/awesome/lib/menubar/index_theme.lua deleted file mode 100644 index 633964a..0000000 --- a/awesome/lib/menubar/index_theme.lua +++ /dev/null @@ -1,164 +0,0 @@ ---------------------------------------------------------------------------- ---- Class module for parsing an index.theme file --- --- @author Kazunobu Kuriyama --- @copyright 2015 Kazunobu Kuriyama --- @classmod menubar.index_theme ---------------------------------------------------------------------------- - --- This implementation is based on the specifications: --- Icon Theme Specification 0.12 --- http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-0.12.html - -local ipairs = ipairs -local setmetatable = setmetatable -local string = string -local table = table -local io = io - --- index.theme groups -local ICON_THEME = "Icon Theme" --- index.theme keys -local DIRECTORIES = "Directories" -local INHERITS = "Inherits" --- per-directory subkeys -local TYPE = "Type" -local SIZE = "Size" -local MINSIZE = "MinSize" -local MAXSIZE = "MaxSize" -local THRESHOLD = "Threshold" - -local index_theme = { mt = {} } - ---- Class constructor of `index_theme` --- @tparam table cls Metatable that will be used. Should always be `index_theme.mt`. --- @tparam string icon_theme_name Internal name of icon theme --- @tparam table base_directories Paths used for lookup --- @treturn table An instance of the class `index_theme` -index_theme.new = function(cls, icon_theme_name, base_directories) - local self = {} - setmetatable(self, { __index = cls }) - - -- Initialize the fields - self.icon_theme_name = icon_theme_name - self.base_directory = nil - self[DIRECTORIES] = {} - self[INHERITS] = {} - self.per_directory_keys = {} - - -- base_directory - local basedir = nil - local handler = nil - for _, dir in ipairs(base_directories) do - basedir = dir .. "/" .. self.icon_theme_name - handler = io.open(basedir .. "/index.theme", "r") - if handler then - -- Use the index.theme which is found first. - break - end - end - if not handler then - return self - end - self.base_directory = basedir - - -- Parse index.theme. - while true do - local line = handler:read() - if not line then - break - end - - local group_header = "^%[(.+)%]$" - local group = line:match(group_header) - if group then - if group == ICON_THEME then - while true do - local item = handler:read() - if not item then - break - end - if item:match(group_header) then - handler:seek("cur", -string.len(item) - 1) - break - end - - local k, v = item:match("^(%w+)=(.*)$") - if k == DIRECTORIES or k == INHERITS then - string.gsub(v, "([^,]+),?", function(match) - table.insert(self[k], match) - end) - end - end - else - -- This must be a 'per-directory keys' group - local keys = {} - - while true do - local item = handler:read() - if not item then - break - end - if item:match(group_header) then - handler:seek("cur", -string.len(item) - 1) - break - end - - local k, v = item:match("^(%w+)=(%w+)$") - if k == SIZE or k == MINSIZE or k == MAXSIZE or k == THRESHOLD then - keys[k] = tonumber(v) - elseif k == TYPE then - keys[k] = v - end - end - - -- Size is a must. Other keys are optional. - if keys[SIZE] then - -- Set unset keys to the default values. - if not keys[TYPE] then keys[TYPE] = THRESHOLD end - if not keys[MINSIZE] then keys[MINSIZE] = keys[SIZE] end - if not keys[MAXSIZE] then keys[MAXSIZE] = keys[SIZE] end - if not keys[THRESHOLD] then keys[THRESHOLD] = 2 end - - self.per_directory_keys[group] = keys - end - end - end - end - - handler:close() - - return self -end - ---- Table of the values of the `Directories` key --- @treturn table Values of the `Directories` key -index_theme.get_subdirectories = function(self) - return self[DIRECTORIES] -end - ---- Table of the values of the `Inherits` key --- @treturn table Values of the `Inherits` key -index_theme.get_inherits = function(self) - return self[INHERITS] -end - ---- Query (part of) per-directory keys of a given subdirectory name. --- @tparam table subdirectory Icon theme's subdirectory --- @treturn[1] string Value of the `Type` key --- @treturn[2] number Value of the `Size` key --- @treturn[3] number VAlue of the `MinSize` key --- @treturn[4] number Value of the `MaxSize` key --- @treturn[5] number Value of the `Threshold` key -function index_theme:get_per_directory_keys(subdirectory) - local keys = self.per_directory_keys[subdirectory] - return keys[TYPE], keys[SIZE], keys[MINSIZE], keys[MAXSIZE], keys[THRESHOLD] -end - -index_theme.mt.__call = function(cls, icon_theme_name, base_directories) - return index_theme.new(cls, icon_theme_name, base_directories) -end - -return setmetatable(index_theme, index_theme.mt) - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/awesome/lib/menubar/init.lua b/awesome/lib/menubar/init.lua deleted file mode 100644 index 10ad65c..0000000 --- a/awesome/lib/menubar/init.lua +++ /dev/null @@ -1,480 +0,0 @@ ---------------------------------------------------------------------------- ---- Menubar module, which aims to provide a freedesktop menu alternative --- --- List of menubar keybindings: --- --- --- --- * "Left" | "C-j" select an item on the left --- * "Right" | "C-k" select an item on the right --- * "Backspace" exit the current category if we are in any --- * "Escape" exit the current directory or exit menubar --- * "Home" select the first item --- * "End" select the last --- * "Return" execute the entry --- * "C-Return" execute the command with awful.spawn --- * "C-M-Return" execute the command in a terminal --- --- @author Alexander Yakushev <yakushev.alex@gmail.com> --- @copyright 2011-2012 Alexander Yakushev --- @module menubar ---------------------------------------------------------------------------- - --- Grab environment we need -local capi = { - client = client, - mouse = mouse, - screen = screen -} -local awful = require("awful") -local common = require("awful.widget.common") -local theme = require("beautiful") -local wibox = require("wibox") - -local function get_screen(s) - return s and capi.screen[s] -end - --- menubar -local menubar = { mt = {}, menu_entries = {} } -menubar.menu_gen = require("menubar.menu_gen") -menubar.utils = require("menubar.utils") -local compute_text_width = menubar.utils.compute_text_width - --- 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. --- @tfield[opt=true] boolean cache_entries -menubar.cache_entries = true - ---- When true the categories will be shown alongside application --- entries. --- @tfield[opt=true] boolean show_categories -menubar.show_categories = true - ---- Specifies the geometry of the menubar. This is a table with the keys --- x, y, width and height. Missing values are replaced via the screen's --- geometry. However, missing height is replaced by the font size. --- @table geometry --- @tfield number geometry.x A forced horizontal position --- @tfield number geometry.y A forced vertical position --- @tfield number geometry.width A forced width --- @tfield number geometry.height A forced height -menubar.geometry = { width = nil, - height = nil, - x = nil, - y = nil } - ---- Width of blank space left in the right side. --- @tfield number right_margin -menubar.right_margin = theme.xresources.apply_dpi(8) - ---- Label used for "Next page", default "▶▶". --- @tfield[opt="▶▶"] string right_label -menubar.right_label = "▶▶" - ---- Label used for "Previous page", default "◀◀". --- @tfield[opt="◀◀"] string left_label -menubar.left_label = "◀◀" - --- awful.widget.common.list_update adds three times a margin of dpi(4) --- for each item: --- @tfield number list_interspace -local list_interspace = theme.xresources.apply_dpi(4) * 3 - ---- Allows user to specify custom parameters for prompt.run function --- (like colors). --- @see awful.prompt -menubar.prompt_args = {} - --- 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 } - -local 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='" .. awful.util.ensure_pango_color(c) .. "'>" .. s .. "</span>" -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 - return colortext(o.name, (theme.menu_fg_focus or theme.fg_focus)), (theme.menu_bg_focus or theme.bg_focus), nil, o.icon - else - return o.name, (theme.menu_bg_normal or theme.bg_normal), nil, o.icon - end -end - -local function load_count_table() - local count_file_name = awful.util.getdir("cache") .. "/menu_count_file" - - local count_file = io.open (count_file_name, "r") - local count_table = {} - - -- read weight file - if count_file then - io.input (count_file) - for line in io.lines() do - local name, count = string.match(line, "([^;]+);([^;]+)") - if name ~= nil and count ~= nil then - count_table[name] = count - end - end - end - - return count_table -end - -local function write_count_table(count_table) - local count_file_name = awful.util.getdir("cache") .. "/menu_count_file" - - local count_file = io.open (count_file_name, "w") - - if count_file then - io.output (count_file) - - for name, count in pairs(count_table) do - local str = string.format("%s;%d\n", name, count) - io.write(str) - end - io.flush() - 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 then return end - if o.key then - current_category = o.key - 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.spawn(shownitems[current_item].cmdline) - - -- load count_table from cache file - local count_table = load_count_table() - - -- increase count - local curname = shownitems[current_item].name - if count_table[curname] ~= nil then - count_table[curname] = count_table[curname] + 1 - else - count_table[curname] = 1 - end - - -- write updated count table to cache file - write_count_table(count_table) - - -- Let awful.prompt execute dummy exec_callback and - -- done_callback to stop the keygrabber properly. - return false - end -end - --- Cut item list to return only current page. --- @tparam table all_items All items list. --- @tparam str query Search query. --- @tparam number|screen scr Screen --- @return table List of items for current page. -local function get_current_page(all_items, query, scr) - scr = get_screen(scr) - if not instance.prompt.width then - instance.prompt.width = compute_text_width(instance.prompt.prompt, scr) - end - if not menubar.left_label_width then - menubar.left_label_width = compute_text_width(menubar.left_label, scr) - end - if not menubar.right_label_width then - menubar.right_label_width = compute_text_width(menubar.right_label, scr) - end - local available_space = instance.geometry.width - menubar.right_margin - - menubar.right_label_width - menubar.left_label_width - - compute_text_width(query, scr) - instance.prompt.width - - local width_sum = 0 - local current_page = {} - for i, item in ipairs(all_items) do - item.width = item.width or - compute_text_width(item.name, scr) + - (item.icon and instance.geometry.height or 0) + list_interspace - if width_sum + item.width > available_space then - if current_item < i then - table.insert(current_page, { name = menubar.right_label, icon = nil }) - break - end - current_page = { { name = menubar.left_label, icon = nil }, item, } - width_sum = item.width - else - table.insert(current_page, item) - width_sum = width_sum + item.width - end - end - return current_page -end - ---- Update the menubar according to the command entered by user. --- @tparam str query Search query. --- @tparam number|screen scr Screen -local function menulist_update(query, scr) - query = query or "" - shownitems = {} - local pattern = awful.util.query_to_pattern(query) - - -- All entries are added to a list that will be sorted - -- according to the priority (first) and weight (second) of its - -- entries. - -- If categories are used in the menu, we add the entries matching - -- the current query with high priority as to ensure they are - -- displayed first. Afterwards the non-category entries are added. - -- All entries are weighted according to the number of times they - -- have been executed previously (stored in count_table). - - local count_table = load_count_table() - local command_list = {} - - local PRIO_NONE = 0 - local PRIO_CATEGORY_MATCH = 2 - - -- Add the categories - if menubar.show_categories then - for _, v in pairs(menubar.menu_gen.all_categories) do - v.focused = false - if not current_category and v.use then - - -- check if current query matches a category - if string.match(v.name, pattern) then - - v.weight = 0 - v.prio = PRIO_CATEGORY_MATCH - - -- get use count from count_table if present - -- and use it as weight - if string.len(pattern) > 0 and count_table[v.name] ~= nil then - v.weight = tonumber(count_table[v.name]) - end - - -- check for prefix match - if string.match(v.name, "^" .. pattern) then - -- increase default priority - v.prio = PRIO_CATEGORY_MATCH + 1 - else - v.prio = PRIO_CATEGORY_MATCH - end - - table.insert (command_list, v) - end - end - end - end - - -- Add the applications according to their name and cmdline - for _, v in ipairs(menubar.menu_entries) do - v.focused = false - if not current_category or v.category == current_category then - - -- check if the query matches either the name or the commandline - -- of some entry - if string.match(v.name, pattern) - or string.match(v.cmdline, pattern) then - - v.weight = 0 - v.prio = PRIO_NONE - - -- get use count from count_table if present - -- and use it as weight - if string.len(pattern) > 0 and count_table[v.name] ~= nil then - v.weight = tonumber(count_table[v.name]) - end - - -- check for prefix match - if string.match(v.name, "^" .. pattern) - or string.match(v.cmdline, "^" .. pattern) then - -- increase default priority - v.prio = PRIO_NONE + 1 - else - v.prio = PRIO_NONE - end - - table.insert (command_list, v) - end - end - end - - local function compare_counts(a, b) - if a.prio == b.prio then - return a.weight > b.weight - end - return a.prio > b.prio - end - - -- sort command_list by weight (highest first) - table.sort(command_list, compare_counts) - -- copy into showitems - shownitems = command_list - - if #shownitems > 0 then - -- Insert a run item value as the last choice - table.insert(shownitems, { name = "Exec: " .. query, cmdline = query, icon = nil }) - - if current_item > #shownitems then - current_item = #shownitems - end - shownitems[current_item].focused = true - else - table.insert(shownitems, { name = "", cmdline = query, icon = nil }) - end - - common.list_update(common_args.w, nil, label, - common_args.data, - get_current_page(shownitems, query, scr)) -end - ---- Create the menubar wibox and widgets. --- @tparam[opt] screen scr Screen. -local function initialize(scr) - instance.wibox = wibox({}) - instance.widget = menubar.get(scr) - 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. --- @tparam[opt] screen scr Screen. -function menubar.refresh(scr) - menubar.menu_gen.generate(function(entries) - menubar.menu_entries = entries - menulist_update(nil, scr) - end) -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: " - end - elseif key == "Escape" then - if current_category then - current_category = nil - current_item = previous_item - return true, nil, "Run: " - end - elseif key == "Home" then - current_item = 1 - return true - elseif key == "End" then - current_item = #shownitems - return true - elseif key == "Return" or key == "KP_Enter" then - if mod.Control then - current_item = #shownitems - if mod.Mod1 then - -- add a terminal to the cmdline - shownitems[current_item].cmdline = menubar.utils.terminal - .. " -e " .. shownitems[current_item].cmdline - end - end - return perform_action(shownitems[current_item]) - end - return false -end - ---- Show the menubar on the given screen. --- @param scr Screen. -function menubar.show(scr) - if not instance.wibox then - initialize(scr) - elseif instance.wibox.visible then -- Menu already shown, exit - return - elseif not menubar.cache_entries then - menubar.refresh(scr) - end - - -- Set position and size - scr = scr or awful.screen.focused() or 1 - scr = get_screen(scr) - local scrgeom = scr.workarea - local geometry = menubar.geometry - instance.geometry = {x = geometry.x or scrgeom.x, - y = geometry.y or scrgeom.y, - height = geometry.height or awful.util.round(theme.get_font_height() * 1.5), - width = geometry.width or scrgeom.width} - instance.wibox:geometry(instance.geometry) - - current_item = 1 - current_category = nil - menulist_update(nil, scr) - - local prompt_args = menubar.prompt_args or {} - - awful.prompt.run(setmetatable({ - prompt = "Run: ", - textbox = instance.prompt.widget, - completion_callback = awful.completion.shell, - history_path = awful.util.get_cache_dir() .. "/history_menu", - done_callback = menubar.hide, - changed_callback = function(query) menulist_update(query, scr) end, - keypressed_callback = prompt_keypressed_callback - }, {__index=prompt_args})) - - instance.wibox.visible = true -end - ---- Hide the menubar. -function menubar.hide() - instance.wibox.visible = false -end - ---- Get a menubar wibox. --- @tparam[opt] screen scr Screen. --- @return menubar wibox. -function menubar.get(scr) - menubar.refresh(scr) - -- Add to each category the name of its key in all_categories - for k, v in pairs(menubar.menu_gen.all_categories) do - v.key = k - end - return common_args.w -end - -function menubar.mt.__call(_, ...) - return menubar.get(...) -end - -return setmetatable(menubar, menubar.mt) - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/awesome/lib/menubar/menu_gen.lua b/awesome/lib/menubar/menu_gen.lua deleted file mode 100644 index ed2aa14..0000000 --- a/awesome/lib/menubar/menu_gen.lua +++ /dev/null @@ -1,141 +0,0 @@ ---------------------------------------------------------------------------- ---- Menu generation module for menubar --- --- @author Antonio Terceiro --- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev --- @module menubar.menu_gen ---------------------------------------------------------------------------- - --- Grab environment -local utils = require("menubar.utils") -local icon_theme = require("menubar.icon_theme") -local pairs = pairs -local ipairs = ipairs -local string = string -local table = table - -local menu_gen = {} - --- Options section - -local data_dir = os.getenv("XDG_DATA_HOME") -if not data_dir then - data_dir = os.getenv("HOME") .. '/.local/share/' -end - ---- Specifies all directories where menubar should look for .desktop --- files. The search is recursive. -menu_gen.all_menu_dirs = { data_dir .. 'applications/', '/usr/share/applications/', '/usr/local/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. -menu_gen.all_categories = { - multimedia = { app_type = "AudioVideo", name = "Multimedia", - icon_name = "applications-multimedia", use = true }, - development = { app_type = "Development", name = "Development", - icon_name = "applications-development", use = true }, - education = { app_type = "Education", name = "Education", - icon_name = "applications-science", use = true }, - games = { app_type = "Game", name = "Games", - icon_name = "applications-games", use = true }, - graphics = { app_type = "Graphics", name = "Graphics", - icon_name = "applications-graphics", use = true }, - office = { app_type = "Office", name = "Office", - icon_name = "applications-office", use = true }, - internet = { app_type = "Network", name = "Internet", - icon_name = "applications-internet", use = true }, - settings = { app_type = "Settings", name = "Settings", - icon_name = "applications-utilities", use = true }, - tools = { app_type = "System", name = "System Tools", - icon_name = "applications-system", use = true }, - utility = { app_type = "Utility", name = "Accessories", - icon_name = "applications-accessories", use = true } -} - ---- Find icons for category entries. -function menu_gen.lookup_category_icons() - for _, v in pairs(menu_gen.all_categories) do - v.icon = icon_theme():find_icon_path(v.icon_name) - end -end - ---- Get category key name and whether it is used by its app_type. --- @param app_type Application category as written in .desktop file. --- @return category key name in all_categories, whether the category is used -local function get_category_name_and_usage_by_type(app_type) - for k, v in pairs(menu_gen.all_categories) do - if app_type == v.app_type then - return k, v.use - end - end -end - ---- Remove CR\LF newline from the end of the string. --- @param s string to trim -local function trim(s) - if not s then return end - if string.byte(s, #s) == 13 then - return string.sub(s, 1, #s - 1) - end - return s -end - ---- Generate an array of all visible menu entries. --- @tparam function callback Will be fired when all menu entries were parsed --- with the resulting list of menu entries as argument. --- @tparam table callback.entries All menu entries. -function menu_gen.generate(callback) - -- Update icons for category entries - menu_gen.lookup_category_icons() - - local result = {} - local unique_entries = {} - local dirs_parsed = 0 - - for _, dir in ipairs(menu_gen.all_menu_dirs) do - utils.parse_dir(dir, function(entries) - entries = entries or {} - for _, entry in ipairs(entries) do - -- Check whether to include program in the menu - if entry.show and entry.Name and entry.cmdline then - local unique_key = entry.Name .. '\0' .. entry.cmdline - if not unique_entries[unique_key] then - local target_category = nil - -- Check if the program falls into at least one of the - -- usable categories. Set target_category to be the id - -- of the first category it finds. - if entry.categories then - for _, category in pairs(entry.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(entry.Name) or "" - local cmdline = trim(entry.cmdline) or "" - local icon = entry.icon_path or nil - table.insert(result, { name = name, - cmdline = cmdline, - icon = icon, - category = target_category }) - unique_entries[unique_key] = true - end - end - end - end - dirs_parsed = dirs_parsed + 1 - if dirs_parsed == #menu_gen.all_menu_dirs then - callback(result) - end - end) - end -end - -return menu_gen - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/awesome/lib/menubar/utils.lua b/awesome/lib/menubar/utils.lua deleted file mode 100644 index 6f80e86..0000000 --- a/awesome/lib/menubar/utils.lua +++ /dev/null @@ -1,316 +0,0 @@ ---------------------------------------------------------------------------- ---- Utility module for menubar --- --- @author Antonio Terceiro --- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev --- @module menubar.utils ---------------------------------------------------------------------------- - --- Grab environment -local io = io -local table = table -local ipairs = ipairs -local string = string -local screen = screen -local awful_util = require("awful.util") -local theme = require("beautiful") -local lgi = require("lgi") -local gio = lgi.Gio -local glib = lgi.GLib -local wibox = require("wibox") -local debug = require("gears.debug") -local protected_call = require("gears.protected_call") - -local 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. -utils.terminal = 'xterm' - ---- The default icon for applications that don't provide any icon in --- their .desktop files. -local default_icon = nil - ---- Name of the WM for the OnlyShownIn entry in the .desktop file. -utils.wm_name = "awesome" - --- Private section - -local all_icon_sizes = { - '128x128' , - '96x96', - '72x72', - '64x64', - '48x48', - '36x36', - '32x32', - '24x24', - '22x22', - '16x16' -} - ---- List of supported icon formats. -local icon_formats = { "png", "xpm", "svg" } - ---- 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 - -local icon_lookup_path = nil ---- Get a list of icon lookup paths. --- @treturn table A list of directories, without trailing slash. -local function get_icon_lookup_path() - if not icon_lookup_path then - local add_if_readable = function(t, path) - if awful_util.dir_readable(path) then - table.insert(t, path) - end - end - icon_lookup_path = {} - local icon_theme_paths = {} - local icon_theme = theme.icon_theme - local paths = glib.get_system_data_dirs() - table.insert(paths, 1, glib.get_user_data_dir()) - table.insert(paths, 1, glib.build_filenamev({glib.get_home_dir(), - '.icons'})) - for _,dir in ipairs(paths) do - local icons_dir = glib.build_filenamev({dir, 'icons'}) - if awful_util.dir_readable(icons_dir) then - if icon_theme then - add_if_readable(icon_theme_paths, - glib.build_filenamev({icons_dir, - icon_theme})) - end - -- Fallback theme. - add_if_readable(icon_theme_paths, - glib.build_filenamev({icons_dir, 'hicolor'})) - end - end - for _, icon_theme_directory in ipairs(icon_theme_paths) do - for _, size in ipairs(all_icon_sizes) do - add_if_readable(icon_lookup_path, - glib.build_filenamev({icon_theme_directory, - size, 'apps'})) - end - end - for _,dir in ipairs(paths)do - -- lowest priority fallbacks - add_if_readable(icon_lookup_path, - glib.build_filenamev({dir, 'pixmaps'})) - add_if_readable(icon_lookup_path, - glib.build_filenamev({dir, 'icons'})) - end - end - return icon_lookup_path -end - ---- Lookup an icon in different folders of the filesystem. --- @tparam string icon_file Short or full name of the icon. --- @treturn string|boolean Full name of the icon, or false on failure. -function utils.lookup_icon_uncached(icon_file) - if not icon_file or icon_file == "" then - return false - 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 awful_util.file_readable(icon_file) and icon_file or nil - else - for _, directory in ipairs(get_icon_lookup_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 false - end -end - -local lookup_icon_cache = {} ---- Lookup an icon in different folders of the filesystem (cached). --- @param icon Short or full name of the icon. --- @return full name of the icon. -function utils.lookup_icon(icon) - if not lookup_icon_cache[icon] and lookup_icon_cache[icon] ~= false then - lookup_icon_cache[icon] = utils.lookup_icon_uncached(icon) - end - return lookup_icon_cache[icon] or default_icon -end - ---- Parse a .desktop file. --- @param file The .desktop file. --- @return A table with file entries. -function utils.parse_desktop_file(file) - local program = { show = true, file = file } - local desktop_entry = false - - -- Parse the .desktop file. - -- We are interested in [Desktop Entry] group only. - for line in io.lines(file) do - if line:find("^%s*#") then - -- Skip comments. - (function() end)() -- I haven't found a nice way to silence luacheck here - elseif not desktop_entry and line == "[Desktop Entry]" then - desktop_entry = true - else - if line:sub(1, 1) == "[" and line:sub(-1) == "]" then - -- A declaration of new group - stop parsing - break - end - - -- Grab the values - for key, value in line:gmatch("(%w+)%s*=%s*(.+)") do - program[key] = value - end - end - end - - -- In case [Desktop Entry] was not found - if not desktop_entry then return nil end - - -- In case the (required) 'Name' entry was not found - if not program.Name or program.Name == '' then return nil 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 not program.OnlyShowIn:match(utils.wm_name) then - program.show = false - end - - -- Look up for a icon. - if program.Icon then - program.icon_path = utils.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:gmatch('[^;]+') 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 - if program.Name == nil then - program.Name = '['.. file:match("([^/]+)%.desktop$") ..']' - end - 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 = utils.terminal .. ' -e ' .. cmdline - end - program.cmdline = cmdline - end - - return program -end - ---- Parse a directory with .desktop files recursively. --- @tparam string dir_path The directory path. --- @tparam function callback Will be fired when all the files were parsed --- with the resulting list of menu entries as argument. --- @tparam table callback.programs Paths of found .desktop files. -function utils.parse_dir(dir_path, callback) - - local function parser(dir, programs) - local f = gio.File.new_for_path(dir) - -- Except for "NONE" there is also NOFOLLOW_SYMLINKS - local query = gio.FILE_ATTRIBUTE_STANDARD_NAME .. "," .. gio.FILE_ATTRIBUTE_STANDARD_TYPE - local enum, err = f:async_enumerate_children(query, gio.FileQueryInfoFlags.NONE) - if not enum then - debug.print_error(err) - return - end - local files_per_call = 100 -- Actual value is not that important - while true do - local list, enum_err = enum:async_next_files(files_per_call) - if enum_err then - debug.print_error(enum_err) - return - end - for _, info in ipairs(list) do - local file_type = info:get_file_type() - local file_path = enum:get_child(info):get_path() - if file_type == 'REGULAR' then - local program = utils.parse_desktop_file(file_path) - if program then - table.insert(programs, program) - end - elseif file_type == 'DIRECTORY' then - parser(file_path, programs) - end - end - if #list == 0 then - break - end - end - enum:async_close() - end - - gio.Async.start(function() - local result = {} - parser(dir_path, result) - protected_call.call(callback, result) - end)() -end - ---- Compute textbox width. --- @tparam wibox.widget.textbox textbox Textbox instance. --- @tparam number|screen s Screen --- @treturn int Text width. -function utils.compute_textbox_width(textbox, s) - s = screen[s or mouse.screen] - local w, _ = textbox:get_preferred_size(s) - return w -end - ---- Compute text width. --- @tparam str text Text. --- @tparam number|screen s Screen --- @treturn int Text width. -function utils.compute_text_width(text, s) - return utils.compute_textbox_width(wibox.widget.textbox(awful_util.escape(text)), s) -end - -return utils - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 |