From 9b943513d574c502dde80120a43884a83d24156e Mon Sep 17 00:00:00 2001 From: Surferlul <lukasabaumann@gmail.com> Date: Mon, 9 Aug 2021 03:38:19 +0200 Subject: [PATCH] changed to vertical layout --- menubar/icon_theme.lua | 253 ++++++++++ menubar/index_theme.lua | 168 +++++++ menubar/init.lua | 601 +++++++++++++++++++++++ menubar/menu_gen.lua | 136 +++++ menubar/utils.lua | 430 ++++++++++++++++ rc.lua | 421 ++++++++++++++-- themes/zenburn/awesome-icon.png | Bin 0 -> 4778 bytes themes/zenburn/submenu.png | Bin 0 -> 440 bytes themes/zenburn/taglist/squarefz.png | Bin 168 -> 4815 bytes themes/zenburn/taglist/squarefz_orig.png | Bin 0 -> 168 bytes themes/zenburn/taglist/squarez.png | Bin 171 -> 4886 bytes themes/zenburn/taglist/squarez_orig.png | Bin 0 -> 171 bytes themes/zenburn/theme.lua | 19 +- 13 files changed, 1974 insertions(+), 54 deletions(-) create mode 100644 menubar/icon_theme.lua create mode 100644 menubar/index_theme.lua create mode 100644 menubar/init.lua create mode 100644 menubar/menu_gen.lua create mode 100644 menubar/utils.lua create mode 100644 themes/zenburn/awesome-icon.png create mode 100644 themes/zenburn/submenu.png create mode 100644 themes/zenburn/taglist/squarefz_orig.png create mode 100644 themes/zenburn/taglist/squarez_orig.png diff --git a/menubar/icon_theme.lua b/menubar/icon_theme.lua new file mode 100644 index 0000000..358f007 --- /dev/null +++ b/menubar/icon_theme.lua @@ -0,0 +1,253 @@ +--------------------------------------------------------------------------- +--- (Deprecated) 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 gfs = require("gears.filesystem") +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 gfs.dir_readable(dir) then + table.insert(dirs, dir) + end + + dir = GLib.build_filenamev({GLib.get_user_data_dir(), "icons"}) + if gfs.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 gfs.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 gfs.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 gfs.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 gfs.file_readable(filename) then + return icon_theme_name + end + end + end + return "hicolor" +end + +local icon_theme = { mt = {} } + +local index_theme_cache = {} + +--- Class constructor of `icon_theme` +-- @deprecated menubar.icon_theme.new +-- @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 gfs.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 gfs.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 gfs.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. +-- @deprecated menubar.icon_theme:find_icon_path +-- @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/menubar/index_theme.lua b/menubar/index_theme.lua new file mode 100644 index 0000000..3ede62a --- /dev/null +++ b/menubar/index_theme.lua @@ -0,0 +1,168 @@ +--------------------------------------------------------------------------- +--- (Deprecated) 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` +-- @deprecated menubar.index_theme.new +-- @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 +-- @deprecated menubar.index_theme:get_subdirectories +-- @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 +-- @deprecated menubar.index_theme:get_inherits +-- @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. +-- @deprecated menubar.index_theme:get_per_directory_keys +-- @tparam table subdirectory Icon theme's subdirectory +-- @treturn string Value of the `Type` key +-- @treturn number Value of the `Size` key +-- @treturn number VAlue of the `MinSize` key +-- @treturn number Value of the `MaxSize` key +-- @treturn 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/menubar/init.lua b/menubar/init.lua new file mode 100644 index 0000000..96445e8 --- /dev/null +++ b/menubar/init.lua @@ -0,0 +1,601 @@ +--------------------------------------------------------------------------- +--- Menubar module, which aims to provide a freedesktop menu alternative. +-- +-- List of menubar keybindings: +-- --- +-- +-- <table class='widget_list' border=1> +-- <tr style='font-weight: bold;'> +-- <th align='center'>Keybinding</th> +-- <th align='center'>Description</th> +-- </tr> </td></tr> +-- <tr><td><kbd>Left</kbd><kbd>C-j</kbd></td><td> select an item on the left </td></tr> +-- <tr><td><kbd>Right</kbd><kbd>C-k</kbd></td><td> select an item on the right </td></tr> +-- <tr><td><kbd>Backspace </kbd></td><td> exit the current category if we are in any </td></tr> +-- <tr><td><kbd>Escape </kbd></td><td> exit the current directory or exit menubar </td></tr> +-- <tr><td><kbd>Home </kbd></td><td> select the first item </td></tr> +-- <tr><td><kbd>End </kbd></td><td> select the last </td></tr> +-- <tr><td><kbd>Return </kbd></td><td> execute the entry </td></tr> +-- <tr><td><kbd>C-Return </kbd></td><td> execute the command with awful.spawn </td></tr> +-- <tr><td><kbd>C-M-Return </kbd></td><td> execute the command in a terminal </td></tr> +-- </table> +-- +-- @author Alexander Yakushev <yakushev.alex@gmail.com> +-- @copyright 2011-2012 Alexander Yakushev +-- @popupmod menubar +--------------------------------------------------------------------------- + +-- Grab environment we need +local capi = { + client = client, + mouse = mouse, + screen = screen +} +local gmath = require("gears.math") +local awful = require("awful") +local gfs = require("gears.filesystem") +local common = require("awful.widget.common") +local theme = require("beautiful") +local wibox = require("wibox") +local gcolor = require("gears.color") +local gstring = require("gears.string") +local gdebug = require("gears.debug") + +local function get_screen(s) + return s and capi.screen[s] +end + + +--- Menubar normal text color. +-- @beautiful beautiful.menubar_fg_normal +-- @param color + +--- Menubar normal background color. +-- @beautiful beautiful.menubar_bg_normal +-- @param color + +--- Menubar border width. +-- @beautiful beautiful.menubar_border_width +-- @tparam[opt=0] number menubar_border_width + +--- Menubar border color. +-- @beautiful beautiful.menubar_border_color +-- @param color + +--- Menubar selected item text color. +-- @beautiful beautiful.menubar_fg_focus +-- @param color + +--- Menubar selected item background color. +-- @beautiful beautiful.menubar_bg_focus +-- @param color + +--- Menubar font. +-- @beautiful beautiful.menubar_font +-- @param[opt=beautiful.font] font + + +-- menubar +local menubar = { menu_entries = {} } +menubar.menu_gen = require("menubar.menu_gen") +menubar.utils = require("menubar.utils") + + + +local current_page = {} +-- 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 + +--- When false will hide results if the current query is empty +-- @tfield[opt=true] boolean match_empty +menubar.match_empty = 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 spacing of dpi(4) between items. +-- @tfield number list_spacing +local list_spacing = theme.xresources.apply_dpi(4) + +--- Allows user to specify custom parameters for prompt.run function +-- (like colors). This will merge with the default parameters, overriding affected values. +-- @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 = nil + +local common_args = { w = wibox.layout.fixed.vertical(), + 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='" .. gcolor.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, item args. +local function label(o) + local fg_color = theme.menubar_fg_normal or theme.menu_fg_normal or theme.fg_normal + local bg_color = theme.menubar_bg_normal or theme.menu_bg_normal or theme.bg_normal + if o.focused then + fg_color = theme.menubar_fg_focus or theme.menu_fg_focus or theme.fg_focus + bg_color = theme.menubar_bg_focus or theme.menu_bg_focus or theme.bg_focus + end + return colortext(gstring.xml_escape(o.name), fg_color), + bg_color, + nil, + o.icon, + o.icon and {icon_size=20} -- TODO: dirty fix +end + +local function load_count_table() + if instance.count_table then + return instance.count_table + end + instance.count_table = {} + local count_file_name = gfs.get_cache_dir() .. "/menu_count_file" + local count_file = io.open (count_file_name, "r") + if count_file then + for line in count_file:lines() do + local name, count = string.match(line, "([^;]+);([^;]+)") + if name ~= nil and count ~= nil then + instance.count_table[name] = count + end + end + count_file:close() + end + return instance.count_table +end + +local function write_count_table(count_table) + count_table = count_table or instance.count_table + local count_file_name = gfs.get_cache_dir() .. "/menu_count_file" + local count_file = assert(io.open(count_file_name, "w")) + for name, count in pairs(count_table) do + local str = string.format("%s;%d\n", name, count) + count_file:write(str) + end + count_file:close() +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 + count_table[curname] = (count_table[curname] or 0) + 1 + -- 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) + + local compute_text_width = function(text, s) + return wibox.widget.textbox.get_markup_geometry(text, s, instance.font)['width'] + end + + 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 border_width = theme.menubar_border_width or theme.menu_border_width or 0 + --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 - border_width * 2 + -- space character is added as input cursor placeholder + local extra_width = menubar.left_label_width + local subtracted = false + local item_height = 24 + local available_space = menubar.geometry.height - item_height * 2 -- TODO: dirty fix + local width_sum = 0 + current_page = {} + for i, item in ipairs(all_items) do + item.width = item.width or ( + compute_text_width(label(item), scr) + + (item.icon and (item_height + list_spacing) or 0) + ) -- TODO: 20 = dirty fix + local total_height = item_height * math.floor(item.width / menubar.geometry.width + 1) + if width_sum + total_height > available_space then -- TODO: 20 = dirty fix + if current_item < i then + table.insert(current_page, { name = menubar.right_label, ncon = nil }) + break + end + current_page = { { name = menubar.left_label, icon = nil }, item, } + width_sum = total_height * 2 -- TODO: 20 = dirty fix + else + table.insert(current_page, item) + width_sum = width_sum + total_height -- TODO: 20 = dirty fix + end + end + return current_page +end + +--- Update the menubar according to the command entered by user. +-- @tparam number|screen scr Screen +local function menulist_update(scr) + local query = instance.query or "" + shownitems = {} + local pattern = gstring.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 + local add_entry = function(entry) + entry.focused = false + if not current_category or entry.category == current_category then + + -- check if the query matches either the name or the commandline + -- of some entry + if string.match(entry.name, pattern) + or string.match(entry.cmdline, pattern) then + + entry.weight = 0 + entry.prio = PRIO_NONE + + -- get use count from count_table if present + -- and use it as weight + if string.len(pattern) > 0 and count_table[entry.name] ~= nil then + entry.weight = tonumber(count_table[entry.name]) + end + + -- check for prefix match + if string.match(entry.name, "^" .. pattern) + or string.match(entry.cmdline, "^" .. pattern) then + -- increase default priority + entry.prio = PRIO_NONE + 1 + else + entry.prio = PRIO_NONE + end + + table.insert (command_list, entry) + end + end + end + + -- Add entries if required + if query ~= "" or menubar.match_empty then + for _, v in ipairs(menubar.menu_entries) do + add_entry(v) + 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 + +--- Refresh menubar's cache by reloading .desktop files. +-- @tparam[opt] screen scr Screen. +-- @staticfct menubar.refresh +function menubar.refresh(scr) + scr = get_screen(scr or awful.screen.focused() or 1) + menubar.menu_gen.generate(function(entries) + menubar.menu_entries = entries + if instance then + menulist_update(scr) + end + 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 == "Up" or (mod.Control and key == "j") then + current_item = math.max(current_item - 1, 1) + return true + elseif key == "Down" or (mod.Control and key == "k") then + current_item = current_item + 1 + return true + elseif key == "Left" or key == "Right" then + local tmp_sum = 0 + local index = nil + local index_gen = function(tbl) + local idx = {} + for k,v in pairs(tbl) do + idx[v] = k + end + return idx + end + if current_page[1]["name"] == menubar.left_label then + tmp_sum = 1 + if key == "Left" then + if not index then + index = index_gen(current_page) + end + tmp_sum = #current_page - index[shownitems[current_item]] + end + elseif key == "Left" then + tmp_sum = #current_page - current_item + end + tmp_sum = tmp_sum + 1 + if current_page[#current_page]["name"] == menubar.right_label and key == "Right" then + if not index then + index = index_gen(current_page) + end + tmp_sum = index[shownitems[current_item]] + end + current_item = current_item + (#current_page - tmp_sum) * (key == "Right" and 1 or -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[opt] scr Screen. +-- @staticfct menubar.show +function menubar.show(scr) + scr = get_screen(scr or awful.screen.focused() or 1) + local fg_color = theme.menubar_fg_normal or theme.menu_fg_normal or theme.fg_normal + local bg_color = theme.menubar_bg_normal or theme.menu_bg_normal or theme.bg_normal + local border_width = theme.menubar_border_width or theme.menu_border_width or 0 + local border_color = theme.menubar_border_color or theme.menu_border_color + local font = theme.menubar_font or theme.font or "Monospace 10" + + if not instance then + -- 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 + + if menubar.cache_entries then + menubar.refresh(scr) + end + + instance = { + wibox = wibox{ + ontop = true, + bg = bg_color, + fg = fg_color, + border_width = border_width, + border_color = border_color, + font = font, + }, + widget = common_args.w, + prompt = awful.widget.prompt(), + query = nil, + count_table = nil, + font = font, + } + local layout = wibox.layout.fixed.vertical() + layout:add(instance.prompt) + layout:add(instance.widget) + instance.wibox:set_widget(layout) + end + + if instance.wibox.visible then -- Menu already shown, exit + return + elseif not menubar.cache_entries then + menubar.refresh(scr) + end + + -- Set position and size + 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 gmath.round(theme.get_font_height(font) * 1.5), + width = (geometry.width or scrgeom.width) - border_width * 2} + instance.wibox:geometry(instance.geometry) + + current_item = 1 + current_category = nil + menulist_update(scr) + + local default_prompt_args = { + prompt = "Run: ", + textbox = instance.prompt.widget, + completion_callback = awful.completion.shell, + history_path = gfs.get_cache_dir() .. "/history_menu", + done_callback = menubar.hide, + changed_callback = function(query) + instance.query = query + menulist_update(scr) + end, + keypressed_callback = prompt_keypressed_callback + } + + awful.prompt.run(setmetatable(menubar.prompt_args, {__index=default_prompt_args})) + + + instance.wibox.visible = true +end + +--- Hide the menubar. +-- @staticfct menubar.hide +function menubar.hide() + if instance then + instance.wibox.visible = false + instance.query = nil + end +end + +--- Get a menubar wibox. +-- @tparam[opt] screen scr Screen. +-- @return menubar wibox. +-- @deprecated get +function menubar.get(scr) + gdebug.deprecate("Use menubar.show() instead", { deprecated_in = 5 }) + 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 + +local mt = {} +function mt.__call(_, ...) + return menubar.get(...) +end + +return setmetatable(menubar, mt) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/menubar/menu_gen.lua b/menubar/menu_gen.lua new file mode 100644 index 0000000..19fb6e7 --- /dev/null +++ b/menubar/menu_gen.lua @@ -0,0 +1,136 @@ +--------------------------------------------------------------------------- +--- Menu generation module for menubar +-- +-- @author Antonio Terceiro +-- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev +-- @module menubar.menu_gen +--------------------------------------------------------------------------- + +-- Grab environment +local gtable = require("gears.table") +local gfilesystem = require("gears.filesystem") +local utils = require("menubar.utils") +local pairs = pairs +local ipairs = ipairs +local table = table + +local menu_gen = {} + +-- Options section + +--- Get the path to the directories where XDG menu applications are installed. +local function get_xdg_menu_dirs() + local dirs = gfilesystem.get_xdg_data_dirs() + table.insert(dirs, 1, gfilesystem.get_xdg_data_home()) + return gtable.map(function(dir) return dir .. 'applications/' end, dirs) +end + +--- Specifies all directories where menubar should look for .desktop +-- files. The search is recursive. +menu_gen.all_menu_dirs = get_xdg_menu_dirs() + +--- 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 }, + science = { app_type = "Science", name="Science", + icon_name = "applications-science", 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. +-- @staticfct menubar.menu_gen.lookup_category_icons +function menu_gen.lookup_category_icons() + for _, v in pairs(menu_gen.all_categories) do + v.icon = utils.lookup_icon(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 + +--- 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. +-- @staticfct menubar.menu_gen.generate +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 + + local name = utils.rtrim(entry.Name) or "" + local cmdline = utils.rtrim(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 + 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/menubar/utils.lua b/menubar/utils.lua new file mode 100644 index 0000000..9c8f283 --- /dev/null +++ b/menubar/utils.lua @@ -0,0 +1,430 @@ +--------------------------------------------------------------------------- +--- Utility module for menubar +-- +-- @author Antonio Terceiro +-- @copyright 2009, 2011-2012 Antonio Terceiro, Alexander Yakushev +-- @module menubar.utils +--------------------------------------------------------------------------- + +-- Grab environment +local table = table +local ipairs = ipairs +local string = string +local screen = screen +local gfs = require("gears.filesystem") +local theme = require("beautiful") +local lgi = require("lgi") +local gio = lgi.Gio +local glib = lgi.GLib +local w_textbox = require("wibox.widget.textbox") +local gdebug = require("gears.debug") +local protected_call = require("gears.protected_call") +local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) + +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. +-- @param[opt="xterm"] string +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 OnlyShowIn entry in the .desktop file. +-- @param[opt="awesome"] string +utils.wm_name = "awesome" + +-- Maps keys in desktop entries to suitable getter function. +-- The order of entries is as in the spec. +-- https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s05.html +local keys_getters +do + local function get_string(kf, key) + return kf:get_string("Desktop Entry", key) + end + local function get_strings(kf, key) + return kf:get_string_list("Desktop Entry", key, nil) + end + local function get_localestring(kf, key) + return kf:get_locale_string("Desktop Entry", key, nil) + end + local function get_localestrings(kf, key) + return kf:get_locale_string_list("Desktop Entry", key, nil, nil) + end + local function get_boolean(kf, key) + return kf:get_boolean("Desktop Entry", key) + end + + keys_getters = { + Type = get_string, + Version = get_string, + Name = get_localestring, + GenericName = get_localestring, + NoDisplay = get_boolean, + Comment = get_localestring, + Icon = get_localestring, + Hidden = get_boolean, + OnlyShowIn = get_strings, + NotShowIn = get_strings, + DBusActivatable = get_boolean, + TryExec = get_string, + Exec = get_string, + Path = get_string, + Terminal = get_boolean, + Actions = get_strings, + MimeType = get_strings, + Categories = get_strings, + Implements = get_strings, + Keywords = get_localestrings, + StartupNotify = get_boolean, + StartupWMClass = get_string, + URL = get_string, + } +end + +-- Private section + +local do_protected_call, call_callback +do + -- Lua 5.1 cannot yield across a protected call. Instead of hardcoding a + -- check, we check for this problem: The following coroutine yields true on + -- success (so resume() returns true, true). On failure, pcall returns + -- false and a message, so resume() returns true, false, message. + local _, has_yieldable_pcall = coroutine.resume(coroutine.create(function() + return pcall(coroutine.yield, true) + end)) + if has_yieldable_pcall then + do_protected_call = protected_call.call + call_callback = function(callback, ...) + return callback(...) + end + else + do_protected_call = function(f, ...) + return f(...) + end + call_callback = protected_call.call + end +end + +local all_icon_sizes = { + 'scalable', + '128x128', + '96x96', + '72x72', + '64x64', + '48x48', + '36x36', + '32x32', + '24x24', + '22x22', + '16x16' +} + +--- List of supported icon exts. +local supported_icon_file_exts = { png = 1, xpm = 2, svg = 3 } + +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 icon_lookup_path then return icon_lookup_path end + + local function ensure_args(t, paths) + if type(paths) == 'string' then paths = { paths } end + return t or {}, paths + end + + local function add_if_readable(t, paths) + t, paths = ensure_args(t, paths) + + for _, path in ipairs(paths) do + if gfs.dir_readable(path) then + table.insert(t, path) + end + end + return t + end + + local function add_with_dir(t, paths, dir) + t, paths = ensure_args(t, paths) + dir = { nil, dir } + + for _, path in ipairs(paths) do + dir[1] = path + table.insert(t, glib.build_filenamev(dir)) + end + return t + end + + icon_lookup_path = {} + local theme_priority = { 'hicolor' } + if theme.icon_theme then table.insert(theme_priority, 1, theme.icon_theme) end + + local paths = add_with_dir({}, glib.get_home_dir(), '.icons') + add_with_dir(paths, { + glib.get_user_data_dir(), -- $XDG_DATA_HOME, typically $HOME/.local/share + unpack(glib.get_system_data_dirs()) -- $XDG_DATA_DIRS, typically /usr/{,local/}share + }, 'icons') + add_with_dir(paths, glib.get_system_data_dirs(), 'pixmaps') + + local icon_theme_paths = {} + for _, theme_dir in ipairs(theme_priority) do + add_if_readable(icon_theme_paths, + add_with_dir({}, paths, theme_dir)) + end + + local app_in_theme_paths = {} + for _, icon_theme_directory in ipairs(icon_theme_paths) do + for _, size in ipairs(all_icon_sizes) do + table.insert(app_in_theme_paths, + glib.build_filenamev({ icon_theme_directory, + size, 'apps' })) + table.insert(app_in_theme_paths, + glib.build_filenamev({ icon_theme_directory, + size, 'categories' })) + end + end + add_if_readable(icon_lookup_path, app_in_theme_paths) + + return add_if_readable(icon_lookup_path, paths) +end + +--- Remove CR newline from the end of the string. +-- @param s string to trim +-- @staticfct menubar.utils.rtrim +function utils.rtrim(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 + +--- 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. +-- @staticfct menubar.utils.lookup_icon_uncached +function utils.lookup_icon_uncached(icon_file) + if not icon_file or icon_file == "" then + return false + end + + local icon_file_ext = icon_file:match(".+%.(.*)$") + if icon_file:sub(1, 1) == '/' and supported_icon_file_exts[icon_file_ext] then + -- If the path to the icon is absolute do not perform a lookup [nil if unsupported ext or missing] + return gfs.file_readable(icon_file) and icon_file or nil + else + -- Look for the requested file in the lookup path + for _, directory in ipairs(get_icon_lookup_path()) do + local possible_file = directory .. "/" .. icon_file + -- Check to see if file exists if requested with a valid extension + if supported_icon_file_exts[icon_file_ext] and gfs.file_readable(possible_file) then + return possible_file + else + -- Find files with any supported extension if icon specified without, eg: 'firefox' + for ext, _ in pairs(supported_icon_file_exts) do + local possible_file_new_ext = possible_file .. "." .. ext + if gfs.file_readable(possible_file_new_ext) then + return possible_file_new_ext + end + end + end + end + -- No icon found + 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. +-- @staticfct menubar.utils.lookup_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. +-- @staticfct menubar.utils.parse_desktop_file +function utils.parse_desktop_file(file) + local program = { show = true, file = file } + + -- Parse the .desktop file. + -- We are interested in [Desktop Entry] group only. + local keyfile = glib.KeyFile() + if not keyfile:load_from_file(file, glib.KeyFileFlags.NONE) then + return nil + end + + -- In case [Desktop Entry] was not found + if not keyfile:has_group("Desktop Entry") then + return nil + end + + for _, key in pairs(keyfile:get_keys("Desktop Entry")) do + local getter = keys_getters[key] or function(kf, k) + return kf:get_string("Desktop Entry", k) + end + program[key] = getter(keyfile, key) + 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 true + if program.NoDisplay then + program.show = false + else + -- Only check these values is NoDisplay is true (or non-existent) + + -- Only show the program if there is no OnlyShowIn attribute + -- or if it contains wm_name or wm_name is empty + if utils.wm_name ~= "" then + if program.OnlyShowIn then + program.show = false -- Assume false until found + for _, wm in ipairs(program.OnlyShowIn) do + if wm == utils.wm_name then + program.show = true + break + end + end + else + program.show = true + end + end + + -- Only need to check NotShowIn if the program is being shown + if program.show and program.NotShowIn then + for _, wm in ipairs(program.NotShowIn) do + if wm == utils.wm_name then + program.show = false + break + end + end + end + end + + -- Look up for a icon. + if program.Icon then + program.icon_path = utils.lookup_icon(program.Icon) + end + + -- Make the variable lower-case like the rest of them + if program.Categories then + program.categories = program.Categories + 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. +-- @staticfct menubar.utils.parse_dir +function utils.parse_dir(dir_path, callback) + + local function get_readable_path(file) + return file:get_path() or file:get_uri() + end + + local function parser(file, programs) + -- Except for "NONE" there is also NOFOLLOW_SYMLINKS + local query = gio.FILE_ATTRIBUTE_STANDARD_NAME .. "," .. gio.FILE_ATTRIBUTE_STANDARD_TYPE + local enum, err = file:async_enumerate_children(query, gio.FileQueryInfoFlags.NONE) + if not enum then + gdebug.print_warning(get_readable_path(file) .. ": " .. tostring(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 + gdebug.print_error(get_readable_path(file) .. ": " .. tostring(enum_err)) + return + end + for _, info in ipairs(list) do + local file_type = info:get_file_type() + local file_child = enum:get_child(info) + if file_type == 'REGULAR' then + local path = file_child:get_path() + if path then + local success, program = pcall(utils.parse_desktop_file, path) + if not success then + gdebug.print_error("Error while reading '" .. path .. "': " .. program) + elseif program then + table.insert(programs, program) + end + end + elseif file_type == 'DIRECTORY' then + parser(file_child, programs) + end + end + if #list == 0 then + break + end + end + enum:async_close() + end + + gio.Async.start(do_protected_call)(function() + local result = {} + parser(gio.File.new_for_path(dir_path), result) + call_callback(callback, result) + end) +end + +-- luacov: disable + +function utils.compute_textbox_width(textbox, s) + gdebug.deprecate("Use 'width, _ = textbox:get_preferred_size(s)' directly.", {deprecated_in=4}) + s = screen[s or mouse.screen] + local w, _ = textbox:get_preferred_size(s) + return w +end + +function utils.compute_text_width(text, s, font) + gdebug.deprecate("Use 'width = textbox.get_markup_geometry(text, s, font)['width']'.", {deprecated_in=4}) + return w_textbox.get_markup_geometry(text, s, font)['width'] +end + +-- luacov: enable + +return utils + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/rc.lua b/rc.lua index 8c468fa..e3ac851 100644 --- a/rc.lua +++ b/rc.lua @@ -3,6 +3,7 @@ pcall(require, "luarocks.loader") -- Standard awesome library +local capi = {awesome = awesome} local gears = require("gears") local awful = require("awful") require("awful.autofocus") @@ -13,15 +14,191 @@ local beautiful = require("beautiful") -- Notification library local naughty = require("naughty") local menubar = require("menubar") -local hotkeys_popup = require("awful.hotkeys_popup") +local menu_width = 200 +local tmp_screen = { 1080, 1920 } +menubar.geometry = { height = tmp_screen[1], width = menu_width, x = tmp_screen[2] - menu_width } + + +--local hotkeys_popup = require("awful.hotkeys_popup") +local hotkeys = require("awful.hotkeys_popup"); --local hotkeys = require("awful.hotkeys_popup") --local hotkeys_popup = hotkeys_popup.widget.new({ width = 100, height = 100 }) --hotkeys_popup.show_help = hotkeys_popup.widget.show_help -- Enable hotkeys help widget for VIM and other apps -- when client with a matching name is opened: -require("awful.hotkeys_popup.keys.vim") ---local cairo = require("lgi").cairo +--vim = require("awful.hotkeys_popup.keys.vim") +local my_hotkeys_popup = hotkeys.widget.new({ width = 1870, height = 1050}); + +local vim_rule_any = {name={"vim", "VIM"}} +for group_name, group_data in pairs({ + ["VIM: motion"] = { color="#009F00", rule_any=vim_rule_any }, + ["VIM: command"] = { color="#aFaF00", rule_any=vim_rule_any }, + ["VIM: command (insert)"] = { color="#cF4F40", rule_any=vim_rule_any }, + ["VIM: operator"] = { color="#aF6F00", rule_any=vim_rule_any }, + ["VIM: find"] = { color="#65cF9F", rule_any=vim_rule_any }, + ["VIM: scroll"] = { color="#659FdF", rule_any=vim_rule_any }, +}) do + my_hotkeys_popup:add_group_rules(group_name, group_data) +end + + +local vim_keys = { + + ["VIM: motion"] = {{ + modifiers = {}, + keys = { + ['`']="goto mark", + ['0']='"hard" BOL', + ['-']="prev line", + w="next word", + e="end word", + ['[']=". misc", + [']']=". misc", + ["'"]=". goto mk. BOL", + b="prev word", + ["|"]='BOL/goto col', + ["$"]='EOL', + ["%"]='goto matching bracket', + ["^"]='"soft" BOL', + ["("]='sentence begin', + [")"]='sentence end', + ["_"]='"soft" BOL down', + ["+"]='next line', + W='next WORD', + E='end WORD', + ['{']="paragraph begin", + ['}']="paragraph end", + G='EOF/goto line', + H='move cursor to screen top', + M='move cursor to screen middle', + L='move cursor to screen bottom', + B='prev WORD', + } + }, { + modifiers = {"Ctrl"}, + keys = { + u="half page up", + d="half page down", + b="page up", + f="page down", + o="prev mark", + } + }}, + + ["VIM: operator"] = {{ + modifiers = {}, + keys = { + ['=']="auto format", + y="yank", + d="delete", + c="change", + ["!"]='external filter', + ['<']='unindent', + ['>']='indent', + } + }}, + + ["VIM: command"] = {{ + modifiers = {}, + keys = { + ['~']="toggle case", + q=". record macro", + r=". replace char", + u="undo", + p="paste after", + gg="go to the top of file", + gf="open file under cursor", + x="delete char", + v="visual mode", + m=". set mark", + ['.']="repeat command", + ["@"]='. play macro', + ["&"]='repeat :s', + Q='ex mode', + Y='yank line', + U='undo line', + P='paste before cursor', + D='delete to EOL', + J='join lines', + K='help', + [':']='ex cmd line', + ['"']='. register spec', + ZZ='quit and save', + ZQ='quit discarding changes', + X='back-delete', + V='visual lines selection', + } + }, { + modifiers = {"Ctrl"}, + keys = { + w=". window operations", + r="redo", + ["["]="normal mode", + a="increase number", + x="decrease number", + g="file/cursor info", + z="suspend", + c="cancel/normal mode", + v="visual block selection", + } + }}, + + ["VIM: command (insert)"] = {{ + modifiers = {}, + keys = { + i="insert mode", + o="open below", + a="append", + s="subst char", + R='replace mode', + I='insert at BOL', + O='open above', + A='append at EOL', + S='subst line', + C='change to EOL', + } + }}, + + ["VIM: find"] = {{ + modifiers = {}, + keys = { + [';']="repeat t/T/f/F", + [',']="reverse t/T/f/F", + ['/']=". find", + ['?']='. reverse find', + n="next search match", + N='prev search match', + f=". find char", + F='. reverse find char', + t=". 'till char", + T=". reverse 'till char", + ["*"]='find word under cursor', + ["#"]='reverse find under cursor', + } + }}, + + ["VIM: scroll"] = {{ + modifiers = {}, + keys = { + zt="scroll cursor to the top", + zz="scroll cursor to the center", + zb="scroll cursor to the bottom", + } + },{ + modifiers = {"Ctrl"}, + keys = { + e="scroll line up", + y="scroll line down", + } + }}, +} + +my_hotkeys_popup:add_hotkeys(vim_keys) + +--my_hotkeys_popup.keys.vim = vim +--local cairo = require("lgi").cairo + -- My custom libs local vicious = require("vicious") @@ -75,6 +252,7 @@ modkey = "Mod4" -- Table of layouts to cover with awful.layout.inc, order matters. awful.layout.layouts = { + awful.layout.suit.spiral, awful.layout.suit.floating, awful.layout.suit.tile, awful.layout.suit.tile.left, @@ -82,7 +260,6 @@ awful.layout.layouts = { awful.layout.suit.tile.top, awful.layout.suit.fair, awful.layout.suit.fair.horizontal, - awful.layout.suit.spiral, awful.layout.suit.spiral.dwindle, awful.layout.suit.max, awful.layout.suit.max.fullscreen, @@ -97,7 +274,7 @@ awful.layout.layouts = { -- {{{ Menu -- Create a launcher widget and a main menu myawesomemenu = { - { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end }, + { "hotkeys", function() my_hotkeys_popup:show_help(nil, awful.screen.focused()) end }, { "manual", terminal .. " -e man awesome" }, { "edit config", editor_cmd .. " " .. awesome.conffile }, { "restart", awesome.restart }, @@ -119,7 +296,18 @@ menubar.utils.terminal = terminal -- Set the terminal for applications that requ -- Keyboard map indicator and switcher mykeyboardlayout = awful.widget.keyboardlayout() - +--mykeyboardlayout.widget.forced_height = 20 +--mykeyboardlayout.widget.text = mykeyboardlayout.widget.text:gsub("%s+", "") +--mykeyboardlayout.widget.forced_width = 20 +local clean_textbox = function(w) + w.text = w.text:sub(2) + w.text = w.text:sub(1, -2) +end +capi.awesome.connect_signal("xkb::map_changed", + function () clean_textbox(mykeyboardlayout.widget) end) +capi.awesome.connect_signal("xkb::group_changed", + function () clean_textbox(mykeyboardlayout.widget) end) +clean_textbox(mykeyboardlayout.widget) -- {{{ Wibar -- Create a wibox for each screen and add it @@ -194,7 +382,7 @@ end ---- datewidget = wibox.widget.textbox() -vicious.register(datewidget, vicious.widgets.date, "%b %d, %R ") +vicious.register(datewidget, vicious.widgets.date, "%m %d %H %M %S", 1) --memwidget = wibox.widget.textbox() --vicious.cache(vicious.widgets.mem) @@ -204,16 +392,19 @@ vicious.register(datewidget, vicious.widgets.date, "%b %d, %R ") batwidget = wibox.widget.progressbar() batbox = wibox.layout.margin( wibox.widget{ { max_value = 1, widget = batwidget, - border_width = 0.5, border_color = "#000000", - color = { type = "linear", - from = { 0, 0 }, - to = { 0, 30 }, - stops = { { 0, "#AECF96" }, - { 1, "#FF5656" } } } }, - forced_height = 10, forced_width = 8, - direction = 'east', color = beautiful.fg_widget, + border_width = 0, border_color = "#000000", + color = "#FFFFFF", + background_color = "#000000" + }, + --color = { type = "linear", + -- from = { 0, 0 }, + -- to = { 0, 30 }, + -- stops = { { 0, "#FFFFFF" }, + -- { 1, "#000000" } } } }, + forced_height = 1, forced_width = 1, + direction = 'south', color = beautiful.fg_widget, layout = wibox.container.rotate }, - 1, 4, 1, 1) + 0, 0, 0, 0) -- Register battery widget vicious.register(batwidget, vicious.widgets.bat, "$2", 1, "BAT1") @@ -269,11 +460,87 @@ awful.screen.connect_for_each_screen(function(s) awful.button({ }, 4, function () awful.layout.inc( 1) end), awful.button({ }, 5, function () awful.layout.inc(-1) end))) -- Create a taglist widget - s.mytaglist = awful.widget.taglist { - screen = s, - filter = awful.widget.taglist.filter.all, - buttons = taglist_buttons - } + --s.mytaglist = awful.widget.taglist { + -- screen = s, + -- filter = awful.widget.taglist.filter.all, + -- buttons = taglist_buttons + --} +s.mytaglist = awful.widget.taglist { + screen = s, + filter = awful.widget.taglist.filter.all, + style = { + shape = function (cr, width, height) gears.shape.powerline(cr, width*8/10, height, height/4) end + }, + layout = { + spacing = -14, + spacing_widget = { + color = '#dddddd', + shape = function (cr, width, height) gears.shape.powerline(cr, width/2, height, height/4) end, + widget = wibox.widget.separator, + }, + layout = wibox.layout.fixed.horizontal + }, + widget_template = { + { + { + { + { + --{ + { + id = 'index_role', + font = "Indie Flower Bold 11", + widget = wibox.widget.textbox, + }, + + widget = wibox.container.place, + --}, + --bg = '#55000044', + --shape = gears.shape.circle, + --widget = wibox.container.background, + }, + layout = wibox.container.rotate, + direction = "east", + }, + --{ + -- { + -- id = 'icon_role', + -- widget = wibox.widget.imagebox, + -- }, + -- margins = 2, + -- widget = wibox.container.margin, + --}, + --{ + -- id = 'text_role', + -- widget = wibox.widget.textbox, + --}, + layout = wibox.layout.fixed.horizontal, + }, + left = 5, + right = 9, + widget = wibox.container.margin + }, + id = 'background_role', + widget = wibox.container.background, + -- Add support for hover colors and an index label + create_callback = function(self, c3, index, objects) --luacheck: no unused args + self:get_children_by_id('index_role')[1].markup = '<b>'..index..'</b>' + --self:connect_signal('mouse::enter', function() + -- if self.bg ~= '#ff000033' then + -- self.backup = self.bg + -- self.has_backup = true + -- end + -- self.bg = '#ff00ff55' + --end) + --self:connect_signal('mouse::leave', function() + -- if self.has_backup then self.bg = self.backup end + --end) + end, + --update_callback = function(self, c3, index, objects) --luacheck: no unused args + -- self:get_children_by_id('index_role')[1].markup = '<b> '..index..' </b>' + --end, + }, + buttons = taglist_buttons +} -- Create a tasklist widget s.mytasklist = awful.widget.tasklist { @@ -283,29 +550,79 @@ awful.screen.connect_for_each_screen(function(s) } -- Create the wibox - s.mywibox = awful.wibar({ position = "bottom", screen = s }) + s.mywibox = awful.wibar({ position = "left", screen = s }) -- Add widgets to the wibox s.mywibox:setup { - layout = wibox.layout.align.horizontal, - { -- Left widgets - layout = wibox.layout.fixed.horizontal, - mylauncher, - s.mytaglist, - s.mypromptbox, - }, - s.mytasklist, -- Middle widget - { -- Right widgets - layout = wibox.layout.fixed.horizontal, - wibox.widget.systray(), - memwidget, - swapwidget, - cpuwidget, - mykeyboardlayout, - datewidget, - batbox, - s.mylayoutbox, - }, + layout = wibox.container.rotate, + direction = "west", + { + layout = wibox.layout.align.vertical, + { + layout = wibox.layout.constraint, + strategy = "max", + height = 18, + { + layout = wibox.layout.align.horizontal, + { -- Left widgets + layout = wibox.layout.fixed.horizontal, + { + layout = wibox.container.rotate, + direction = "east", + mylauncher, + }, + s.mytaglist, + s.mypromptbox, + }, + s.mytasklist, -- Middle widget + { -- Right widgets + layout = wibox.layout.fixed.horizontal, + wibox.widget.systray(), + memwidget, + swapwidget, + cpuwidget, + { + layout = wibox.container.rotate, + direction = "east", + mykeyboardlayout.widget, + }, + { + forced_width = 1, + orientation = "vertical", + widget = wibox.widget.separator + }, + { + thickness = 0, + forced_width = 6, + orientation = "vertical", + widget = wibox.widget.separator + }, + { + layout = wibox.container.rotate, + direction = "east", + datewidget, + }, + s.mylayoutbox, + }, + }, + }, + { + layout = wibox.layout.constraint, + { + layout = wibox.layout.flex.horizontal, + { + layout = wibox.container.rotate, + direction = "north", + batbox, + }, + { + layout = wibox.container.rotate, + direction = "south", + batbox, + } + } + } + } } end) -- }}} @@ -320,7 +637,10 @@ root.buttons(gears.table.join( -- {{{ Key bindings globalkeys = gears.table.join( - awful.key({ modkey, }, "s", hotkeys_popup.show_help, + awful.key({ modkey, }, "s", + function () + my_hotkeys_popup:show_help(nil, awful.screen.focused()) + end, {description="show help", group="awesome"}), awful.key({ modkey, }, "Left", awful.tag.viewprev, {description = "view previous", group = "tag"}), @@ -601,7 +921,7 @@ client.connect_signal("manage", function (c) -- Set the windows at the slave, -- i.e. put it at the end of others instead of setting it master. -- if not awesome.startup then awful.client.setslave(c) end - + c.shape = beautiful.shape if awesome.startup and not c.size_hints.user_position and not c.size_hints.program_position then @@ -661,7 +981,16 @@ end) client.connect_signal("mouse::enter", function(c) c:emit_signal("request::activate", "mouse_enter", {raise = false}) end) - -client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end) -client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) +--beautiful.border_normal = "#00000055" +--beautiful.border_focus = "#00000000" +client.connect_signal("focus", function(c) + c.border_color = beautiful.border_focus + c.border_width = beautiful.border_width_focus +end) +client.connect_signal("unfocus", function(c) + c.border_color = beautiful.border_normal + c.border_width = beautiful.border_width + c.useless_gap = 0 +end) + -- }}} diff --git a/themes/zenburn/awesome-icon.png b/themes/zenburn/awesome-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..60be4f2553646a0d9f9d96aa4024fc2f2a3b502b GIT binary patch literal 4778 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 literal 0 HcmV?d00001 diff --git a/themes/zenburn/submenu.png b/themes/zenburn/submenu.png new file mode 100644 index 0000000000000000000000000000000000000000..b2778e2ebe7f632abc51257e3609992bda592a83 GIT binary patch literal 440 zcmV;p0Z0CcP)<h;3K|Lk000e1NJLTq000>P000>X1^@s6#OZ}&00004b3#c}2nYxW zd<bNS00009a7bBm000Fg000Fg0RaTRiU0rr8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10X0cPK~zY`?bWSMLQxoi@pHXypaueNCW-_j#Zk;eoW<luWRpO? zg=(@8sWt<ZVsp3MVvqnEXX72P%K^4KJ~kcVW8xoh=QP5Te><PA0+j320kMMYcDovI z;uJB)%(T|y>2z8Hj+`L9UQg2LG>t}MEh2;Ea(U|nQA(kdBAd<9YPAv(`2en+Ap7$9 zJe^KwE+TKhr4wXdu~;OEA~PC|UVw8a$i8y9{L}CE<2a6=fKw-kQVQSqsaC6BA~H^r z<Pq?!BdJu1APCmO;c&3oZ0@YC#Pd8VmCCo)dTflT1HRSmDwRsV-EKFYOeW93nbm_Y z6bgi4Xhh@{xUhPKbGaPtc6%-&@4%JS$C$}vXf~UPh<t9h+Z*fO%3`sYiHKgUR`)LF i$pdhFn2ZPH-~9m+jnqF(&Qk*b0000<MNUMnLSTab-nz*E literal 0 HcmV?d00001 diff --git a/themes/zenburn/taglist/squarefz.png b/themes/zenburn/taglist/squarefz.png index 0927720449ef42f4117e0487fe6ff82b7482804e..a65608b927337512345e8ef03ea4f4ced250092c 100644 GIT binary patch literal 4815 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 delta 100 zcmX@Fx`J_nga#us0|P_v8#_55#aJBV?!>U}oXkrghb_P-#C7`y<q!AQe|_4ve{!af zg~3e@c}{s1`*f>*paMQm7sn8e>&ZV3Ff>*$GSn|)K6uaOI7lmlr>mdKI;Vst07#f2 Aa{vGU diff --git a/themes/zenburn/taglist/squarefz_orig.png b/themes/zenburn/taglist/squarefz_orig.png new file mode 100644 index 0000000000000000000000000000000000000000..0927720449ef42f4117e0487fe6ff82b7482804e GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^EI=&G$P6TV-`L3kDaPU;cPEB*=VV?2IcxzwA+Fmu zD1W%W{_E4W{UGU*AirP+hi5m^K%69RcNc~ZR#^`qhqJ&VvY3H^?+6GpPSxg<1`4v5 zc>21s-{g?zlvlA&x9SH9@p-y9hHzX@{&9ezv4WAIei`$@dp5^GwlR3R`njxgN@xNA DFNrJj literal 0 HcmV?d00001 diff --git a/themes/zenburn/taglist/squarez.png b/themes/zenburn/taglist/squarez.png index 9b41c26ea753665cfd295ef36083dd55e6f4ae71..0fd3c2a6e4040beed91bc1c08fe07c691742d95b 100644 GIT binary patch literal 4886 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 J;&HRn{|0DsNxuL9 delta 103 zcmbQHwwiH*ga#us0|P_v8#_55#aJBV?!>U}oXkrghb_P-#C7|I%XjXa+3V!9ck%`y z3*(y{@|+6Hhc++00aPI9>Eal|aXtCR0Ru)3dxHn83~6f2jHS<)=>jDgJYD@<);T3K F0RW|;AuIp@ diff --git a/themes/zenburn/taglist/squarez_orig.png b/themes/zenburn/taglist/squarez_orig.png new file mode 100644 index 0000000000000000000000000000000000000000..9b41c26ea753665cfd295ef36083dd55e6f4ae71 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^EI=&G$P6TV-`L3kDaPU;cPEB*=VV?2IcxzwA+Fmu zT)uPX%w8v-y&&n5AirP+hi5m^K%69RcNc~ZR#^`qhqJ&VvY3H^?+6GpPSxg<1`4v5 zc>21s-{g?zRA4@|dFc(Hkf5iFV+hCf<R1qN7&+_>9<VZ`sWCH_K3}E_lw|O9^>bP0 Hl+XkKo;)j; literal 0 HcmV?d00001 diff --git a/themes/zenburn/theme.lua b/themes/zenburn/theme.lua index 75fdee7..0adfaca 100644 --- a/themes/zenburn/theme.lua +++ b/themes/zenburn/theme.lua @@ -5,9 +5,10 @@ -- By Adrian C. (anrxc) -- ---------------------------------------- -local themes_path = require("gears.filesystem").get_themes_dir() +local themes_path = "/home/surferlul/.config/awesome/themes/" local dpi = require("beautiful.xresources").apply_dpi local beautiful = require("beautiful") +local gears = require("gears") -- {{{ Main local theme = {} @@ -34,9 +35,9 @@ theme.hotkeys_fg = "#EEEEFF" theme.hotkeys_label_fg = "#111122" theme.hotkeys_modifiers_fg = "#DD7777" theme.hotkeys_description_font = "Indie Flower Bold 10" -theme.hotkeys_border_width = 1 +theme.hotkeys_border_width = 2 theme.hotkeys_border_color = "#6f6f6f55" - +theme.hotkeys_shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, 15) end theme.menubar_bg_normal = "#11112299" theme.menubar_fg_normal = "#FFBBBB" theme.menubar_bg_focus = "#333344FF" @@ -48,10 +49,12 @@ theme.menu_bg_focus = "#333344FF" theme.menu_fg_focus = "#BBBBFF" -- {{{ Borders -theme.useless_gap = dpi(2) -theme.border_width = dpi(1) -theme.border_normal = "#6F6F6F55" -theme.border_focus = "#6F6F6F55" +theme.shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, 4) end +theme.useless_gap = 2 +theme.border_width = 2 +theme.border_width_focus = 2 +theme.border_normal = "#00000077" -- basically no border +theme.border_focus = "#00000000" -- slightly more lit up than the shadow theme.border_marked = "#CC939355" -- }}} @@ -103,7 +106,7 @@ theme.taglist_squares_unsel = themes_path .. "zenburn/taglist/squarez.png" -- {{{ Misc theme.awesome_icon = themes_path .. "zenburn/awesome-icon.png" -theme.menu_submenu_icon = themes_path .. "default/submenu.png" +theme.menu_submenu_icon = themes_path .. "zenburn/submenu.png" -- }}} -- {{{ Layout