summaryrefslogtreecommitdiff
path: root/awesome/lib/menubar
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/menubar')
-rw-r--r--awesome/lib/menubar/icon_theme.lua251
-rw-r--r--awesome/lib/menubar/index_theme.lua164
-rw-r--r--awesome/lib/menubar/init.lua480
-rw-r--r--awesome/lib/menubar/menu_gen.lua141
-rw-r--r--awesome/lib/menubar/utils.lua316
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 &lt;yakushev.alex@gmail.com&gt;
--- @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