From d6cd57e474a8daca20ebfc70a2b9e8a44e78f22d Mon Sep 17 00:00:00 2001 From: twa022 Date: Wed, 21 Sep 2022 16:53:57 -0400 Subject: [PATCH] Add settings GUI and new configuration options (#69) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [200~Add support for vala-panel to the terminate_appmenu_registrar function. * Use new get_desktop_env() wrapper function to check for Budgie too. * Add gsettings option to pin HUD to screen rather that window. * Try importing xfconf regardless of desktop environment. * use gdk_screen_get_resolution to get DPI and use the get_dpi method as a fallback. * Better checking for avoiding panel overlap. * Speed up getting the process command line by only get the process command line for the process we care about. * Add internal settings store to ease keeping track of settings. Make location, menu separator, and width customizable. Try to do work only when a setting changes rather than every time we call the HUD. * Minor fixes * Actually set the custom width. * Don't use a negative margin * Fix list of valid locations and add more logging. * Add a GUI for changing the settings. Move common functions and defaults into a common file. * Update README * Actually install the common.py file. Whoops. * Improve isrtl function and add custom CSS for invalid fields. * Add custom CSS for changed values. * Rewrite hud-settings.py to split all the class methods out from __init__. * Add a dialog from kupfer to configure the keyboard shortcut. TODO: doesn't let us select a single modifier key like the default Alt_L * Update README * Move duplicate code getting the rofi theme list into common.py * Add ability to save recently selected menu items per application and show them at the top of the HUD list * Change the menu separator to being selectable from a list of left/right arrow pairs rather than a free for all. * Make sure the session store of the recently used list is updated when updating from gsettings or the settings app. * Add a way to select single modifier keys for the shortcut in the settings app. * Give the fields in the settings app better names. * Groundwork for making the program translatable. * Change the gettext domain to 'mate-hud' * Change all the python script shebangs to python3 from python * Add some comments. Update the separator on each invocation in case interface direction changes. * Store the menu separator pair so we don't query from gsettings every invocation but can still set to the LTR or RTL variant. * Set the preferences-system icon in the desktop file too (pending our own) * Update README * Remove validate_menu_separator function that was based on the old way of storing it * Change the width entry to a SpinButton. Don't allow invalid entries for width or theme -- if the value in gsettings is wrong, change it back to the default. Remove invalid style. * Don't accidentally add 'Recently Used ------...' to the list of recently used menu items. * Change how the values for 'recently-used-max' are interpreted to give an option to disable saving recently used menu items * Add our own icon * Update the keyboard shortcut dialog ui file against GTK3 (3.16+) * Install the rofi themes to rofi's prefix regardless where we set the prefix for the mate-hud installation. * Add plotinus service as a last method to try to retrieve menus (credit to gnome-hud). * Support plotinus from original repo: https://github.com/p-e-w/plotinus or unityx-plotinus. * Remove deprecated functions. Correctly return whether the GTK interface succeeded or not. * Remove an duplicate output option passed to inkscape in the gen_icons script * Add @2 png icons and install the scalable icon to the right directory in the hicolor icon theme. * Watch for changes to the panel and update the margin asynchronously as needed. * Get xfconf information over dbus rather than through GI -- removes optional dependency on gir1.2-xfconf0 * Add some budgie support. * Make the panel property listeners work. * Remove last xfconf gi code and switch to dbus. * Fix checking if appmenu loaded when running mate-panel * Remove unused get_desktop_env function * Add support for avoiding overlapping vala-panel. * Check which plank dock is running in case it's not the default when we're calculating the margin. * Terminate registrar (if appmenu isn't running) and kill plotinus on keyboard interrupt. * Only look in the user config dir for vala-panel config. * Try to make hud_settings.py a little more maintainable and fix using a custom width in units other than pixels. * Make sure the vala panel config directory exists before we try to watch it. * Add recently used max and none to the defaults constants. * Make HUD prompt configurable. * Add placeholder text for the prompt so you can see what the default is * Only create the settings store once. Try using a color from the theme to indicate changes in the settings app. * Do a better job using the theme color to indicate changes in the settings app. * Pipe menu items to rofi one at a time so we can show the HUD before we have collected all the menu items. For programs with many menu items makes the HUD launch almost instantly instead of having a lag. (Credit to zren/plasma-hud) * Explore the menus from first to last when using the GTK interface too. * Add HUD transparency option in gsettings. * Add transparency controls to the settings app. * Wait until we're sure we have a menu to display to start rofi. Co-authored-by: Martin Wimpress <304639+flexiondotorg@users.noreply.github.com> --- README.md | 31 +- gen_icons.sh | 31 + setup.py | 35 +- usr/lib/mate-hud/common.py | 255 +++++ usr/lib/mate-hud/getkey_dialog.py | 138 +++ usr/lib/mate-hud/getkey_dialog.ui | 192 ++++ usr/lib/mate-hud/hud-settings.py | 523 ++++++++++ usr/lib/mate-hud/i18n.py | 12 + usr/lib/mate-hud/mate-hud | 978 ++++++++++++++---- usr/share/applications/hud-settings.desktop | 9 + .../glib-2.0/schemas/org.mate.hud.gschema.xml | 104 ++ .../icons/hicolor/1024x1024/apps/mate-hud.png | Bin 0 -> 27569 bytes .../icons/hicolor/128x128/apps/mate-hud.png | Bin 0 -> 2965 bytes .../icons/hicolor/128x128@2/apps/mate-hud.png | Bin 0 -> 5999 bytes .../icons/hicolor/16x16/apps/mate-hud.png | Bin 0 -> 534 bytes .../icons/hicolor/16x16@2/apps/mate-hud.png | Bin 0 -> 905 bytes .../icons/hicolor/22x22/apps/mate-hud.png | Bin 0 -> 669 bytes .../icons/hicolor/22x22@2/apps/mate-hud.png | Bin 0 -> 1128 bytes .../icons/hicolor/24x24/apps/mate-hud.png | Bin 0 -> 726 bytes .../icons/hicolor/24x24@2/apps/mate-hud.png | Bin 0 -> 1245 bytes .../icons/hicolor/256x256/apps/mate-hud.png | Bin 0 -> 5999 bytes .../icons/hicolor/256x256@2/apps/mate-hud.png | Bin 0 -> 12729 bytes .../icons/hicolor/32x32/apps/mate-hud.png | Bin 0 -> 905 bytes .../icons/hicolor/32x32@2/apps/mate-hud.png | Bin 0 -> 1610 bytes .../icons/hicolor/48x48/apps/mate-hud.png | Bin 0 -> 1245 bytes .../icons/hicolor/48x48@2/apps/mate-hud.png | Bin 0 -> 2348 bytes .../icons/hicolor/512x512/apps/mate-hud.png | Bin 0 -> 12729 bytes .../icons/hicolor/64x64/apps/mate-hud.png | Bin 0 -> 1610 bytes .../icons/hicolor/64x64@2/apps/mate-hud.png | Bin 0 -> 2965 bytes .../icons/hicolor/scalable/apps/mate-hud.svg | 74 ++ usr/share/pixmaps/mate-hud.svg | 74 ++ 31 files changed, 2240 insertions(+), 216 deletions(-) create mode 100755 gen_icons.sh create mode 100644 usr/lib/mate-hud/common.py create mode 100644 usr/lib/mate-hud/getkey_dialog.py create mode 100644 usr/lib/mate-hud/getkey_dialog.ui create mode 100755 usr/lib/mate-hud/hud-settings.py create mode 100644 usr/lib/mate-hud/i18n.py create mode 100644 usr/share/applications/hud-settings.desktop create mode 100644 usr/share/icons/hicolor/1024x1024/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/128x128/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/128x128@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/16x16/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/16x16@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/22x22/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/22x22@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/24x24/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/24x24@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/256x256/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/256x256@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/32x32/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/32x32@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/48x48/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/48x48@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/512x512/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/64x64/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/64x64@2/apps/mate-hud.png create mode 100644 usr/share/icons/hicolor/scalable/apps/mate-hud.svg create mode 100644 usr/share/pixmaps/mate-hud.svg diff --git a/README.md b/README.md index 4bb67d8..5611cf2 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,13 @@ includes an implementation of the `com.canonical.AppMenu.Registrar` DBus service. Applications exporting their menu via `dbusmenu` need this service to run. `mate-hud.py` tries to get the menu of the currently focused window, lists possible actions and asks the user which one to -run. `mate-hud.py`, binds itself to the `space` keyboard -shortcut by default. +run. `mate-hud.py`, binds itself to the `Alt_L` keyboard +shortcut by default (can be changed in the settings GUI). -### Gsettings +### Settings -`mate-hud.py` reads two gsettings keys: +`mate-hud` includes a small GUI for configuring settings: `hud-settings.py` +which should show up in your applications menu. `mate-hud.py` reads two gsettings keys: * `org.mate.hud`: `shortcut` (Default: `'Alt_L'`) * `org.mate.hud`: `rofi-theme` (Default: `mate-hud`) @@ -44,25 +45,18 @@ shortcut by default. which the `mate-hud` Debian package will do, and the `enabled` key is set to *True* using something like `dconf-editor`. -`mate-hud` -can be enabled or disabled by MATE Tweak under `Panel > Panel Features > Enable HUD`. +`mate-hud` can be enabled or disabled by MATE Tweak under `Panel > Panel Features > Enable HUD`. ### Themes -`mate-hud.py` uses the `mate-hud` theme by default. -The included `mate-hud` and `mate-hud-rounded` themes try to use colors -from your GTK theme. You can see the available rofi themes in -`/usr/share/rofi/themes` or add your own to `~/.local/share/rofi/themes` -Theme files are named `.rasi` and you can change the theme using -the following command: - -``` -gsettings set org.mate.hud rofi-theme -``` +`mate-hud.py` uses the `mate-hud-rounded` theme by default. +The included `mate-hud` and `mate-hud-rounded` themes and their HiDPI variants +try to use colors from your GTK theme and your system font. You can see +the available themes and make changes with the included settings program. ### Manual Setup - * The `vala-panel-appmenu` applet for MATE should be added to a panel. + * The `vala-panel-appmenu` applet for MATE or XFCE should be added to a panel. * `mate-hud.py` should be started on session start-up. * The following should be added to the users `~/.profile` or `/etc/profile.d` or `/etc/X11/Xsession.d/`. @@ -84,11 +78,14 @@ export UBUNTU_MENUPROXY=1 * `mate-desktop` * `python3` * `python3-dbus` + * `python3-pkgconfig` + * `python3-pyinotify` * `python3-setproctitle` * `python3-xlib` * `rofi` * `unity-gtk2-module` * `unity-gtk3-module` + * `plotinus` (optional - additional menu backend for some GTK3 programs without a traditional menu) A reference package for Debian/Ubuntu is available from: diff --git a/gen_icons.sh b/gen_icons.sh new file mode 100755 index 0000000..6831ecf --- /dev/null +++ b/gen_icons.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +dir="$( dirname "$(readlink -f "$0")" )" + +if [ ! -f "${dir}"/usr/share/pixmaps/mate-hud.svg ] ; then + echo "mate-hud.svg not found" >&2 + exit 1 +fi + +if [ ! `which inkscape 2>/dev/null` ] ; then + echo "inkscape required to convert svg to png" + exit 1 +fi + +rm -fr "${dir}"/usr/share/icons + +for d in 16 22 24 32 48 64 128 256 512 1024; do + install -dm755 "${dir}"/usr/share/icons/hicolor/${d}x${d}/apps + inkscape -w ${d} -h ${d} "${dir}"/usr/share/pixmaps/mate-hud.svg \ + -o "${dir}"/usr/share/icons/hicolor/${d}x${d}/apps/mate-hud.png +done + +for d in 16 22 24 32 48 64 128 256; do + d2=$(( $d * 2 )) + install -dm755 "${dir}"/usr/share/icons/hicolor/${d}x${d}@2/apps + inkscape -w ${d2} -h ${d2} "${dir}"/usr/share/pixmaps/mate-hud.svg \ + -o "${dir}"/usr/share/icons/hicolor/${d}x${d}@2/apps/mate-hud.png +done + +install -Dm644 "${dir}"/usr/share/pixmaps/mate-hud.svg \ + "${dir}"/usr/share/icons/hicolor/scalable/apps/mate-hud.svg diff --git a/setup.py b/setup.py index e048157..8b5387a 100755 --- a/setup.py +++ b/setup.py @@ -28,6 +28,9 @@ import DistUtilsExtra.command.build_i18n import DistUtilsExtra.command.clean_i18n +import pkgconfig +rofi_prefix = pkgconfig.variables('rofi').get('prefix') + __VERSION__ = '22.04.4' def datafilelist(installbase, sourcebase): @@ -41,12 +44,36 @@ def datafilelist(installbase, sourcebase): data_files = [ ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/mate-hud']), + ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/common.py']), + ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/hud-settings.py']), + ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/i18n.py']), + ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/getkey_dialog.py']), + ('{prefix}/lib/mate-hud/'.format(prefix=sys.prefix), ['usr/lib/mate-hud/getkey_dialog.ui']), + ('{prefix}/share/applications/'.format(prefix=sys.prefix), ['usr/share/applications/hud-settings.desktop']), ('{prefix}/share/mate/autostart/'.format(prefix=sys.prefix), ['usr/share/mate/autostart/mate-hud.desktop']), ('{prefix}/share/glib-2.0/schemas/'.format(prefix=sys.prefix), ['usr/share/glib-2.0/schemas/org.mate.hud.gschema.xml']), - ('{prefix}/share/rofi/themes/'.format(prefix=sys.prefix), ['usr/share/rofi/themes/mate-hud.rasi']), - ('{prefix}/share/rofi/themes/'.format(prefix=sys.prefix), ['usr/share/rofi/themes/mate-hud-hidpi.rasi']), - ('{prefix}/share/rofi/themes/'.format(prefix=sys.prefix), ['usr/share/rofi/themes/mate-hud-rounded.rasi']), - ('{prefix}/share/rofi/themes/'.format(prefix=sys.prefix), ['usr/share/rofi/themes/mate-hud-rounded-hidpi.rasi']), + ('{prefix}/share/pixmaps/'.format(prefix=sys.prefix), ['usr/share/pixmaps/mate-hud.svg']), + ('{prefix}/share/icons/hicolor/16x16/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/16x16/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/22x22/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/22x22/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/24x24/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/24x24/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/32x32/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/32x32/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/48x48/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/48x48/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/64x64/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/64x64/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/128x128/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/128x128/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/256x256/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/256x256/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/512x512/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/512x512/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/16x16@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/16x16@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/22x22@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/22x22@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/24x24@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/24x24@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/32x32@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/32x32@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/48x48@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/48x48@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/64x64@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/64x64@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/128x128@2/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/128x128@2/apps/mate-hud.png']), + ('{prefix}/share/icons/hicolor/scalable/apps'.format(prefix=sys.prefix), ['usr/share/icons/hicolor/scalable/apps/mate-hud.svg']), + ('{prefix}/share/rofi/themes/'.format(prefix=rofi_prefix), ['usr/share/rofi/themes/mate-hud.rasi']), + ('{prefix}/share/rofi/themes/'.format(prefix=rofi_prefix), ['usr/share/rofi/themes/mate-hud-hidpi.rasi']), + ('{prefix}/share/rofi/themes/'.format(prefix=rofi_prefix), ['usr/share/rofi/themes/mate-hud-rounded.rasi']), + ('{prefix}/share/rofi/themes/'.format(prefix=rofi_prefix), ['usr/share/rofi/themes/mate-hud-rounded-hidpi.rasi']), ] cmdclass = { diff --git a/usr/lib/mate-hud/common.py b/usr/lib/mate-hud/common.py new file mode 100644 index 0000000..035af06 --- /dev/null +++ b/usr/lib/mate-hud/common.py @@ -0,0 +1,255 @@ +#!/usr/bin/python3 + +import gi +import logging +import os +import pkgconfig +import re + +gi.require_version('Gtk', '3.0') +from gi.repository import Gio, Gtk + +import i18n +_ = i18n.language.gettext + +def constant(f): + def fset(self, value): + raise TypeError + def fget(self): + return f() + return property(fget, fset) + +class Defaults(object): + @constant + def THEME(): + return 'mate-hud-rounded' + + @constant + def LOCATION(): + return 'north west' + + @constant + def LOCATION_RTL(): + return 'north east' + + @constant + def MONITOR(): + return 'window' + + @constant + def VALID_LOCATIONS(): + return [ 'default', 'north west', 'north', 'north east', 'east', 'south east', 'south', 'south west', 'west', 'center' ] + + @constant + def VALID_MONITORS(): + return [ 'window', 'monitor' ] + + @constant + def VALID_SEPARATOR_PAIRS(): + # unicode pair: left arrow (for RTL languages), 3 spaces (to make it easier to read), right arrow + # If you add more valid pairs here, be sure to add them in the schema org.mate.hud.separator-pairs enum too. + return [ u'\u25C2' + ' '*3 + u'\u25B8', # "◂ ▸" + u'\u2190' + ' '*3 + u'\u2794', # "← ➔" # doesn't seem to be a left arrow to match the right, so close enough + u'\u2190' + ' '*3 + u'\u279C', # "← ➜" # doesn't seem to be a left arrow to match the right, so close enough + u'\u2B9C' + ' '*3 + u'\u2B9E', # "⮜ ⮞" + u'\u276E' + ' '*3 + u'\u276F', # "❮ ❯" + u'\u00AB' + ' '*3 + u'\u00BB', # "« »" + u'\u2039' + ' '*3 + u'\u203A' ] # "‹ ›" + + @constant + def SEPARATOR(): + return HUD_DEFAULTS.VALID_SEPARATOR_PAIRS[0] + + @constant + def RECENTLY_USED_MAX(): + return 10 + + @constant + def RECENTLY_USED_UNLIMITED(): + return -1 + + @constant + def RECENTLY_USED_NONE(): + return 0 + + @constant + def CUSTOM_WIDTH(): + return '0' + + @constant + def PROMPT(): + return _('HUD') + + @constant + def RECENTLY_USED_DECORATION(): + return u'\u2015' * 100 + +HUD_DEFAULTS = Defaults() + +def get_bool(schema, path, key): + if path: + settings = Gio.Settings.new_with_path(schema, path) + else: + settings = Gio.Settings.new(schema) + return settings.get_boolean(key) + +def get_string(schema, path, key): + if path: + settings = Gio.Settings.new_with_path(schema, path) + else: + settings = Gio.Settings.new(schema) + return settings.get_string(key) + +def get_number(schema, path, key): + if path: + settings = Gio.Settings.new_with_path(schema, path) + else: + settings = Gio.Settings.new(schema) + return settings.get_int(key) + +def get_list(schema, path, key): + if path: + settings = Gio.Settings.new_with_path(schema, path) + else: + settings = Gio.Settings.new(schema) + return settings.get_strv(key) + +def get_rofi_theme(): + rofi_theme = 'mate-hud-rounded' + try: + rofi_theme = get_string('org.mate.hud', None, 'rofi-theme') + except: + logging.error(_('org.mate.hud gsettings not found. Defaulting to ') + rofi_theme) + return rofi_theme + +def validate_custom_width(custom_width): + custom_width = re.sub(r'\s', '', custom_width) + if len(re.findall(r'^[0-9]+(px|em|ch|%)?$', custom_width)) == 1: + w = re.sub(r'(px|em|ch|%)?$', '', custom_width) + try: + w = int(w) + return True + except: + pass + return False + +def get_custom_width(): + custom_width = get_string('org.mate.hud', None, 'custom-width') + if validate_custom_width(custom_width): + custom_width = re.sub(r'\s', '', custom_width) + w = re.sub(r'(px|em|ch|%)?$', '', custom_width) + u = re.sub(r'^[0-9]+', '', custom_width) + if u == '': + u = 'px' + return [ not ( w == '0' and u == 'px' ), w, u ] + raise ValueError( _("Invalid custom width specified") ) + +def use_custom_width(): + try: + w = get_custom_width() + if not ( w[0] == '0' and w[1] == 'px' ): + return True + except: + pass + return False + +def get_menu_separator_pair(): + menu_separator = HUD_DEFAULTS.SEPARATOR + try: menu_separator = get_string('org.mate.hud', None, 'menu-separator') + except: pass + return menu_separator + +def get_menu_separator(pair=None): + if not pair: + pair = get_menu_separator_pair() + #pair stored as 'R L' R: RTL separator, L: LTR separator (spaces may be variable, currently 3) + if isrtl(): + return pair[0] + else: + return pair[-1] + +def monitor_rofi_argument(monitor): + arguments = { 'window': '-2', 'monitor': '-1' } + if monitor in HUD_DEFAULTS.VALID_MONITORS: + return arguments[monitor] + else: + return arguments[HUD_DEFAULTS.MONITOR] + +def get_monitor(): + monitor = HUD_DEFAULTS.MONITOR + try: + monitor = get_string('org.mate.hud', None, 'hud-monitor') + except: + logging.error(_('org.mate.hud gsettings not found. Defaulting to ') + HUD_DEFAULTS.MONITOR) + if monitor in HUD_DEFAULTS.VALID_MONITORS: + return monitor + else: + return HUD_DEFAULTS.MONITOR + +def get_location(): + default_location = 'default' + location = default_location + try: + location = get_string('org.mate.hud', None, 'location') + except: + logging.error(_('org.mate.hud gsettings not found. Defaulting to ') + default_location) + if location not in HUD_DEFAULTS.VALID_LOCATIONS: + location = default_location + logging.error(_("Invalid location specified, defaulting to ") + default_location ) + return location + +def get_recently_used_max(): + recently_used_max = 0 + try: + recently_used_max = get_number('org.mate.hud', None, 'recently-used-max') + except: + logging.error(_('org.mate.hud gsettings not found. Defaulting to ') + recently_used_max) + return recently_used_max + +def get_transparency(): + transparency = 100 + try: + transparency = get_number('org.mate.hud', None, 'transparency') + except: + logging.error(_('org.mate.hud gsettings not found. Defaulting to ') + transparency) + return transparency + +def isrtl(): + window = Gtk.Window() + style_context = window.get_style_context() + state = style_context.get_state() + return state & Gtk.StateFlags.DIR_RTL + +def get_theme_list(sort=False): + def sort_themes(theme_name): + return theme_name.lower() + + themes = [] + theme_dirs = [ os.path.expanduser('~') + '/.local/share/rofi/themes/' , + pkgconfig.variables('rofi').get('prefix') + '/share/rofi/themes/' ] + for directory in theme_dirs: + for filename in os.listdir(directory): + f = os.path.join(directory, filename) + # checking if it is a file + if os.path.isfile(f) and filename[-5:] == '.rasi': + theme = filename[:-5] + if theme not in themes: + themes.append( theme ) + if sort: + themes.sort(key=sort_themes) + return themes + +def rgba_to_hex(color): + """ + Return hexadecimal string for :class:`Gdk.RGBA` `color`. + """ + return "#{0:02x}{1:02x}{2:02x}".format( + int(color.red * 255), + int(color.green * 255), + int(color.blue * 255)) + +def get_color(style_context, preferred_color, fallback_color): + color = rgba_to_hex(style_context.lookup_color(preferred_color)[1]) + if color == '#000000': + color = rgba_to_hex(style_context.lookup_color(fallback_color)[1]) + return color diff --git a/usr/lib/mate-hud/getkey_dialog.py b/usr/lib/mate-hud/getkey_dialog.py new file mode 100644 index 0000000..ff93225 --- /dev/null +++ b/usr/lib/mate-hud/getkey_dialog.py @@ -0,0 +1,138 @@ +# Taken from kupfer https://github.com/kupferlauncher/kupfer + +from gi.repository import Gtk, Gdk +import inspect, os.path + + +class GetKeyDialogController(object): + def __init__(self, check_callback=None, previous_key=None, + screen=None, parent=None, + show_clear=True): + ''' + check_callback: optional function to check is entered key is valid. + previous_key - optional previous keybinding, press equal act like cancel + screen: Screen to use + parent: Parent toplevel window + show_clear: Show the “clear” button + ''' + builder = Gtk.Builder() + builder.set_translation_domain('mate-hud') + filename = inspect.getframeinfo(inspect.currentframe()).filename + path = os.path.dirname(os.path.abspath(filename)) + ui_file = path + "/getkey_dialog.ui" + builder.add_from_file(ui_file) + builder.connect_signals(self) + self.window = builder.get_object("dialoggetkey") + self.labelkey = builder.get_object('labelkey') + self.imagekeybindingaux = builder.get_object('imagekeybindingaux') + self.labelkeybindingaux = builder.get_object('labelkeybindingaux') + self.labelaccelerator = builder.get_object('labelaccelerator') + buttonclear = builder.get_object('buttonclear') + if not show_clear: + buttonclear.hide() + + self.imagekeybindingaux.hide() + self.labelkeybindingaux.hide() + + self._key = None + self._check_callback = check_callback + self._previous_key = previous_key + self._press_time = None + + if screen: + self.window.set_screen(screen) + if parent: + self.window.set_transient_for(parent) + self.window.connect("focus-in-event", self.on_window_focus_in) + self.window.connect("focus-out-event", self.on_window_focus_out) + + def run(self): + ''' Run dialog, return key codes or None when user press cancel''' + self.window.set_keep_above(True) + self.window.run() + self.window.destroy() + return self._key + + def _return(self, key): + " Finish dialog with @key as result" + self._key = key + self.window.hide() + + def on_buttoncancel_activate(self, _widget): + self.return_cancel() + return True + + def on_buttonclear_activate(self, _widget): + self.return_clear() + return True + + def return_cancel(self): + self._return(None) + + def return_clear(self): + self._return("") + + def translate_keyboard_event(self, widget, event): + keymap = Gdk.Keymap.get_for_display(widget.get_display()) + # translate keys properly + _wasmapped, keyval, egroup, level, consumed = keymap.translate_keyboard_state( + event.hardware_keycode, event.get_state(), event.group) + modifiers = Gtk.accelerator_get_default_mod_mask() & ~consumed + + state = event.get_state() & modifiers + + return keyval, state + + def update_accelerator_label(self, keyval, state): + accel_label = Gtk.accelerator_get_label(keyval, state) + self.labelaccelerator.set_text(accel_label) + + def on_dialoggetkey_key_press_event(self, widget, event): + self.imagekeybindingaux.hide() + self.labelkeybindingaux.hide() + self._press_time = event.time + + keyval, state = self.translate_keyboard_event(widget, event) + state = Gdk.ModifierType(state) + keyname = Gtk.accelerator_name(keyval, state) + if keyname == 'Escape': + self.return_cancel() + elif keyname == 'BackSpace': + self.return_clear() + self.update_accelerator_label(keyval, state) + + def on_dialoggetkey_key_release_event(self, widget, event): + if not self._press_time: + return + keyval, state = self.translate_keyboard_event(widget, event) + self.update_accelerator_label(0, 0) + + state = Gdk.ModifierType(state) + if Gtk.accelerator_valid(keyval, state): + key = Gtk.accelerator_name(keyval, state) + if (self._previous_key is not None and + key == self._previous_key): + self.return_cancel() + return + if self._check_callback is None or self._check_callback(key): + self._return(key) + else: + self.imagekeybindingaux.show() + self.labelkeybindingaux.show() + + + def on_window_focus_in(self, window, _event): + pass + + def on_window_focus_out(self, _window, _event): + pass + + +def ask_for_key(check_callback=None, previous_key=None, screen=None, + parent=None, show_clear=True): + dlg = GetKeyDialogController(check_callback, previous_key, + screen=screen, + parent=parent, + show_clear=show_clear) + result = dlg.run() + return result diff --git a/usr/lib/mate-hud/getkey_dialog.ui b/usr/lib/mate-hud/getkey_dialog.ui new file mode 100644 index 0000000..02fac0f --- /dev/null +++ b/usr/lib/mate-hud/getkey_dialog.ui @@ -0,0 +1,192 @@ + + + + + + False + 6 + Set Keyboard Shortcut + False + True + center + normal + + + + + True + False + vertical + 12 + + + True + False + end + + + gtk-clear + True + False + False + True + + + + False + False + 0 + + + + + gtk-cancel + True + False + False + True + + + + False + False + 1 + + + + + False + False + end + 0 + + + + + True + False + 12 + + + True + False + gtk-preferences + 6 + + + True + True + 0 + + + + + True + False + 12 + + + True + False + Set Keyboard Shortcut + 0 + 0 + + + + + + + True + True + 0 + + + + + True + False + Please press desired key combination + True + 0 + 0 + + + True + True + 1 + + + + + True + False + 12 + + + True + False + gtk-dialog-error + + + True + True + 0 + + + + + True + False + Keybinding could not be bound + 0 + + + True + True + 1 + + + + + True + True + 2 + + + + + True + False + 0 + + + + + + True + True + 3 + + + + + True + True + 1 + + + + + False + True + 1 + + + + + + buttoncancel + + + diff --git a/usr/lib/mate-hud/hud-settings.py b/usr/lib/mate-hud/hud-settings.py new file mode 100755 index 0000000..5dd6e2d --- /dev/null +++ b/usr/lib/mate-hud/hud-settings.py @@ -0,0 +1,523 @@ +#!/usr/bin/python3 + +import gi +import logging +import os.path +import pkgconfig +import re +import setproctitle + +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gdk, Gio, Gtk + +from common import * +import getkey_dialog + +import i18n +_ = i18n.language.gettext + +class HUDCurrentSettings(): + @property + def shortcut(self): + return get_string( 'org.mate.hud', None, 'shortcut' ) + + @property + def use_custom_width(self): + return get_custom_width()[0] + + @property + def custom_width(self): + return int(get_custom_width()[1]) + + @property + def custom_width_units(self): + return get_custom_width()[2] + + @property + def location(self): + return get_string( 'org.mate.hud', None, 'location' ) + + @property + def rofi_theme(self): + return get_string( 'org.mate.hud', None, 'rofi-theme' ) + + @property + def monitor(self): + return get_string( 'org.mate.hud', None, 'hud-monitor' ) + + @property + def recently_used_max(self): + return get_number( 'org.mate.hud', None, 'recently-used-max' ) + + @property + def menu_separator(self): + return get_string( 'org.mate.hud', None, 'menu-separator' ) + + @property + def use_prompt(self): + return get_string( 'org.mate.hud', None, 'prompt' ) != '' + + @property + def prompt(self): + return get_string( 'org.mate.hud', None, 'prompt' ) + + @property + def transparency(self): + return get_number( 'org.mate.hud', None, 'transparency' ) + # Add new properties here that return the current value of a gsettings key + +class HUDSettingsWindow(Gtk.Window): + # Add 'widget-name': 'HUDCurrentSettings property name' when adding a new option + widget_property_map = { + 'shortcut': 'shortcut', + 'custom-shortcut': 'shortcut', + 'theme': 'rofi_theme', + 'use-width': 'use_custom_width', + 'width': 'custom_width', + 'width-units': 'custom_width_units', + 'monitor': 'monitor', + 'location': 'location', + 'separator': 'menu_separator', + 'recently-used': 'recently_used_max', + 'use-prompt': 'use_prompt', + 'prompt': 'prompt', + 'transparency': 'transparency' + } + + widget_signal_map = { + # widget: [ signal, function_name ] + 'theme': [ "changed", 'selection_changed' ], + 'use-width': [ "toggled", 'use_custom_width_toggled' ], + 'width': [ "changed", 'selection_changed' ], + 'width-units': [ "changed", 'selection_changed' ], + 'monitor': [ "changed", 'selection_changed' ], + 'location': [ "changed", 'selection_changed' ], + 'separator': [ "changed", 'selection_changed' ], + 'recently-used': [ "value-changed", 'selection_changed' ], + 'use-prompt': [ "toggled", 'use_prompt_toggled' ], + 'prompt': [ "changed", 'selection_changed' ], + 'shortcut': [ "changed", 'shortcut_selector_changed' ], + 'custom-shortcut': [ "clicked", 'on_shortcut_clicked' ], + 'transparency': [ "value-changed", 'selection_changed' ], + 'reset-recently-used': [ "clicked", 'reset_recently_used' ], + 'reset-to-defaults': [ "clicked", 'reset_to_defaults' ], + 'reset': [ "clicked", 'reset_view' ], + 'apply-changes': [ "clicked", 'apply_changes' ] + } + + + # I guess if there are ever widgets that don't correespond to a property, we would + # have to write this out, but for now this works fine + widget_names = list( widget_property_map.keys() ) + + # Add new gsettings options here if we provide fields to change them + # A changed listener will be set up with a callback to reload_view_on_change + keys = [ 'shortcut', + 'hud-monitor', + 'location', + 'rofi-theme', + 'menu-separator', + 'custom-width', + 'recently-used-max', + 'prompt' ] + + valid_units = [ 'px', 'em', 'ch', '%' ] + single_modifier_keys = [ 'Alt_L', 'Alt_R', 'Ctrl_L', 'Ctrl_R', 'Super_L', 'Super_R' ] + + def __init__(self): + super().__init__(title="HUD Settings") + self.add_custom_css_classes() + self.set_border_width(10) + self.set_resizable(False) + self.set_icon_name("mate-hud") + + box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=50) + self.add(box_outer) + + box_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_shortcut = Gtk.Label(label=_("Keyboard Shortcut: "), xalign=0, + tooltip_text=_("Keyboard shortcut to activate the HUD")) + hbox.pack_start(lbl_shortcut, True, True, 0) + hbox_ = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + cbx_shortcut = Gtk.ComboBoxText(name='shortcut') + for u in range(len(self.single_modifier_keys)): + cbx_shortcut.insert(u, str(u), self.single_modifier_keys[u]) + cbx_shortcut.insert(len(self.single_modifier_keys), str(len(self.single_modifier_keys)), _("Custom: ")) + hbox_.pack_start(cbx_shortcut, False, True, 0) + btn_shortcut = Gtk.Button(name='custom-shortcut') + hbox_.pack_start(btn_shortcut, False, True, 0) + hbox.pack_start(hbox_, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_theme = Gtk.Label(label=_("HUD Theme: "), xalign=0, + tooltip_text=_("HUD theme. Default is 'mate-hud-rounded'\n" + \ + "The mate-hud* themes attempt to match the system font and colors from the GTK theme.")) + hbox.pack_start(lbl_theme, True, True, 0) + cbx_theme = Gtk.ComboBoxText(name='theme') + hbox.pack_start(cbx_theme, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_prompt = Gtk.Label(label=_("HUD Prompt: "), xalign=0, + tooltip_text=_("HUD prompt. Default is 'HUD' localized if possible.")) + hbox.pack_start(lbl_prompt, True, True, 0) + hbox_ = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + ckb_prompt = Gtk.CheckButton(name='use-prompt') + hbox_.pack_start(ckb_prompt, True, True, 0) + entry_prompt = Gtk.Entry(name='prompt') + entry_prompt.set_placeholder_text(HUD_DEFAULTS.PROMPT) + hbox_.pack_start(entry_prompt, False, True, 0) + hbox.pack_start(hbox_, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_width = Gtk.Label(label=_("Custom Width: "), xalign=0, + tooltip_text=_("Override the width of the HUD specified in the theme")) + hbox.pack_start(lbl_width, True, True, 0) + hbox_ = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + ckb_width = Gtk.CheckButton(name='use-width') + hbox_.pack_start(ckb_width, True, True, 0) + self.width_adjustments = { + 'px': Gtk.Adjustment(lower=0, upper=7680, step_increment=10, page_increment=100, page_size=0, value=600), + 'em': Gtk.Adjustment(lower=0, upper=200, step_increment=1, page_increment=5, page_size=0, value=40), + 'ch': Gtk.Adjustment(lower=0, upper=200, step_increment=1, page_increment=5, page_size=0, value=40), + '%': Gtk.Adjustment(lower=0, upper=100, step_increment=1, page_increment=5, page_size=0, value=40) + } + sb_width = Gtk.SpinButton(name='width') # set the adjustment when we load the value from gsettings + hbox_.pack_start(sb_width, True, True, 0) + cbx_units_width = Gtk.ComboBoxText(name='width-units') + for u in range(len(self.valid_units)): + cbx_units_width.insert(u, str(u), self.valid_units[u]) + cbx_units_width.set_active(0) + hbox_.pack_start(cbx_units_width, True, True, 0) + hbox.pack_start(hbox_, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_monitor = Gtk.Label(label=_("Attach HUD to: "), xalign=0, + tooltip_text=_("Where to attach the HUD.\nDefault is to the current window.\n" + + "If set to monitor, the HUD will try to avoid overlapping any panels.")) + hbox.pack_start(lbl_monitor, True, True, 0) + cbx_monitor = Gtk.ComboBoxText(name='monitor') + for u in range(len(HUD_DEFAULTS.VALID_MONITORS)): + cbx_monitor.insert(u, str(u), HUD_DEFAULTS.VALID_MONITORS[u]) + hbox.pack_start(cbx_monitor, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_location = Gtk.Label(label=_("HUD location: "), xalign=0, + tooltip_text=_("How to position the HUD in relation to what is attached to (window or monitor).\n" + \ + "'default' is north west for LTR languages and north east for RTL languages.")) + hbox.pack_start(lbl_location, True, True, 0) + cbx_location = Gtk.ComboBoxText(name='location') + for u in range(len(HUD_DEFAULTS.VALID_LOCATIONS)): + cbx_location.insert(u, str(u), HUD_DEFAULTS.VALID_LOCATIONS[u]) + hbox.pack_start(cbx_location, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_separator = Gtk.Label(label=_("Menu Separator: "), xalign=0, + tooltip_text=_("Character to separate the parts of the menu heirarchy in the HUD (RTL and LTR variants)")) + hbox.pack_start(lbl_separator, True, True, 0) + cbx_separator = Gtk.ComboBoxText(name='separator') + for u in range(len(HUD_DEFAULTS.VALID_SEPARATOR_PAIRS)): + cbx_separator.insert(u, str(u), HUD_DEFAULTS.VALID_SEPARATOR_PAIRS[u]) + hbox.pack_start(cbx_separator, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_transparency = Gtk.Label(label=_("Transparency: "), xalign=0, + tooltip_text=_("Transparency of the HUD window\n" + \ + " 0: Completely transparent\n" + \ + "100: Solid color")) + hbox.pack_start(lbl_transparency, True, True, 0) + adjustment = Gtk.Adjustment(lower=0, upper=100, step_increment=1, page_increment=5, page_size=0, value=0) + sb_transparency = Gtk.SpinButton(xalign=1, name='transparency', adjustment=adjustment) + hbox.pack_start(sb_transparency, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_recent_max = Gtk.Label(label=_("Max Recently Used Items: "), xalign=0, + tooltip_text=_("Maximum number of recently used items to remember per application\n" + \ + " 0: Don't save recently used items\n" + \ + "-1: save unlimited recently used items")) + hbox.pack_start(lbl_recent_max, True, True, 0) + adjustment = Gtk.Adjustment(lower=-1, upper=100, step_increment=1, page_increment=10, page_size=0, value=0) + sb_recent_max = Gtk.SpinButton(xalign=1, name='recently-used', adjustment=adjustment) + hbox.pack_start(sb_recent_max, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + lbl_recent_reset = Gtk.Label(label=_("Recently Used Item List: "), xalign=0, + tooltip_text=_("Reset the recently used item list")) + hbox.pack_start(lbl_recent_reset, True, True, 0) + btn_reset_recently_used = Gtk.Button(name='reset-recently-used', label=_("Reset")) + hbox.pack_start(btn_reset_recently_used, False, True, 0) + box_main.pack_start(hbox, True, True, 0) + + box_outer.pack_start(box_main, True, True, 0) + + box_buttons = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) + btn_reset_to_defaults = Gtk.Button(name='reset-to-defaults', label=_("Reset to defaults")) + box_buttons.pack_start(btn_reset_to_defaults, True, True, 0) + btn_reset = Gtk.Button(name='reset', label=_("Clear Changes")) + box_buttons.pack_start(btn_reset, True, True, 0) + btn_apply = Gtk.Button(name='apply-changes', label=_("Apply Changes")) + box_buttons.pack_start(btn_apply, False, True, 0) + box_outer.pack_start(box_buttons, True, True, 0) + + def show_all(self): + super().show_all() + self.reload_view() + # Connect to the widget changed signals after we load the view + # and establish the widget's initial values. Otherwise, the we'll + # be responding to change signals as we load the initial state + self.connect_to_signals() + + def add_custom_css_classes(self): + screen = Gdk.Screen.get_default() + provider = Gtk.CssProvider() + style_context = Gtk.StyleContext() + style_context.add_provider_for_screen( + screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ) + color = rgba_to_hex(style_context.lookup_color('theme_selected_bg_color')[1]) + css = bytes(""" + entry.changed, + combobox.changed button.combo, + comboboxtext.changed button.combo, + button.changed, + spinbutton.changed entry, + checkbutton.changed check { + border: solid #1fced2; + border-width: 2px; + } + """.replace('#1fced2', color).encode('utf-8')) + provider.load_from_data(css) + + def get_widget_by_name(self, name, root=None): + if not root: root = self.get_toplevel() + if root.get_name() == name: + return root + try: + widgets = root.get_children() + except: + widgets = [] + for w in widgets: + if str(w.get_name()) == name: + return w + try: + children = w.get_children() + except: + children = [] + for y in children: + z = self.get_widget_by_name( name, root=y ) + if z: return z + return None + + def use_custom_width_toggled(self, button): + use_cw = button.get_active() + self.get_widget_by_name('width').set_visible(use_cw) + self.get_widget_by_name('width-units').set_visible(use_cw) + self.selection_changed(button) + self.selection_changed(self.get_widget_by_name('width')) + self.selection_changed(self.get_widget_by_name('width-units')) + + def use_prompt_toggled(self, button): + self.get_widget_by_name('prompt').set_visible(button.get_active()) + self.selection_changed(button) + self.selection_changed(self.get_widget_by_name('prompt')) + + def recent_max_update_tooltip(self): + w = self.get_widget_by_name('recently-used') + recent_max = w.get_value_as_int() + if recent_max == HUD_DEFAULTS.RECENTLY_USED_UNLIMITED: + w.set_tooltip_text(_('Unlimited')) + elif recent_max == HUD_DEFAULTS.RECENTLY_USED_NONE: + w.set_tooltip_text(_("Don't save or show recently used menu items")) + else: + w.set_has_tooltip(False) + + def on_shortcut_clicked(self, widget): + keystr = getkey_dialog.ask_for_key( + previous_key=get_string('org.mate.hud', None, 'shortcut'), + screen=widget.get_screen(), + parent=widget.get_toplevel() + ) + if not keystr: + return + w = self.get_widget_by_name('custom-shortcut') + w.set_label(keystr) + self.selection_changed(w) + + def reset_to_defaults(self, button): + logging.info(_("Resetting all settings to default")) + settings = Gio.Settings.new('org.mate.hud') + for key in self.keys: + settings.reset(key) + + def reset_recently_used(self, button): + logging.info(_("Resetting recently used menu entry list")) + Gio.Settings.new('org.mate.hud').reset('recently-used') + + def apply_changes(self, button): + logging.info(_("Applying changes")) + + settings = Gio.Settings.new('org.mate.hud') + settings.set_string( 'shortcut', self.get_widget_by_name('custom-shortcut').get_label()) + settings.set_string( 'hud-monitor', self.get_widget_by_name('monitor').get_active_text()) + settings.set_string( 'location', self.get_widget_by_name('location').get_active_text()) + settings.set_string( 'rofi-theme', self.get_widget_by_name('theme').get_active_text()) + settings.set_string( 'menu-separator', self.get_widget_by_name('separator').get_active_text()) + settings.set_int( 'recently-used-max', self.get_widget_by_name('recently-used').get_value_as_int()) + settings.set_int( 'transparency', self.get_widget_by_name('transparency').get_value_as_int()) + if self.get_widget_by_name('use-prompt').get_active(): + settings.set_string( 'prompt', self.get_widget_by_name('prompt').get_text()) + else: + settings.set_string( 'prompt', '') + + if self.get_widget_by_name('use-width').get_active(): + settings.set_string('custom-width', \ + str(self.get_widget_by_name('width').get_value_as_int()) + \ + self.get_widget_by_name('width-units').get_active_text()) + else: # Default is use the theme width (no custom width, so apply that if the checkbutton isn't checked + settings.set_string('custom-width', HUD_DEFAULTS.CUSTOM_WIDTH) + + self.selection_changed_all() + + def selection_changed_all( self ): + for name in self.widget_names: + widget = self.get_widget_by_name( name ) + if widget: self.selection_changed( widget ) + + def shortcut_selector_changed( self, widget ): + use_custom = ( widget.get_active_text() == _('Custom') + ': ' ) + custom_shortcut_btn = self.get_widget_by_name( 'custom-shortcut' ) + if not use_custom: + custom_shortcut_btn.set_label(widget.get_active_text()) + self.selection_changed(custom_shortcut_btn) + custom_shortcut_btn.set_visible( use_custom ) + self.selection_changed(widget) + + def selection_changed( self, widget ): + style_context = widget.get_style_context() + + if widget.get_name() == 'shortcut' and widget.get_active_text() == _('Custom') + ': ': + widget = self.get_widget_by_name( 'custom-shortcut' ) + widget_type = type(widget).__name__ + current_value = getattr( HUDCurrentSettings(), self.widget_property_map.get( widget.get_name() ) ) + displayed_value = current_value # assume not changed, til we get the value + if widget_type == 'Button': displayed_value = widget.get_label() + elif widget_type == 'SpinButton': displayed_value = widget.get_value_as_int() + elif widget_type == 'ComboBoxText': displayed_value = widget.get_active_text() + elif widget_type == 'Entry': displayed_value = widget.get_text() + elif widget_type == 'CheckButton': displayed_value = widget.get_active() + changed = ( current_value != displayed_value ) + if changed: + style_context.add_class('changed') + widget.set_tooltip_text(_("Change not applied yet")) + else: + style_context.remove_class('changed') + widget.set_has_tooltip(False) + if widget.get_name() == 'recently-used': + self.recent_max_update_tooltip() + if widget.get_name() == 'width-units': # and changed: + logging.info( 'Changing width adjustment' ) + self.get_widget_by_name('width').set_adjustment( self.width_adjustments[ widget.get_active_text() ] ) + + def connect_to_signals(self): + names = self.widget_signal_map.keys() + for name in names: + signal, function = self.widget_signal_map[name] + self.get_widget_by_name(name).connect( signal, getattr( self, function ) ) + + def reload_view_on_change(self, schema, key): + logging.info( _("Reloading view in response to key change.") ) + self.reload_view(key=key) + + def reset_view(self, button): + self.reload_view() + + def reload_view(self, key=None): + logging.info(_("Reloading view") + ( " " + _('for') + " " + key if key else "" ) ) + + if not key or key == 'shortcut': + shortcut = get_string( 'org.mate.hud', None, 'shortcut' ) + if shortcut in self.single_modifier_keys: + self.get_widget_by_name('shortcut').set_active(self.single_modifier_keys.index(shortcut)) + self.get_widget_by_name('custom-shortcut').set_visible(False) + else: + # The shortcut combobox has all the single modifiers, then 'Custom: ' + self.get_widget_by_name('shortcut').set_active(len(self.single_modifier_keys)) + self.get_widget_by_name('custom-shortcut').set_visible(True) + self.get_widget_by_name('custom-shortcut').set_label( get_string( 'org.mate.hud', None, 'shortcut' ) ) + + if not key or key == 'rofi-theme': + themes = get_theme_list(sort=True) + widget = self.get_widget_by_name('theme') + widget.remove_all() + for u in range(len(themes)): + widget.insert(u, str(u), themes[u]) + try: + widget.set_active(themes.index(get_rofi_theme())) + except: + Gio.Settings.new('org.mate.hud').set_string('rofi-theme', HUD_DEFAULTS.THEME) + widget.set_active(themes.index(HUD_DEFAULTS.THEME)) + + if not key or key == 'custom-width': + try: + use_width, width, units = get_custom_width() + except: + Gio.Settings.new('org.mate.hud').set_string('custom-width', HUD_DEFAULTS.CUSTOM_WIDTH) + use_width, width, units = get_custom_width() + + widget_use = self.get_widget_by_name('use-width') + widget_width = self.get_widget_by_name('width') + widget_units = self.get_widget_by_name('width-units') + widget_use.set_active(use_width) + widget_width.set_visible(use_width) + widget_units.set_visible(use_width) + if use_width: + if units == widget_units.get_active_text(): + widget_width.set_value(int(width)) + widget_units.set_active(self.valid_units.index(units)) + widget_width.set_adjustment( self.width_adjustments[self.get_widget_by_name('width-units').get_active_text()] ) + + if not key or key == 'prompt': + use_prompt = HUDCurrentSettings().use_prompt + self.get_widget_by_name('use-prompt').set_active(use_prompt) + self.get_widget_by_name('prompt').set_text( HUDCurrentSettings().prompt ) + self.get_widget_by_name('prompt').set_visible( use_prompt ) + + if not key or key == 'hud-monitor': + self.get_widget_by_name('monitor').set_active(HUD_DEFAULTS.VALID_MONITORS.index(get_monitor())) + + if not key or key == 'location': + self.get_widget_by_name('location').set_active(HUD_DEFAULTS.VALID_LOCATIONS.index(get_location())) + + if not key or key == 'menu-separator': + self.get_widget_by_name('separator').set_active(HUD_DEFAULTS.VALID_SEPARATOR_PAIRS.index(get_menu_separator_pair())) + + if not key or key == 'recently-used-max': + self.get_widget_by_name('recently-used').set_value(get_recently_used_max()) + self.recent_max_update_tooltip() + + if not key or key == 'transparency': + self.get_widget_by_name('transparency').set_value(get_transparency()) + +if __name__ == "__main__": + setproctitle.setproctitle('hud-settings') + logging.basicConfig(level=logging.INFO) + + win = HUDSettingsWindow() + win.connect("destroy", Gtk.main_quit) + settings = Gio.Settings.new("org.mate.hud") + for k in win.keys: + settings.connect("changed::" + k, win.reload_view_on_change) + + win.show_all() + Gtk.main() diff --git a/usr/lib/mate-hud/i18n.py b/usr/lib/mate-hud/i18n.py new file mode 100644 index 0000000..85e8736 --- /dev/null +++ b/usr/lib/mate-hud/i18n.py @@ -0,0 +1,12 @@ +#!/usr/bin/python3 + +import os, sys +import locale +import gettext + +APP_NAME = "mate-hud" +LOCALE_DIR = os.path.join(sys.prefix, "share", "locale") +gettext.install (True) +gettext.bindtextdomain (APP_NAME, LOCALE_DIR) +gettext.textdomain (APP_NAME) +language = gettext.translation (APP_NAME, LOCALE_DIR, fallback = True) diff --git a/usr/lib/mate-hud/mate-hud b/usr/lib/mate-hud/mate-hud index a8cebd7..96fe9ee 100755 --- a/usr/lib/mate-hud/mate-hud +++ b/usr/lib/mate-hud/mate-hud @@ -4,10 +4,15 @@ import gi gi.require_version('Gdk', '3.0') gi.require_version("Gtk", "3.0") +import configparser import dbus +import json import logging import os +import pkgconfig import psutil +import pyinotify +import re import setproctitle import subprocess import time @@ -16,26 +21,40 @@ from dbus.mainloop.glib import DBusGMainLoop from gi.repository import Gio, GLib, Gtk, Gdk, GObject from Xlib import display, protocol, X, Xatom, error -def get_desktop_env(): - desktop_env = '' - try: - desktop_env = os.environ['XDG_CURRENT_DESKTOP'] - except: - pass - if not desktop_env: - try: - desktop_env = os.environ['XDG_SESSION_DESKTOP'] - except: - pass - return desktop_env - -if 'XFCE' in get_desktop_env(): - try: - gi.require_version("Xfconf", "0") - from gi.repository import Xfconf - Xfconf.init() - except: - logging.debug('running XFCE, but xfconf gi repository not available') +from common import * + +class Store(object): + def __new__(cls): + if not hasattr(cls, 'instance'): + cls.instance = super(Store, cls).__new__(cls) + # Set up the default store variables + cls.instance.margin = [ -1, -1 ] + cls.instance.last_gtk_theme = '' + cls.instance.gtk_theme = '' + cls.instance.last_font_name = '' + cls.instance.font_name = '' + cls.instance.dpi = 0 + cls.instance.rofi_theme = HUD_DEFAULTS.THEME + cls.instance.rofi_theme_overrides = None + cls.instance.mate_hud_themes = [ 'mate-hud', 'mate-hud-hidpi', 'mate-hud-rounded', 'mate-hud-rounded-hidpi' ] + cls.instance.themes_hidpi_versions = { 'mate-hud': 'mate-hud-hidpi', 'mate-hud-rounded': 'mate-hud-rounded-hidpi' } + cls.instance.monitor = HUD_DEFAULTS.MONITOR + cls.instance.location = HUD_DEFAULTS.LOCATION if not isrtl() else HUD_DEFAULTS.LOCATION_RTL + cls.instance.custom_width = HUD_DEFAULTS.CUSTOM_WIDTH + cls.instance.menu_separator_pair = get_menu_separator_pair() + cls.instance.menu_separator = get_menu_separator() + cls.instance.recently_used = None + cls.instance.recently_used_max = get_number( 'org.mate.hud', None, 'recently-used-max' ) + cls.instance.plotinus_enabled = False + cls.instance.plotinus_schema = None + cls.instance.plotinus_path = None + cls.instance.plotinus_bus_name = None + cls.instance.plotinus_bus_path = None + cls.instance.panels = [] + cls.instance.prompt = '' + cls.instance.rofi_process = None + return cls.instance +STORE = Store() class EWMH: """This class provides the ability to get and set properties defined @@ -91,35 +110,7 @@ def format_path(path): result = result.replace('Root > ', '') result = result.replace('Label Empty > ', '') result = result.replace('_', '') - return result.replace('>', u'\u0020\u0020\u00BB\u0020\u0020') - -def get_bool(schema, path, key): - if path: - settings = Gio.Settings.new_with_path(schema, path) - else: - settings = Gio.Settings.new(schema) - return settings.get_boolean(key) - -def get_string(schema, path, key): - if path: - settings = Gio.Settings.new_with_path(schema, path) - else: - settings = Gio.Settings.new(schema) - return settings.get_string(key) - -def get_number(schema, path, key): - if path: - settings = Gio.Settings.new_with_path(schema, path) - else: - settings = Gio.Settings.new(schema) - return settings.get_int(key) - -def get_list(schema, path, key): - if path: - settings = Gio.Settings.new_with_path(schema, path) - else: - settings = Gio.Settings.new(schema) - return settings.get_strv(key) + return result.replace('>', u'\u0020\u0020' + STORE.menu_separator + u'\u0020\u0020').lstrip() def process_running(name): uid = os.getuid() @@ -133,6 +124,18 @@ def process_running(name): return True return False +def process_get_cmdline(name): + uid = os.getuid() + for process in psutil.process_iter(): + try: + proc = process.as_dict(attrs=['name', 'uids']) + except psutil.NoSuchProcess: + pass + else: + if name == proc['name'] and uid == proc['uids'].real: + return process.as_dict(attrs=['cmdline'])['cmdline'] + return [] + def kill_process(name): uid = os.getuid() for process in psutil.process_iter(): @@ -151,64 +154,294 @@ def kill_process(name): def terminate_appmenu_registrar(): # TODO: # - Use Dbus Quit method. - # - Add checks for other Desktop Environments. - if 'MATE' in get_desktop_env(): - if process_running('appmenu-registrar') and not process_running('appmenu-mate'): - kill_process('appmenu-registrar') - elif process_running('xfce4-panel'): + appmenu_loaded = False + if process_running('mate-panel'): + applets = get_list( 'org.mate.panel', '/org/mate/panel/general/', 'object-id-list') + for a in applets: + if get_string( 'org.mate.panel.object', '/org/mate/panel/objects/' + a + '/', 'applet-iid' ) == 'AppmenuAppletFactory::AppmenuApplet': + appmenu_loaded = True + break + if not appmenu_loaded and process_running('xfce4-panel'): + bus = dbus.SessionBus() try: - xfc_panel = Xfconf.Channel.new("xfce4-panel") - panels = xfc_panel.get_arrayv("/panels") + object = bus.get_object("org.xfce.Xfconf", "/org/xfce/Xfconf") + interface = dbus.Interface(object, dbus_interface="org.xfce.Xfconf") + panels = list(interface.GetProperty( 'xfce4-panel', '/panels' )) plugin_ids = [] for panel in panels: - plugin_ids += xfc_panel.get_arrayv("/panels/panel-" + str(panel) + "/plugin-ids") - appmenu_loaded = False + plugin_ids += list(interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/plugin-ids")) for plugid in plugin_ids: - if ( xfc_panel.get_string("/plugins/plugin-" + str(plugid), "") == 'appmenu' ): + if ( str(interface.GetProperty('xfce4-panel', "/plugins/plugin-" + str(plugid))) == 'appmenu' ): appmenu_loaded = True break - if process_running('appmenu-registrar') and not appmenu_loaded: - kill_process('appmenu-registrar') + except dbus.exceptions.DBusException: + logging.info('Failed to get xfce4-panel information over dbus.') + cmdline = process_get_cmdline( 'vala-panel' ) + if not appmenu_loaded and cmdline: + profile = 'default' + try: + profile = cmdline[cmdline.index('-p') + 1] except: - logging.debug('running XFCE panel, but xfconf gi repository not available') - -def rgba_to_hex(color): - """ - Return hexadecimal string for :class:`Gdk.RGBA` `color`. - """ - return "#{0:02x}{1:02x}{2:02x}".format( - int(color.red * 255), - int(color.green * 255), - int(color.blue * 255)) - -def get_color(style_context, preferred_color, fallback_color): - color = rgba_to_hex(style_context.lookup_color(preferred_color)[1]) - if color == '#000000': - color = rgba_to_hex(style_context.lookup_color(fallback_color)[1]) - return color - -def get_menu(menuKeys): - """ - Generate menu of available menu items. - """ - if not menuKeys: - return '' - - menu_string, *menu_items = menuKeys - for menu_item in menu_items: - menu_string += '\n' + menu_item + pass #if not specified, default profile is used + config = configparser.ConfigParser() + confdir = GLib.get_user_config_dir() + if os.path.isfile( confdir + '/vala-panel/' + profile ): + config.read( confdir + '/vala-panel/' + profile ) + # List of the plugins in the loaded config (each item will be single-quoted + plugins = config.get('core-version-1', 'units').strip("][").split(', ') + + for p in plugins: + try: + if config[p[1:-1]]['plugin-type'] == "'org.valapanel.appmenu'": + appmenu_loaded = True + break + except: + pass + if not appmenu_loaded and process_running('budgie-panel'): + panels = get_list( 'com.solus-project.budgie-panel', None, 'panels' ) + applets = [] + for p in panels: + applets.append( get_list('com.solus-project.budgie-panel.panel', '/com/solus-project/budgie-panel/panels/{' + p + '}/', 'applets') ) + for a in applets: + name = get_string('com.solus-project.budgie-panel.applet', '/com/solus-project/budgie-panel/applets/{' + p + '}/', 'name') + if name == 'Global Menu': + appmenu_loaded = True + break + + if process_running('appmenu-registrar') and not appmenu_loaded: + kill_process('appmenu-registrar') + +def get_running_panels(): + panels = [] + for p in [ 'xfce4-panel', 'mate-panel', 'budgie-panel', 'plank', 'dockx' 'vala-panel' ]: + if process_running(p): + panels.append(p) + return panels + +def thr_panel_updater(): + while True: + time.sleep(60) + panels = get_running_panels() + if panels != STORE.panels: + logging.info("Running panels have changed, updating margin") + STORE.panels = panels + update_panel_margin() + +def get_panel_margin(): + logging.info( 'Getting panel margin' ) + margin = [ -1, -1 ] + location = STORE.location + if 'xfce4-panel' in STORE.panels: + pos_nm = { 'left': [ 5, 6, 8 ], 'top': [ 2, 6, 11 ], 'right': [ 1, 2, 4 ], 'bottom': [ 4, 8, 12 ] } + orientation = { 'horizontal': [ 0 ], 'vertical': [ 1, 2 ] } + bus = dbus.SessionBus() + try: + object = bus.get_object("org.xfce.Xfconf", "/org/xfce/Xfconf") + interface = dbus.Interface(object, dbus_interface="org.xfce.Xfconf") + panels = list(interface.GetProperty( 'xfce4-panel', '/panels' )) + for panel in panels: + _pos = interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/position") #.split(';=') + pos = re.split(r'[;=]', _pos ) + # [ 'p', p, 'x', x, 'y', y ] + edge = int( pos[1] ) + + mode = 0 # Default panel mode, key doesn't always exist if default + if interface.PropertyExists('xfce4-panel', "/panels/panel-" + str(panel) + "/mode"): + mode = interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/mode") + + ah = 0 # Default autohide value, key doesn't always exist if default + if interface.PropertyExists('xfce4-panel', "/panels/panel-" + str(panel) + "/autohide-behavior"): + ah = interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/autohide-behavior") + is_panel = ( ah == 0 ) + if is_panel and mode in orientation.get('vertical') and \ + ( ( edge in pos_nm.get('left') and 'west' in location ) or \ + ( edge in pos_nm.get('right') and 'east' in location ) ): + x = int(interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/size")) + if x > margin[0]: + margin[0] = x + if is_panel and mode in orientation.get('horizontal') and \ + ( ( edge in pos_nm.get('top') and 'north' in location ) or \ + ( edge in pos_nm.get('bottom') and 'south' in location ) ): + y = int(interface.GetProperty('xfce4-panel', "/panels/panel-" + str(panel) + "/size")) + if y > margin[1]: + margin[1] = y + except dbus.exceptions.DBusException: + logging.info('Failed to get xfce4-panel information over dbus.') + if 'mate-panel' in STORE.panels: + panels = get_list( 'org.mate.panel', None, 'toplevel-id-list' ) + for p in panels: + size = get_number( 'org.mate.panel.toplevel', '/org/mate/panel/toplevels/' + p + '/', 'size' ) + orientation = get_string( 'org.mate.panel.toplevel', '/org/mate/panel/toplevels/' + p + '/', 'orientation' ) + if ( ( orientation == 'left' and 'west' in location ) or \ + ( orientation == 'right' and 'east' in location ) ) and \ + size > margin[0]: + margin[0] = size + if ( ( orientation == 'top' and 'north' in location ) or \ + ( orientation == 'bottom' and 'south' in location ) ) and \ + size > margin[1]: + margin[1] = size + if 'budgie-panel' in STORE.panels: + panels = get_list( 'com.solus-project.budgie-panel', None, 'panels' ) + for p in panels: + size = get_number( 'com.solus-project.budgie-panel.panel', '/com/solus-project/budgie-panel/panels/{' + p + '}/', 'size' ) + orientation = get_string( 'com.solus-project.budgie-panel.panel', '/com/solus-project/budgie-panel/panels/{' + p + '}/', 'location' ) + if ( ( orientation == 'left' and 'west' in location ) or \ + ( orientation == 'right' and 'east' in location ) ) and \ + size > margin[0]: + margin[0] = size + if ( ( orientation == 'top' and 'north' in location ) or \ + ( orientation == 'bottom' and 'south' in location ) ) and \ + size > margin[1]: + margin[1] = size + if 'plank' in STORE.panels: + cmdline = process_get_cmdline( 'plank' ) + dock = 'dock1' # default + try: + idx = -1 + if '--name' in cmdline: + idx = cmdline.index('--name') + elif '-n' in cmdline: + idx = cmdline.index('-n') + if idx > 0: + dock = cmdline[idx + 1] + except: + pass + position = get_string('net.launchpad.plank.dock.settings', '/net/launchpad/plank/docks/' + dock + '/', 'position') + + size = get_number('net.launchpad.plank.dock.settings', '/net/launchpad/plank/docks/' + dock + '/', 'icon-size') + theme = get_string('net.launchpad.plank.dock.settings', '/net/launchpad/plank/docks/' + dock + '/', 'theme') + config = configparser.ConfigParser() + cfg_file = pkgconfig.variables('plank').get('prefix') + 'plank/themes/' + theme + '/dock.theme' + if os.path.isfile( cfg_file ): + config.read( cfg_file ) + pad = 0 + try: + pad = float(config['PlankDockTheme']['BottomPadding']) + except: + pass + size = round( size * ( 1 + pad / 10 ) ) + + plank_is_panel = False + if get_string( 'net.launchpad.plank.dock.settings', '/net/launchpad/plank/docks/' + dock + '/', 'hide-mode') == 'none': + plank_is_panel = True + if plank_is_panel and size > margin[0] and \ + ( ( position == 'left' and 'west' in location ) or \ + ( position == 'right' and 'east' in location ) ): + margin[0] = size + if plank_is_panel and size > margin[1] and \ + ( ( position == 'top' and 'north' in location ) or \ + ( position == 'bottom' and 'south' in location ) ): + margin[1] = size + if 'dockx' in STORE.panels: + dockx_is_panel = False + if get_string( 'org.dockbarx.dockx', None, 'behaviour') == 'standard': + dockx_is_panel = True + position = get_string( 'org.dockbarx.dockx', None, 'position') + size = get_number( 'org.dockbarx.dockx', None, 'size' ) + if dockx_is_panel and size > margin[0] and \ + ( ( position == 'left' and 'west' in location ) or \ + ( position == 'right' and 'east' in location ) ): + margin[0] = size + if dockx_is_panel and size > margin[1] and \ + ( ( position == 'top' and 'north' in location ) or \ + ( position == 'bottom' and 'south' in location ) ): + margin[1] = size + if 'vala-panel' in STORE.panels: + cmdline = process_get_cmdline( 'vala-panel' ) + if cmdline: + profile = 'default' + try: + profile = cmdline[cmdline.index('-p') + 1] + except: + pass #if not specified, default profile is used + + config = configparser.ConfigParser() + confdir = GLib.get_user_config_dir() + if os.path.isfile( confdir + '/vala-panel/' + profile ): + config.read( confdir + '/vala-panel/' + profile ) + # List of the 'units' in the loaded config (toplevels, applets, other objects?) + # (each item will be single-quoted). We only care about the toplevels (panels) now + units = [] + try: + units = config.get('core-version-1', 'units').strip("][").split(', ') + except: + pass + for u in units: + try: + if config[u[1:-1]]['object-type'] == "'toplevel'": + size = int(config[u[1:-1]]['height']) + # comes back as 'north-left', 'west-down', etc + position = config[u[1:-1]]['panel-gravity'].strip("'").split('-')[0] + # was auto-hide in one place and autohide in another? + #ah = config[u[1:-1]]['auto-hide'] + if size > margin[0] and \ + ( ( position == 'west' and 'west' in location ) or \ + ( position == 'east' and 'east' in location ) ): + margin[0] = size + if size > margin[1] and \ + ( ( position == 'north' and 'north' in location ) or \ + ( position == 'south' and 'south' in location ) ): + margin[1] = size + except: + pass + + if margin[0] > 0 and margin[1] < 0: + margin[1] = 0 + if margin[1] > 0 and margin[0] < 0: + margin[0] = 0 + logging.info( 'New margin:' + str(margin) ) + return margin + +def update_panel_margin(): + STORE.margin = get_panel_margin() + +def update_theme_overrides_if_needed(): + gtk_settings = Gtk.Settings.get_default() + STORE.gtk_theme = gtk_settings.get_property( 'gtk-theme-name' ) + STORE.font_name = gtk_settings.get_property( 'gtk-font-name' ) + if not STORE.rofi_theme_overrides or STORE.gtk_theme != STORE.last_gtk_theme or STORE.font_name != STORE.last_font_name: + STORE.rofi_theme_overrides = get_theme_overrides() + STORE.last_gtk_theme = STORE.gtk_theme + STORE.last_font_name = STORE.font_name + +def get_theme_overrides(): + logging.info( 'Getting rofi theme overrides' ) + # Get the currently active font. + theme_options = '' + + font_name = Gtk.Settings.get_default().get_property( 'gtk-font-name' ) + if font_name: + theme_options += ' * { font: "' + font_name + '"; } ' - # Get some colors from the currently selected theme. window = Gtk.Window() - - # Allow closing the HUD with the same modifier key that opens it - shortcut = get_shortcut() - keyval, modifiers = Gtk.accelerator_parse(shortcut) - shortcut = '' if modifiers else ',' + shortcut - - desktop_name = get_desktop_env() - + style_context = window.get_style_context() + + bg_color = get_color(style_context, 'dark_bg_color', 'theme_bg_color') + fg_color = get_color(style_context, 'dark_fg_color', 'theme_fg_color') + #borders = get_color(style_context, 'borders', 'border_color') + + logging.debug('bg_color: %s', str(bg_color)) + logging.debug('fg_color: %s', str(fg_color)) + #logging.debug('borders: %s', str(borders)) + + selected_bg_color = rgba_to_hex(style_context.lookup_color('theme_selected_bg_color')[1]) + selected_fg_color = rgba_to_hex(style_context.lookup_color('theme_selected_fg_color')[1]) + alpha = get_transparency() * 255 // 100 + # Overwrite some of the theme options + theme_options += 'listview { background-color: ' + bg_color + f'{alpha:x}' + '; ' + \ + ' border-color: ' + selected_bg_color + '; } ' + \ + 'element { text-color: ' + fg_color + '; } ' + \ + 'element selected.normal { background-color: ' + selected_bg_color + '; ' + \ + ' text-color: ' + selected_fg_color + '; } ' + \ + 'inputbar { background-color: ' + bg_color + '; ' + \ + ' border-color: ' + selected_bg_color + '; ' + \ + ' text-color: ' + fg_color + '; } ' + return theme_options + +def get_display_dpi(): + logging.info( 'Getting DPI' ) # Calculate display DPI value + window = Gtk.Window() screen = window.get_screen() scale = window.get_scale_factor() @@ -218,87 +451,96 @@ def get_menu(menuKeys): else: return 0 - width_dpi = get_dpi(screen.width(), screen.width_mm()) - height_dpi = get_dpi(screen.height(), screen.height_mm()) - dpi = scale * (width_dpi + height_dpi) / 2 - - rofi_theme = get_rofi_theme() - mate_hud_themes = [ 'mate-hud', 'mate-hud-hidpi', 'mate-hud-rounded', 'mate-hud-rounded-hidpi' ] - themes_hidpi_versions = { 'mate-hud': 'mate-hud-hidpi', 'mate-hud-rounded': 'mate-hud-rounded-hidpi' } - # switch to the hidpi version of the theme if needed. - if rofi_theme in mate_hud_themes: - if scale > 1 and rofi_theme in themes_hidpi_versions.keys(): - rofi_theme = themes_hidpi_versions[rofi_theme] + dpi = screen.get_resolution() + # https://docs.gtk.org/gdk3/method.Screen.get_resolution.html + # gdk_screen_get_resolution() returns -1 if no resolution is set + if dpi == -1: + width_dpi = get_dpi(screen.width(), screen.width_mm()) + height_dpi = get_dpi(screen.height(), screen.height_mm()) + dpi = (width_dpi + height_dpi) / 2 + return round( dpi * scale ) + +def init_rofi(): + STORE.recently_used_current_window = [] + if STORE.current_win_name in STORE.recently_used.keys(): + STORE.recently_used_current_window = STORE.recently_used.get(STORE.current_win_name) + + # update each time in case interface direction has changed (unlikely, but shouldn't cost use much + STORE.menu_separator = get_menu_separator(pair=STORE.menu_separator_pair) + + # Allow closing the HUD with the same modifier key that opens it + shortcut = get_shortcut() + keyval, modifiers = Gtk.accelerator_parse(shortcut) + shortcut = '' if modifiers else ',' + shortcut + prompt = STORE.prompt or HUD_DEFAULTS.PROMPT + cmd = ['rofi', '-dmenu', '-i', - '-p', 'HUD', + '-p', prompt, '-lines', '10', - '-dpi', str(round(dpi)), + '-dpi', str(STORE.dpi), '-separator-style', 'none', '-hide-scrollbar', '-click-to-exit', - '-levenshtein-sort', '-line-padding', '2', '-kb-cancel', 'Escape' + shortcut, - '-sync', # withhold display until menu entries are ready - '-monitor', '-2', # show in the current application - '-theme', rofi_theme, - '-theme-str', 'window { location: north west; ' + \ - ' anchor: north west; }' ] # Override the window location to the top left of the current window + '-monitor', monitor_rofi_argument(STORE.monitor), # show in the current application or current window + '-theme', STORE.rofi_theme, + '-theme-str', 'window { location: ' + STORE.location + '; ' + \ + ' anchor: ' + STORE.location + '; }' ] # Override the window location + if STORE.monitor == 'monitor': + margin = STORE.margin + if margin[0] >= 0 or margin[1] >= 0: + cmd += [ '-theme-str', 'window { margin: ' + str(margin[1]) + 'px ' + str(margin[0]) + 'px; } ' ] # If we use the default adaptive theme, we need to pull in some # color information from the GTK theme - if rofi_theme in mate_hud_themes: - # Get the currently active font. - font_name = '' - if 'MATE' in desktop_name: - font_name = get_string('org.mate.interface', None, 'font-name') - elif 'XFCE' in desktop_name: - try: - font_name = Xfconf.Channel.new_with_property_base("xsettings", "/Gtk").get_string("/FontName", "") - except: - logging.debug('running XFCE, but xfconf gi repository not available') - elif 'X-Cinnamon' in desktop_name: - font_name = get_string('org.cinnamon.desktop.interface', None, 'font-name') - elif 'Budgie:GNOME' in desktop_name: - font_name = get_string('org.gnome.desktop.interface', None, 'font-name') - if font_name: - cmd += [ '-theme-str', '* { font: "' + font_name + '"; } ' ] - - window = Gtk.Window() - style_context = window.get_style_context() - - bg_color = get_color(style_context, 'dark_bg_color', 'theme_bg_color') - fg_color = get_color(style_context, 'dark_fg_color', 'theme_fg_color') - #borders = get_color(style_context, 'borders', 'border_color') - - logging.debug('bg_color: %s', str(bg_color)) - logging.debug('fg_color: %s', str(fg_color)) - #logging.debug('borders: %s', str(borders)) - - selected_bg_color = rgba_to_hex(style_context.lookup_color('theme_selected_bg_color')[1]) - selected_fg_color = rgba_to_hex(style_context.lookup_color('theme_selected_fg_color')[1]) - #error_bg_color = rgba_to_hex(style_context.lookup_color('error_bg_color')[1]) - #error_fg_color = rgba_to_hex(style_context.lookup_color('error_fg_color')[1]) - #info_bg_color = rgba_to_hex(style_context.lookup_color('info_bg_color')[1]) - #info_fg_color = rgba_to_hex(style_context.lookup_color('info_fg_color')[1]) - #text_color = rgba_to_hex(style_context.lookup_color('theme_text_color')[1]) - - # Overwrite some of the theme options - theme_options = 'listview { background-color: ' + bg_color + '; ' + \ - ' border-color: ' + selected_bg_color + '; } ' + \ - 'element { text-color: ' + fg_color + '; } ' + \ - 'element selected.normal { background-color: ' + selected_bg_color + '; ' + \ - ' text-color: ' + selected_fg_color + '; } ' + \ - 'inputbar { background-color: ' + bg_color + '; ' + \ - ' border-color: ' + selected_bg_color + '; ' + \ - ' text-color: ' + fg_color + '; } ' - cmd += [ '-theme-str', theme_options ] - - menu_cmd = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - menu_cmd.stdin.write(menu_string.encode('utf-8')) - menu_result = menu_cmd.communicate()[0].decode('utf8').rstrip() - menu_cmd.stdin.close() + if STORE.rofi_theme in STORE.mate_hud_themes: + update_theme_overrides_if_needed() + cmd += [ '-theme-str', STORE.rofi_theme_overrides ] + if STORE.custom_width != HUD_DEFAULTS.CUSTOM_WIDTH: + cmd += [ '-theme-str', ' window { width: ' + STORE.custom_width + STORE.custom_width_units + '; } ' ] + + STORE.rofi_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + if STORE.recently_used_current_window: + STORE.rofi_process.stdin.write(('Recently Used ' + HUD_DEFAULTS.RECENTLY_USED_DECORATION + '\n ' + '\n '.join(STORE.recently_used_current_window).replace('>',STORE.menu_separator) + '\n' + HUD_DEFAULTS.RECENTLY_USED_DECORATION + '\n').encode('utf-8')) + STORE.rofi_process.stdin.flush() + +def write_menuitem(menu_item): + menu_string = menu_item + '\n' + + if STORE.recently_used_current_window and menu_item in STORE.recently_used_current_window: return + try: + STORE.rofi_process.stdin.write((' ' + menu_string).encode('utf-8')) + STORE.rofi_process.stdin.flush() + except BrokenPipeError: + # Rofi process terminated either we selected an option, or used the + # shortcut to close before everything was piped to rofi + pass + +def get_menu(): + """ + Generate menu of available menu items. + """ + if not STORE.rofi_process and STORE.rofi_process.poll() is not None: + logging.debug("get_menu() rofi_process was terminated before asking for menu_result") + return '' + menu_result = STORE.rofi_process.communicate()[0].decode('utf8').strip() + STORE.rofi_process.stdin.close() + STORE.rofi_process = None + STORE.recently_used_current_window = None + + # Add the menu result to the list of recently used commands for the application + if STORE.recently_used_max != HUD_DEFAULTS.RECENTLY_USED_NONE and menu_result and not HUD_DEFAULTS.RECENTLY_USED_DECORATION in menu_result: + result_fmt = menu_result.replace(STORE.menu_separator, '>').lstrip() + if STORE.current_win_name not in STORE.recently_used.keys(): + STORE.recently_used.update({ STORE.current_win_name: [] }) + if result_fmt in STORE.recently_used.get(STORE.current_win_name): + STORE.recently_used.get(STORE.current_win_name).remove(result_fmt) # we're moving it to the front + STORE.recently_used.get(STORE.current_win_name).insert(0, result_fmt) + if STORE.recently_used_max != HUD_DEFAULTS.RECENTLY_USED_UNLIMITED: + STORE.recently_used[STORE.current_win_name] = STORE.recently_used.get(STORE.current_win_name)[:STORE.recently_used_max] + Gio.Settings.new('org.mate.hud').set_string('recently-used', json.dumps(STORE.recently_used)) return menu_result """ @@ -312,7 +554,7 @@ def try_appmenu_interface(window_id): appmenu_registrar_object = session_bus.get_object('com.canonical.AppMenu.Registrar', '/com/canonical/AppMenu/Registrar') appmenu_registrar_object_iface = dbus.Interface(appmenu_registrar_object, 'com.canonical.AppMenu.Registrar') except dbus.exceptions.DBusException: - logging.info('Unable to register with com.canonical.AppMenu.Registrar.') + logging.debug('Unable to register with com.canonical.AppMenu.Registrar.') return False # --- Get dbusmenu object path @@ -321,7 +563,7 @@ def try_appmenu_interface(window_id): if not registrar_running: terminate_appmenu_registrar() except dbus.exceptions.DBusException: - logging.info('Unable to get dbusmenu object path.') + logging.debug('Unable to get dbusmenu object path.') return False # --- Access dbusmenu items @@ -329,9 +571,12 @@ def try_appmenu_interface(window_id): dbusmenu_object = session_bus.get_object(dbusmenu_bus, dbusmenu_object_path) dbusmenu_object_iface = dbus.Interface(dbusmenu_object, 'com.canonical.dbusmenu') except ValueError: - logging.info('Unable to access dbusmenu items.') + logging.debug('Unable to access dbusmenu items.') return False + # --- Valid menu, so init rofi process to capture keypresses. + init_rofi() + dbusmenu_root_item = dbusmenu_object_iface.GetLayout(0, 0, ["label", "children-display"]) dbusmenu_item_dict = dict() @@ -361,16 +606,16 @@ def try_appmenu_interface(window_id): if len(item_children) == 0: if new_path not in blacklist: - dbusmenu_item_dict[format_path(new_path)] = item_id + menu_item = format_path(new_path) + dbusmenu_item_dict[menu_item] = item_id + write_menuitem(menu_item) else: blacklist.append(new_path) for child in item_children: expanse_all_menu_with_dbus(child, False, new_path) expanse_all_menu_with_dbus(dbusmenu_root_item[1], True, "") - menuKeys = sorted(dbusmenu_item_dict.keys()) - - menu_result = get_menu(menuKeys) + menu_result = get_menu() # --- Use dmenu result if menu_result in dbusmenu_item_dict: @@ -403,7 +648,7 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list terminate_appmenu_registrar() except dbus.exceptions.DBusException: logging.info('Unable to connect with com.gtk.Menus.') - return + return False # Here's the deal: The idea is to reduce the number of calls to the proxy and keep it as low as possible # because the proxy is a potential bottleneck @@ -423,10 +668,13 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list # --- Construct menu list --- potential_new_layers = [] - def queue(potLayer, label, path): + def queue(potLayer, label, path, idx = None): # collects potentially new layers to check them against usedLayers # potLayer: ID of potential layer, label: None if nondescript, path - potential_new_layers.append([potLayer, label, path]) + if idx == None: + potential_new_layers.append([potLayer, label, path]) + else: + potential_new_layers.insert(idx, [potLayer, label, path]) def explore(parent, path): for node in parent: @@ -443,7 +691,8 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list # There theoretically could be a section that is also a submenu, so we have to handel this via queue # submenus are more important than sections if ':submenu' in element: - queue(element[':submenu'][0], None, path + " > " + element['label']) + idx = 0 if node[0] == 0 else None + queue(element[':submenu'][0], None, path + " > " + element['label'], idx) # We ignore whether or not a submenu points to a specific index, shouldn't matter because of the way the menu got exportet # Worst that can happen are some duplicates # Also we don't Start() directly which could mean we get nothing under this label but this shouldn't really happen because there shouldn't be two submenus @@ -460,6 +709,10 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list menu_action = str(element['action']).split(".",1)[1] action_path = format_path(path + " > " + element['label']) gtk_menubar_action_dict[action_path] = menu_action + # If rofi isn't running already this is when we know we have a menu finally, so start it up + if not STORE.rofi_process: + init_rofi() + write_menuitem(action_path) if 'target' in element: gtk_menubar_action_target_dict[action_path] = element['target'] else: @@ -484,8 +737,10 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list gtk_menu_menus_iface.End(usedLayers) - menuKeys = sorted(gtk_menubar_action_dict.keys()) - menu_result = get_menu(menuKeys) + menuKeys = gtk_menubar_action_dict.keys() + if len(menuKeys) == 0: + return False + menu_result = get_menu() # --- Use menu result if menu_result in gtk_menubar_action_dict: @@ -508,6 +763,76 @@ def try_gtk_interface(gtk_bus_name, gtk_menu_object_path, gtk_actions_paths_list action_iface.Activate(action, target, not_use_platform_data) except Exception as e: logging.debug('action_path: %s', str(action_path)) + return True + +# DbusPlotinusMenuItem and DbusPlotinusMenu classes taken and slightly +# modified from gnome-hud https://github.com/hardpixel/gnome-hud +class DbusPlotinusMenuItem(object): + + def __init__(self, item): + self.path = list(item['Path'])[1:] + self.action = int(item['Id']) + self.accel = list(item['Accelerators']) + self.label = item['Label'] + self.text = format_path('>' + '>'.join(self.path + [self.label])) + +class DbusPlotinusMenu(object): + + def __init__(self, session, window_object_path): + self.actions = {} + self.session = session + self.win_path = window_object_path + self.interface = self.get_interface() + + def activate(self, selection): + self.actions[selection].Execute() + + def get_interface(self): + bus_name = STORE.plotinus_bus_name + bus_path = STORE.plotinus_bus_path + + try: + object = self.session.get_object(bus_name, bus_path) + interface = dbus.Interface(object, dbus_interface=bus_name) + return interface + except dbus.exceptions.DBusException: + logging.info('Unable to get plotinus D-Bus interface') + return None + + def get_results(self): + self.actions = {} + + if self.interface and self.win_path: + name, paths = self.interface.GetCommands(self.win_path) + commands = [self.session.get_object(name, path) for path in paths] + + if commands: + init_rofi() + else: + return False + + for command in commands: + self.collect_entries(command) + return True + + def collect_entries(self, command): + interface = dbus.Interface(command, dbus_interface='org.freedesktop.DBus.Properties') + command = dbus.Interface(command, dbus_interface=(STORE.plotinus_bus_name + '.Command')) + properties = interface.GetAll(STORE.plotinus_bus_name + '.Command') + menu_item = DbusPlotinusMenuItem(properties) + + self.actions[menu_item.text] = command + write_menuitem(menu_item.text) + +def try_plotinus_interface(gtk_win_object_path): + plotinus = DbusPlotinusMenu(dbus.SessionBus(), gtk_win_object_path) + plotinus_success = plotinus.get_results() + if not plotinus_success: + return False + menu_result = get_menu() + if menu_result: + plotinus.activate(menu_result) + return True def hud(widget, keystr, user_data): logging.debug("Handling %s", str(user_data)) @@ -519,6 +844,10 @@ def hud(widget, keystr, user_data): logging.debug('ewmh.getActiveWindow returned None, giving up') return window_id = hex(ewmh._getProperty('_NET_ACTIVE_WINDOW')[0]) + win_name = ewmh._getProperty('WM_CLASS', win) + # comes back in the format b'name\x00Name\x00' and we just want to keep name (\x00 is Null character) + win_name = bytes(bytearray(win_name)[:bytearray(win_name).index(0)]).decode('utf-8') + STORE.current_win_name = win_name gtk_bus_name = ewmh._getProperty('_GTK_UNIQUE_BUS_NAME', win) gtk_menubar_object_path = ewmh._getProperty('_GTK_MENUBAR_OBJECT_PATH', win) gtk_app_object_path = ewmh._getProperty('_GTK_APPLICATION_OBJECT_PATH', win) @@ -529,7 +858,8 @@ def hud(widget, keystr, user_data): [i.decode('utf8') if isinstance(i, bytes) \ else i for i in [gtk_bus_name, gtk_menubar_object_path, gtk_app_object_path, gtk_win_object_path, gtk_unity_object_path]] - logging.debug('Window id is : %s', window_id) + logging.debug('Window id: %s', window_id) + logging.debug('Window name: %s', win_name) logging.debug('_GTK_UNIQUE_BUS_NAME: %s', gtk_bus_name) logging.debug('_GTK_MENUBAR_OBJECT_PATH: %s', gtk_menubar_object_path) logging.debug('_GTK_APPLICATION_OBJECT_PATH: %s', gtk_app_object_path) @@ -541,8 +871,10 @@ def hud(widget, keystr, user_data): appmenu_success = try_appmenu_interface(int(window_id, 16)) if not registrar_running: terminate_appmenu_registrar() - - if not appmenu_success and gtk_menubar_object_path: + if appmenu_success: + return + gtkmenubar_success = False + if gtk_menubar_object_path: logging.debug('Appmenu found nothing.') # Many apps do not respect menu action groups, such as # LibreOffice and gnome-mpv, so we have to include all action @@ -553,9 +885,23 @@ def hud(widget, keystr, user_data): gtk_menubar_object_path, gtk_app_object_path, gtk_unity_object_path])) - try_gtk_interface(gtk_bus_name, gtk_menubar_object_path, gtk_actions_paths_list) + gtkmenubar_success = try_gtk_interface(gtk_bus_name, gtk_menubar_object_path, gtk_actions_paths_list) + else: + logging.debug('_GTK_MENUBAR_OBJECT_PATH in None. Unable to use the menubar interface.') + if gtkmenubar_success: + return + else: + logging.debug('GTK menubar found nothing.') + if STORE.plotinus_enabled: + logging.debug('Trying Plotinus interface') + if gtk_win_object_path: + success = try_plotinus_interface(gtk_win_object_path) + if not success: + logging.debug('Plotinus found nothing. Giving up.') + else: + logging.debug('_GTK_WINDOW_OBJECT_PATH in None. Unable to use plotinus interface') else: - logging.debug('_GTK_MENUBAR_OBJECT_PATH in None, giving up.') + logging.debug('Plotinus is not enabled') class GlobalKeyBinding(GObject.GObject, threading.Thread): __gsignals__ = { @@ -570,7 +916,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread): self.display = display.Display() self.screen = self.display.screen() self.window = self.screen.root - self.keymap = Gdk.Keymap().get_default() + self.keymap = Gdk.Keymap().get_for_display(Gdk.Display().get_default()) self.keycodes = self.get_keycodes() self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() @@ -759,14 +1105,6 @@ def get_shortcut(): logging.error('org.mate.hud gsettings not found. Defaulting to %s.' % shortcut) return shortcut -def get_rofi_theme(): - rofi_theme = 'docu' - try: - rofi_theme = get_string('org.mate.hud', None, 'rofi-theme') - except: - logging.error('org.mate.hud gsettings not found. Defaulting to %s.' % rofi_theme) - return rofi_theme - def remove_autostart(filename): config_dir = GLib.get_user_config_dir() autostart_file = os.path.join(config_dir, 'autostart', filename) @@ -775,7 +1113,7 @@ def remove_autostart(filename): if __name__ == "__main__": setproctitle.setproctitle('mate-hud') - logging.basicConfig(level=logging.INFO) + logging.basicConfig(level=logging.DEBUG) # Remove old-style autostart .desktop file for mate-hud remove_autostart('mate-hud.desktop') @@ -788,6 +1126,212 @@ if __name__ == "__main__": tap_timeout = settings.get_int("tap-timeout") keybinder.tap_timeout = tap_timeout; + def change_rofi_theme(schema, key): + default_theme = HUD_DEFAULTS.THEME + rofi_theme = settings.get_string("rofi-theme") + + themes = get_theme_list() + if not rofi_theme in themes: + logging.info( '%s not found as a valid rofi theme, defaulting to %s' % ( rofi_theme, default_theme ) ) + settings.set_string('rofi-theme', default_theme ) + return + + if rofi_theme in STORE.mate_hud_themes: + if Gtk.Window().get_scale_factor() > 1 and rofi_theme in STORE.themes_hidpi_versions.keys(): + rofi_theme = STORE.themes_hidpi_versions[rofi_theme] + STORE.rofi_theme = rofi_theme + if STORE.rofi_theme in STORE.mate_hud_themes: + update_theme_overrides_if_needed() + + def change_monitor(schema, key): + STORE.monitor = get_monitor() + change_location(None, None) + + def change_location(schema, key): + location = get_location() + if location == 'default': + location = HUD_DEFAULTS.LOCATION if not isrtl() else HUD_DEFAULTS.LOCATION_RTL + logging.info( "Using default location: %s" % location ) + else: + logging.info( "Updated location to: %s" % location ) + STORE.location = location + change_panel_margin(None, None) + + def change_panel_margin(schema, key): + if STORE.location == 'center': + logging.info( 'Updating panel margin to 0 for HUD in the center' ) + STORE.margin = [ 0, 0 ] + elif STORE.monitor == 'window': + STORE.margin = [ -1, -1 ] + else: + STORE.margin = get_panel_margin() + + def change_custom_width(schema, key): + try: + STORE.use_custom_width, STORE.custom_width, STORE.custom_width_units = get_custom_width() + except: + logging.error( "Invalid custom width specified. Resetting to default." ) + settings.set_string('custom-width', HUD_DEFAULTS.CUSTOM_WIDTH) + return # since we changed the setting, it will call this function again + if STORE.use_custom_width: + logging.info('Using custom width ' + STORE.custom_width + STORE.custom_width_units) + else: + logging.info('Using width specified by theme.') + + def change_menu_separator_pair(schema, key): + STORE.menu_separator_pair = get_menu_separator_pair() + logging.info('Menu separator pair set as %s' % STORE.menu_separator_pair) + STORE.menu_separator = get_menu_separator(pair=STORE.menu_separator_pair) + + def change_recently_used_max(schema, key): + STORE.recently_used_max = get_number('org.mate.hud', None, 'recently-used-max') + logging.info( 'Updated recently used max number entries to %d' % STORE.recently_used_max ) + if STORE.recently_used_max > 0: + for key in STORE.recently_used.keys(): + STORE.recently_used[key] = STORE.recently_used.get(key)[:STORE.recently_used_max] + settings.set_string('recently-used', json.dumps(STORE.recently_used)) + elif STORE.recently_used_max == 0: + settings.set_string('recently-used', '{}') # 0 means don't save recently used, so clear it out. + + def change_recently_used(schema, key): + recently_used = get_string('org.mate.hud', None, 'recently-used') + try: + STORE.recently_used = json.loads(recently_used) + except: + logging.info( 'Reset recently used list to empty.' ) + settings.set_string('recently-used', '{}') + + def change_prompt(schema, key): + STORE.prompt = get_string( 'org.mate.hud', None, 'prompt' ) + + def start_plotinus(): + # Enable plotinus D-bus service in gsettings + ss = Gio.SettingsSchemaSource.get_default() + schema = ss.lookup('com.worldwidemann.plotinus', True) + if schema: + STORE.plotinus_schema = 'com.worldwidemann.plotinus' + STORE.plotinus_path = '/com/worldwidemann/plotinus/' + STORE.plotinus_bus_name = 'com.worldwidemann.plotinus' + STORE.plotinus_bus_path = '/com/worldwidemann/plotinus' + else: + schema = ss.lookup('org.unityx.plotinus', True) + if schema: + STORE.plotinus_schema = 'org.unityx.plotinus' + STORE.plotinus_path = '/org/unityx/plotinus/' + STORE.plotinus_bus_name = 'org.unityx.plotinus' + STORE.plotinus_bus_path = '/com/worldwidemann/plotinus' + if schema: + # The last tagged release of plotinus 0.2.0 doesn't include the dbus service + # so we need to make sure this key exists that we're using a compatible version + if schema.has_key('dbus-enabled'): + plotinus_settings = Gio.Settings.new_with_path(STORE.plotinus_schema, STORE.plotinus_path + 'default/') + plotinus_settings.set_boolean('dbus-enabled', True) + else: + logging.info('Unable to enable plotinus D-bus service') + return + else: + logging.info('Plotinus schema not installed') + return + # Start the D-bus service executable + if not process_running('plotinus'): + try: + subprocess.Popen(['plotinus']) + logging.info('Launching plotinus D-Bus service') + except: + logging.info('Unable to launch plotinus D-Bus executable') + return + else: + logging.info('plotinus D-Bus service is already running') + STORE.plotinus_enabled = True + + def xfce_panel_change_handler(channel, prop, value): + watched_props = [ 'autohide-behavior', 'mode', 'position', 'size', 'panels' ] + prop = prop.split('/')[-1] + if channel == 'xfce4-panel' and prop.split('/')[-1] in watched_props: + # If we got a new panel or removed one, update our listeners + if prop in 'panels': + setup_panel_change_handlers() + panel_change_handler(None, None) + + def panel_new_or_removed_handler(schema, key): + panel_listeners = setup_panel_change_handlers() + panel_change_handler(None, None) + + def panel_change_handler(schema, key): + if schema and key: + logging.debug('Called panel_change_handler. schema: ' + \ + schema.get_property('schema-id') + \ + ', path: ' + schema.get_property('path') + \ + ', key: ' + key ) + else: + logging.debug('Called panel_change_handler manually.') + update_panel_margin() + + def vala_panel_change_handler(e): + update_panel_margin() + + def setup_panel_change_handlers(): + #xfce4-panel + bus = dbus.SessionBus() + try: + object = bus.get_object("org.xfce.Xfconf","/org/xfce/Xfconf") + # Listens to every change on xfconf, so we'll have to filter out what we care about + object.connect_to_signal("PropertyChanged", xfce_panel_change_handler, dbus_interface="org.xfce.Xfconf") + except dbus.DBusException: + logging.debug( 'Unable to set D-Bus listener for xfce panel changes.' ) + + ss = Gio.SettingsSchemaSource.get_default() + settings_objects = [] + #mate-panel + if ss.lookup('org.mate.panel', True): + settings_objects.append(Gio.Settings.new('org.mate.panel')) + settings_objects[-1].connect("changed::toplevel-id-list", panel_new_or_removed_handler) + panels = get_list("org.mate.panel", None, 'toplevel-id-list') + for p in panels: + settings_objects.append(Gio.Settings.new_with_path( 'org.mate.panel.toplevel', '/org/mate/panel/toplevels/' + p + '/' )) + settings_objects[-1].connect("changed::size", panel_change_handler) + settings_objects[-1].connect("changed::orientation", panel_change_handler) + else: + logging.debug( 'mate-panel schema not found' ) + + #budgie-panel + if ss.lookup('com.solus-project.budgie-panel', True): + settings_objects.append(Gio.Settings.new('com.solus-project.budgie-panel')) + settings_objects[-1].connect("changed::panels", panel_new_or_removed_handler) + panels = get_list('com.solus-project.budgie-panel', None, 'panels') + for p in panels: + settings_objects.append(Gio.Settings.new_with_path( 'com.solus-project.budgie-panel.panel', '/com/solus-project/budgie-panel/panels/{' + p + '}/' )) + settings_objects[-1].connect("changed::size", panel_change_handler) + settings_objects[-1].connect("changed::location", panel_change_handler) + else: + logging.debug( 'budgie panel schema not found' ) + + #plank + if ss.lookup('net.launchpad.plank', True): + settings_objects.append(Gio.Settings.new('net.launchpad.plank')) + settings_objects[-1].connect("changed::enabled-docks", panel_new_or_removed_handler) + docks = get_list('net.launchpad.plank', None, 'enabled-docks' ) + for dock in docks: + settings_objects.append(Gio.Settings.new_with_path('net.launchpad.plank.dock.settings', '/net/launchpad/plank/docks/' + dock + '/')) + settings_objects[-1].connect("changed::position", panel_change_handler) + settings_objects[-1].connect("changed::icon-size", panel_change_handler) + settings_objects[-1].connect("changed::theme", panel_change_handler) + settings_objects[-1].connect("changed::hide-mode", panel_change_handler) + else: + logging.debug( 'plank schema not found' ) + + #dockx + if ss.lookup('org.dockbarx.dockx', True): + settings_objects.append(Gio.Settings.new('org.dockbarx.dockx')) + settings_objects[-1].connect("changed::position", panel_change_handler) + settings_objects[-1].connect("changed::behavior", panel_change_handler) + settings_objects[-1].connect("changed::size", panel_change_handler) + else: + logging.debug( 'dockx schema not found' ) + + return settings_objects + + enabled = False enabled = get_bool('org.mate.hud', None, 'enabled') @@ -804,10 +1348,54 @@ if __name__ == "__main__": settings = Gio.Settings.new("org.mate.hud") settings.connect("changed::shortcut", change_shortcut) settings.connect("changed::tap-timeout", change_tap_timeout) + settings.connect("changed::rofi-theme", change_rofi_theme) + settings.connect("changed::hud-monitor", change_monitor) + settings.connect("changed::location", change_location) + settings.connect("changed::custom-width", change_custom_width) + settings.connect("changed::menu-separator", change_menu_separator_pair) + settings.connect("changed::recently-used-max", change_recently_used_max) + settings.connect("changed::recently-used", change_recently_used) + settings.connect("changed::prompt", change_prompt) + + # watches what panels are running + STORE.panels = get_running_panels() + panel_updater_thread = threading.Thread(target=thr_panel_updater, daemon=True).start() + + # If we don't preserve the gsettings objects in this context, + # the listeners don't work + panel_listeners = setup_panel_change_handlers() + + vala_panel_config_dir = GLib.get_user_config_dir() + '/vala-panel/' + watch = True + if not os.path.isdir(vala_panel_config_dir): + try: os.mkdir(vala_panel_config_dir) + except: watch = False + if watch: + wm = pyinotify.WatchManager() + notifier = pyinotify.ThreadedNotifier(wm, default_proc_fun=vala_panel_change_handler) + notifier.start() + wm.add_watch(GLib.get_user_config_dir() + '/vala-panel/', pyinotify.IN_MODIFY, rec=True, auto_add=True) + else: + notifier = None + + # Do some initial setup, so we don't have to do it when the HUD is called + change_rofi_theme(None, None) + change_monitor(None, None) # This calls change_location too + STORE.dpi = get_display_dpi() + change_custom_width(None, None) + change_menu_separator_pair(None, None) + change_recently_used(None, None) + change_recently_used_max(None, None) + change_prompt(None, None) + start_plotinus() try: GLib.MainLoop().run() except KeyboardInterrupt: + if notifier: + notifier.stop() + terminate_appmenu_registrar() + kill_process('plotinus') GLib.MainLoop().quit() else: logging.info("The HUD is disabled via org.mate.hud in gsettings.") diff --git a/usr/share/applications/hud-settings.desktop b/usr/share/applications/hud-settings.desktop new file mode 100644 index 0000000..c61beb0 --- /dev/null +++ b/usr/share/applications/hud-settings.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=HUD Settings +Exec=/usr/lib/mate-hud/hud-settings.py +Icon=mate-hud +StartupNotify=false +Terminal=false +Categories=Settings; +X-XfcePluggable=true diff --git a/usr/share/glib-2.0/schemas/org.mate.hud.gschema.xml b/usr/share/glib-2.0/schemas/org.mate.hud.gschema.xml index 020ff48..65f16bf 100644 --- a/usr/share/glib-2.0/schemas/org.mate.hud.gschema.xml +++ b/usr/share/glib-2.0/schemas/org.mate.hud.gschema.xml @@ -1,5 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + true @@ -23,6 +48,73 @@ Find available themes in /usr/share/rofi/themes or put your own in ~/.local/share/rofi/themes + + 'window' + Whether to pin the HUD to the monitor or to the current window + + Whether to pin the HUD to the monitor or to the current window + + + + "default" + Where to position the HUD on the window (or monitor) + + Where to position the HUD on the window (or monitor) + + + + '' + The prompt to use for the HUD + + Prompt to use for the HUD + Default: '' -> displayed as HUD localized if available + + + + '0' + A custom width for the HUD (or 0 for default) + + Custom width for the HUD. + + 0: Use theme defined width + + 'NUM' or 'NUM px': NUM screen pixels + + 'NUM em': Relative to text height. + + 'NUM ch': Relative to width of a single number. + + 'NUM %': Num percent of the monitor* width + + * monitor to rofi means whatever it is attached to (window or monitor) + + + + "◂ ▸" + Character to separate the parts of the menu heirarchy in the HUD (RTL and LTR variants) + + Character to separate the parts of the menu heirarchy in the HUD (RTL and LTR variants) + + + + "{}" + JSON dictionary of recently selected menu items per application + + JSON dictionary of recently selected menu items per application + + + + 10 + + The maximum number of recently used menu entries to save per application + + The maximum number of recently used menu entries to save per application + + -1 is interpreted as unlimited entries. + + 0 is interpreted as don't show/save recently used items + + 250 The timeout between key press and release to determine if the user meant to open MATE HUD @@ -31,5 +123,17 @@ Set to 0 to disable the timeout. + + 100 + + The transparency of the HUD window background + + The transparency of the HUD window background + + 0 completely transparent + + 100 solid color + + diff --git a/usr/share/icons/hicolor/1024x1024/apps/mate-hud.png b/usr/share/icons/hicolor/1024x1024/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..7a6de7654aea1da03efe96b76dfcae9809cd2507 GIT binary patch literal 27569 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 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/128x128@2/apps/mate-hud.png b/usr/share/icons/hicolor/128x128@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..01891edeaf2b327f24866e49263707183c09e0fe GIT binary patch literal 5999 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 BE`0z1 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/16x16/apps/mate-hud.png b/usr/share/icons/hicolor/16x16/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..d6fc516b4b2cc5babab97a891c53c3ed38f2bc29 GIT binary patch literal 534 zcmV+x0_pvUP)E z%yJPC1)WakF_Az-AR<(&)t^EL0+1NFT<&kP*(`x^7xZxw1J7+qUl;jmGIb zKmdT&`jgf=a#g8R;5ZIA=gWodZ<@bGwX?0MdX zQtBlUF!Bwqetbt@^g@37u!N1>ee7&*ajo@70Lg&!{m;mMtHBtvkl+2X2f4O}%ipg+ z`U6&uV6AgZ|J-7JFN`sq9p;frr50)v0Yn7LvM`&?qFg4Ei8V(6DdnpWBC^amN1;$a z5ClSze(COCKX#5y9^JyY9|hcMFxt)4Np3pM`^7d1sUkE;3aQP(%UZm z3#6>NgW`{q2NCJP!(0yo1sx0q8|<>$HYEv3-(9AxU4Oi-4*kM&NS^0?o=@^VZ}M=I zQrxBZJFR{n09>^knx^r(uD@^`r;9n6%k@K+-6*#larH=B}qC2Fj(gNdp}lI zR-U59o^Eb#(wiumOj1dbC?Q1tyC(A+2n3%Xx|KoRVn5gUZdnV4dY#sTz0Jp z)ejdlfY-%g>3KJ@&zQf=*J^X|cv$#;GXMY>?|y)zqa&E6*)Vo^co>SJTwiB0w*a8) zI^yv-6Ts@~Du#xJ8pbsRpePD&48>3@pp48y5@)nRAu_h@$vak|Y?0Q8ic)1WZp)Gbe8vKvmVk$;rv5?d|QsYQc`< zAel_o1Oxz46cG-G;qiEy2LOOjDD=`WjF0>K`+>@l-84-cA0OB40iNeEH8s^bz@Pth zZ!8vjmCa_~tb(6q=d?^7%YnTU(>;?d^1aem+&1 zn+bpr!bhXg%~l82&dyG!T5(D#xXMPWCr#7%VzD@8+x8>YHG&{~QxxS$Rn<~8e^UVe fLwEi!xO0Htsl|`-PKBG_00000NkvXXu0mjfwxpuD literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/22x22/apps/mate-hud.png b/usr/share/icons/hicolor/22x22/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..575be8d285b027e6ad67cb0df06f0794eff556c9 GIT binary patch literal 669 zcmV;O0%HA%P)XV!zZp#*$&=E-;KdldMT`$ZZBdC52tf$0g1|-LPKE*zhc>fO2y~;1 zT0XEv3;PFj5ezP(zhIDTA#MhutYLUj))k+()rdZ4Mtk802j-sdoF8ZI%;hqaQtU$P zPN)FfXA_bnJvIy@J)h4#c1>Qd_ggR+Jg(JhpKQsL(nVx4nU4VIHsSaC=fz_2*>eAK zEFQ|`@}q5`X2j$16Fcx?k0+DKt$)};06@Rr_eZ1AAK7fSFU#^B%dHSav3_!>Est@dbVHyIN0CA;oWuX8x0VHk#C=?j7YpU(#XD7{-f!H!@6P!t8D(a6%v=ktg}B9`7p zaG_AxRB}GBBuP+JbuAwbhtX=aHiO-6w{BI?Y&N$W(GJXU+#8zbymyhXd+hNfw2 zjj2=$$z*afxKgQ%2_Y#}Ra=^-g@?o8J^&mY9U&A7tu^vIzp|#3f?*iClCX+cEOs&& z3>=U1veM}^l_cq*+0WSBAf;02X|LCNmCNN^9LHJK0KjxQg`y~!&1U^hr*qTH+kyc= zmgO6|t``U)SL|w7mYoIy0j1Gsyj{*ag8xT5yYv16pWkN#6BGa700000NkvXXu0mjf D%(*S- literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/22x22@2/apps/mate-hud.png b/usr/share/icons/hicolor/22x22@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..727b165401ee6523a3d517c78980e0110f22fc2b GIT binary patch literal 1128 zcmV-u1eg1XP)z5BUc#4pP4itDC5Sa?OKf57`;-frJB%`(k_H(p{1flTF5`JcP&B$jm-pt zkx<+lu@~xX_LwH zozZ9<^>{oFnSv0JWOKXSCX2=L0033GwYRrtT`t$PLb;1I$(N!i@_l`MhZh0+Pitvu zITJFWwY5U z%5h377K^<&G&J-h&+~af5F!l?4LAIL|F1=zr0T@saO~m&>$gzTXf!lDJbX(OMNOd^ zF1oChQh$FxTrL+nIy#`yXqe+1A0K09X9pgS2P-QpZ|8Ek5P)t;W7ZxX85yBU>-6-L zdU|?@<2V`}9sRWIRiYgEd_Gp!g3@ZWn4Fvh5g{IrUzf6BDhZuVhqksh-1vD9za;-q zM)`!^Xt;upy1D=WnM~%YlnoQGN~OZX^E`gI`v8BQpX2Q4cP2os-T;pOcaU%0J;Z?F z@8zF}BuAfl(jDa03Bd8A;s*+5V7*oijssqEe2ka6 zEKD&3qv@$<4uGKMiuy1E*Qix^uf>4SfeQ8Yde$&c>CIR5s3}3DXdV8{Vk&JUQ+s=R zMZYTo27qWZij9p8*?u;g4V|5xvi%eT&(F_edU{&6pVR5Y($bP_KgCBRzuzx=6HY`- zuoVG*)~Y&S#WlRWy)Apvb$54TU|@hLpJL$Ugs-bW&|=N3Eb4w^cBYy|EFJ;BuipuX6EMZ?(W$7`ugjo0!&R!VR3P>?1VKn zHQ3zTgkI0K|0p==dV72ObUNL}+S=MXxm>Pb0K44|l}c51!rIze2!bGw@(FQN;zE03 zVxlLROn#nDr_K3%UbVHgWyxeR{K?4)bJAjpMx!vB&2TszcY?uS`~M8&{!*=0>pcK; zaBxuZLnskZFc>5NG&neTyCR2Bv)TL;0L;zJDelexiijS^ZES4(x}cGqHat=9W?yS>-v^TnlXnScSn>-FmP_xHby#bWQL(`lt=Br+Hbsn*uk uo3pdCMK3&K+ZsphPQN) zZVuTsP9@;jxy{fag-)eH5gLLJ4{hps-uXItSUt~6iXZ&L```Ef-~ayi`0qHz7-k86 zrr7}qPEJKp5~gV`xCQ!rzCVPJFNcSReOCp>m~DG|dyiIDR(=CuUMw1onzAgb!#PIn zpG7j6YUuwXFA6h%o+6;M?*!g1VCdyHBEb2C=`yz?%?3yV0pAMNs?Hr)nZ<8c6P?%@p#wq1Ws6A zUq|JKhHs6!8_mY!WeL~U*ZzDyzd$Ly046-s0R%z7=bsIHEWQKlTN8N?p1yz>3L`S# zf*=Usd7jugrd5@^e-HfYyr&a94Br_qa$3-vH3{eE=P*svaX%amLy{zWox7=kVHl`X zDzGf)79|o1?C$PPjGrpt_xnL9okqL8K&R6IrF3G8WLZWm7Mm{6@Aq{lf+&jE+S)>| z*Bjg8I1Z6W#I-zyl@H~%HD&;6Z2tgna@FoBN+uPf(N~Kcq^77I* z@aejaY&HwSFvf!8@i>abqIZEpp>P}ug+4T!&1dy`{kg8|X+j99)v9ZfVRXA)2!hbI z9h1haqA1B&EY`2pYMy7&$;k;@U0rQ?nnje-ubQU4-Q3*FFD@<$gpf&80KnDN6)ekY zXEK>5!+y@oM}L2Rf6cP2c{h$IiocGIj=qojJqi2|X8u?47u{jGZA3V)zyJUM07*qo IM6N<$f=9hfaR2}S literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/24x24@2/apps/mate-hud.png b/usr/share/icons/hicolor/24x24@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..aa1a6d6c4b16a779349aa788d12f6e021fe63d7c GIT binary patch literal 1245 zcmV<31S0#1P)W z|Kt84SeC^@26^8EgyK=aedECkC@R#^YPCL($K#DG%Thv%QWO;}EiL`d>2w|m%>|Za zbDG6sd0ACebq#l}hP^(czB0y}jzLuC6_bqHg4Jc|fbxzI40Yukr?F>MN_&+KT_F|8rS$ zb8~QFVxlhB94L4n$Of9GF+4nswzf9t^?Hz`u)Q%7iC}ws8*aB7Uawah4u`i%lB~2l2{$nsAzgLt?X}qXaqoJVzKA(?>$K#Cv-rV*RBtRmO;G6vrmi@;< z(qzT6av7vjDFA?Bn6gYhf+z8>=kLJWT;sRzUm=ya;+KRVp!@haWKXpJdVFyHE^nw{ z0SwC`8Nb3GyFVd$b;&CSK~X5LZ~Bh_rhu*#ETB>@#V>LNJ{;$D637XiT$0yEumE$t z8j-{el7;+S9PmU&qe(5#>nB)1l|qWonrnro;SIq8fWP*V#l=NLA`#B91VO-LGC`}= z=6B8jQ3M#Rg3V^*6)TDWwOWmEIE-jC$~l%KNmN%?^R6w5002;_ zR8Xl@Vx=n>5B^%^Q2+oO92`I?oDW2l2;2#u1pFp1$7P+}v7PTKb^SL|0c=h{xlc zikFp@fue+6wPu|Ijg5`w{r&y7e!oBOkuVqx;_1_;NF)-Rikr=5csw3XF}IObfYa$b zVi=}reSQ5$uh*ONpi)s$f%*A)oSmInI@-Umu<%7R8YSxM>(ScUD(G08Ml2SC&*#I+ z$_kRnBupmL?(*{T`&k3{v{2e?Hd~9)Xgn$|E*AY_x2C4%dSGDS^L!k5kH9}MIXS6| z#bPf~sgy!+GT=rgll?q9JNrW+&Y}poPdvU4+&3Nt+&BIN>5!ucpsW;#00000NkvXX Hu0mjfLgqhu literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/256x256/apps/mate-hud.png b/usr/share/icons/hicolor/256x256/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..01891edeaf2b327f24866e49263707183c09e0fe GIT binary patch literal 5999 zcmchbcTkg0x5uAQ6%nLE072=}dv5|_lq$W0bSZ|egc864N>NZ+=m<#vN$*v9uL=YR zVCaP2+kKpQ@64UK_q{XspPQM?lR3}sX7}vwIiK%|(9u%AO#&qW0N^(4vFbAbfPg{B0DrZlASLaoO+E0C= zzda)1JPwUpjY#Hv$a}9{HIj$x=|GugTuMoiIaE7q!hYQ6XI%2L;_t%TJkJ}H04yg| zpjRz1B=E{!Z*DTRq-wHTT3Rwc z%KkAsGgIF)G*k*UXCWsg<@?99cmO@6%K3U4+ge^$*2c)l_-lM}Qb9*omm>IR)1-XX zeI=T(`W}q3qqEc3gfG6}`}glEHa0fR^EDo}6n+AqU#UWVyGmS7Pfr^Srpi|Dd=zX7 z-&|eAL=#+E3(-5FYdn5+Ml&N=IXRbqZTu<~Tp9ec=4}B?O--@&_VooHCp2GhBJaxAr6P81Duf{r zi2RVkc~KO?!oTew;#D`pV$;L^4CS!8S~})OX0~EbELYmA=Um5U)Fz}!(Zs~$Gwnw#(Q#9M|Yhh`@RI; zOjwI84)%6(;`TkZ!M$LI#Tu1bHijbPH|)js$uQ_zFBXeNe*@9iO6hhcxkHNAazhT~ zHvBvp5sIUAJ{ym)D=XS7gOIe$Z{L0fobK84`jN>Gt3tjcBwUwNR?;-D<0nW5U7S3? zk@~k-0urbJePiPj6&w@BL@P~>p#fYjajlmVGXetc7Dskn-SpCs<_(;Yp<(<$s`AF~ zTN!0#p7;ESb~HFRIF@Qe|F--RA0NFq2&CmVG@xbK*laod$oOsfkv2A`|qa?;Ns6et$xt%$B0fOD zL&6Op6-aK}_!Ji#d!^vepGX(9kD6!tGw5X`rL8Vz-}{C4TgcdB8=*^vuvS(s4i1an z?(W2nz!#-gWK9GFt9fZ@cOP(bhl784u|HMrsLjdF{%vjRmg*)OVa-zu3yTWJp|qRZ zjmMT)uOazkIlr_fB?wUSSW`1p`cU}^!N97S{Y0od*R~Z zvgLaoXnOq^i3jMkj%2G7S65V|B(U>%T%H|b(XVj?ge`pc?}z4Ur)xz-MA-c>=H}yz z3=IvfvAvmBUyn*gq4MkMl6!l5SARxOd2jv}e&Ob}b?lZV?bT@&`>h$JkxNiGaTaxJ zsg9HcsjRP0Er0qa?n_!4IGU8zTSI9kGMQI9tbuzyTn9Z|={g9+JUIa$KmVa5G^#_D z+P>1Xv{nIY(dGf*P&GADr`a(IvGsLzcEbsUMy0*rlI{vwD>dIe2c4481O2^yeW?to zu>o%=b^s;06tN8vuxjEHv}~xc+Q6(RUY~ZA5v3helaVN4lZ0$S190ftdUM|l@p`}Q zc$J3_&njs99m*TrXX{vcpsyC^nV5((vR>~mk7TO6=N1r%mL;kAtwJuZsvdJU=QEr7 zgDXYwoOxqfLM%+{;Q0=ruaXZAyr-K2Ws?S^Hj?r_#Kh#azb79{6t<=azlP=@44x?G(21m=Z?~5OaWDu>f1>!b0U7-pAHCb-W7kho5`uqD? z3YqeaxBS)fmSdOQmk`&g5B{lGc(0} z*7b4p85GXW&L67EXST-Y<`j&uQd(edRt}E0q(m1y3oM+P$*TCoWcn3uPoMUAe_fJ# zYp{WL0uw~{S_=*T{$WewHZwjhW(sy&&=IH8@h`gmdL&TL7^H#~%ix5?a&vaaga)K2 z`YbLjtqo_YG|pM7s}pZbS%I#)LrJ-KFh8?3TY>#ZB4atWnX8(?84(^NB9amx8FN3I zebyH>H~CW&ZPeYV4$#4m!dQ}SXa|wAQH{*qN^qW8o0fH_x^pLEwMs@-Hqe5)@b93k zvkL~u@YS7;M{=j~BGS zO>Qqm;_1Lpji?ujUP+a4iEq}^2z#)Of4Id zQGE4axAQadLG9>Vj#E9OrqTDs7P2}+gGaNezir{w8bJ;ucZJ_QcaYamQ0@)-v_x`y z%fgP~d$XugHlUyNhu_9!R_$!P*nAz==0{kvxayRB)=6}Bq(KoCd}P1JNR5j>Z;Xxs z;Dv*@G|Ot~>%8mEI4h2$stx_7ZMN#!`P+ms)wJLoN7vv@tnOkKnUm8GBy%YA#!e|? z>+5Gdtt999gp5B|2x9DwRLte!p>R>nzZAjvOzGTVXS1h(#y(4nUd)`5R z5F`DZo}r-u?A|CpXPPrKE`xFLyvq9;`KWHCE2f4gD)BjsF{bK#Zv(qK`CyY!r-!w9 z&g%6$E!e&LS-nHPpR+BR)#IF_w1<_TyK(6wExJpyzUg5Xv-?`@6W~7F6y-I$qmuVc z=O=lPDzni>{!GX=AuhgWCLutj9Ttl||4?+WI|&8dd>{X7`l^};v`5i=s)Jn#(LhT1 z_S9wZd2?Xy5V?SikSmhq6tO_kdY_)+d8Z|CA^^MpVQe8YbJ%Y;?BHAqbh39ay8x9y zD9`8KL7+$t3=^7BB(+P<*{!0a2m4tgnP>88_~4PbVBSMXs9j)wK(!HOF@c4N zUE=|MgoFUA5H)~o(E$KF6;K6`{#QeLh!RxS!a~zR%HUOcq6X)O=xENH?@f*wNsuNs zHuvNY$Mw9I`x$WDb<|W;Dy7X=GW^DvCQ$%E89-pIudlBPgTY?y&A%-uc<@A9JI|ut z*F$}TgBr*-C^Y>17iTjOWqf)L4xE0Z77rmp9#Twy6AzC5Zgx>o z8$4@YF!v4*Y_!AMckiA( zc|sD!qL?Q8L0uUlR8Ux$4JM(pnfa?uW;MyQpfhLx{Q=1y>lT!eQH#~*2)@1wyB>iJwvl!Qmu4m~%($)%n44GgvLuHl^dtD|Z(g&YwH688GFv>(B2K|w*A!B-2A z1^#9q*-&>iRaHz|fj}spwaDu|JE*KLAGj5!Rjv$v1Ti6a*3ZSD&Rx;WVy?f1z)g;g zkAEcCct8odJY*Ib`6vpimXnin(4~0w`N@+f-3xHI`e+dn2|R(pGRMdDaol$aLFiy* zMW(%8X28+2at9FnONSK^vch8fUta@Rw*0`$m)lx{=froIT_7iCXNxN@fykO$80g9+ zet2{x@bKZoCXfVyksq{5Iy%D?|7w{yuq@9>6|IJcX)^^t(eeH1_>RreSPQ6H>o(qKnlM@fq>kh&`cCs2*i;B_eWJB zs*fHy81vCG(UM{ulDUDxiD_|{$)aMkG@zQDl)6JfL6JnorDbji!cTwd+pzY93{XXR zbqy25^{9q~grJ4rWF+B%GESbEnVCFQ9#NH1T&$Tmi>IchR^fm60)#$xlg`rYmn0-4 zS!y3?M?jUpBW2wEi=cY=r#cd4iP)-C*1KmWm` z*-KqdPZ1w)Z+O?PaqLFRT_=QJO|hWt7jk=%+`2>fme!vn3yVvqd>uex<%8h%Jub( ztHd@BKmTlb@bwi8WNq|k^Uk56n2U>x8e62b_i>tk`@7pdAVFTWu1^%kf$I`n6ctmt zUMm6IL4AC_(Hcf<8+6)d#R;Bz8e#$h>t?7D%i20y%N8h*FTaN4%BNiMH`dpK0zn+@ z(n^t{;27P$37kDWCWOaLyl`XBs#L9*bSOWqs;H2g93B=bEh%viP*G8F0{K2zPmk&e z1VejQ52!9PEtU*ly$l{~wzIcayQ5pvzHkE!j-MN62bTv>ia#k3m>#(@0B84i!m9dt z-sd1B2Y-Lg1o+lnQVuf*1O!mK{hEp>Pipn!xx87PkU+Q55Mwzg&q+$mRd04>tHa>lw* z-~lLLCiH%^mJEuh0)5E{FK&SA9Vvq+tjG5~8S^t)lGVpPKH>)Y`rOkJQc@>1y&fqK zAyUFl!x^PtT#ZakKg2+G1kaDQ^cvi(t*x6r==#6KgWu=l+qB4;X*!-mJm7@L>(X$vj{c@&ii>#Ce1FNgA$98D1(j_Oq$kSxs%ZU4p=qdqEnjJ)6F={AN`}+V#lx_V#+P z4sj}a`0S9v4}Z=1nV#O$d~!`eSS+Z8WTqD2=%WezgN@#=yq@4E-SRZzv1P3%wy=z7 za&N$fJR`5CxA#M2WMswhp>n!}TXMkF#pz5j+i<2l;;38Y9qHPBT<~O(2@TkOw>T^Y z2>dIu_jlUK1rHAox5ln{`S`xQc|+j8+d-HAB+p8$AebOQqe)2~W9 zp0A|{gBka0)*%ZxM~`>`i!;Q!?fE=Y`4nHN@sEcJU>)h$%2+83`qt(Up4#t-ayYaVdL0O9t_?DNqvJJ|S zszUc6YatytT!@gExPF~eITMF-f8p-#yEc{D?;y%=)f6xQrrbIBR8$@G*z8W@&{B+I zQ@fqW;YRVjPA|tDOzSMDYlA)@0*@p%A#yf`CFV&C)YRkcjjKY_iC|SB8Wd^H=nYCj zOlMDje~N_1;?GC8j`s_Uu-HH2z($Y5Q4c#@2EIf|dbW2Ww;G)O2*j#|PYXb2pqK!D;oxaal!v{CJ)o9v+?&Y#H|Kmk!__ z|MjbQQ&ZE`6j+H&q7yI=zg$LvPNsK?i-{rc=<2d!Q3yEs1*X%}g@pyPV#5ssoOua| zT@K|_L={z4gRX9Fjm_EFY@P1a#L`UBK>aMP3#^-hr1ndLQxBDpU<3wQ1s4g_t;>sx zCNSX^{le)n{;ltxh_n71l>I;O*}ui%|9y-rmIVtw4{NgaF|b$;z|^!{s%)Q BE`0z1 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/256x256@2/apps/mate-hud.png b/usr/share/icons/hicolor/256x256@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..53492c8ac4a4a93d1fb1209f8145696c67f4c358 GIT binary patch literal 12729 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 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/32x32/apps/mate-hud.png b/usr/share/icons/hicolor/32x32/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..e850e582a9f95e0ae689460104ee054983b1ad87 GIT binary patch literal 905 zcmV;419tq0P)Sze(COCKX#5y9^JyY9|hcMFxt)4Np3pM`^7d1sUkE;3aQP(%UZm z3#6>NgW`{q2NCJP!(0yo1sx0q8|<>$HYEv3-(9AxU4Oi-4*kM&NS^0?o=@^VZ}M=I zQrxBZJFR{n09>^knx^r(uD@^`r;9n6%k@K+-6*#larH=B}qC2Fj(gNdp}lI zR-U59o^Eb#(wiumOj1dbC?Q1tyC(A+2n3%Xx|KoRVn5gUZdnV4dY#sTz0Jp z)ejdlfY-%g>3KJ@&zQf=*J^X|cv$#;GXMY>?|y)zqa&E6*)Vo^co>SJTwiB0w*a8) zI^yv-6Ts@~Du#xJ8pbsRpePD&48>3@pp48y5@)nRAu_h@$vak|Y?0Q8ic)1WZp)Gbe8vKvmVk$;rv5?d|QsYQc`< zAel_o1Oxz46cG-G;qiEy2LOOjDD=`WjF0>K`+>@l-84-cA0OB40iNeEH8s^bz@Pth zZ!8vjmCa_~tb(6q=d?^7%YnTU(>;?d^1aem+&1 zn+bpr!bhXg%~l82&dyG!T5(D#xXMPWCr#7%VzD@8+x8>YHG&{~QxxS$Rn<~8e^UVe fLwEi!xO0Htsl|`-PKBG_00000NkvXXu0mjfwxpuD literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/32x32@2/apps/mate-hud.png b/usr/share/icons/hicolor/32x32@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..f382911e3618099cdc8c6d8a135cb7c4f71424af GIT binary patch literal 1610 zcmV-Q2DSN#P)y<$}K={EE^!V0J*VjfZPJ)#*#N6XE7%=H#fiM_xnEy zhr@>H>1j1>Q2@YkTv)AEdvrS8_a{!A_*IHF004xLl%u}BzR7Ghk24HI0AwvpCey^h zg9lsF(VA+cbdVqjN}J90TQ-x97v<&Ue+h!1%eny-6&3g8PX1Yxm6birssZ)&^`FU| z^!%u;t#xM20E@-qlRM%0VKf@WtQa5&LIKBdvL_rbnwpx-Gz>^M4+sW>=4dpU=n&Z; zied>3o`my&SS+Ta(TEhddi84O&6_vB;y5mrpPwJ(dH%k^VEDSdz5QZ3Jd2tLy$l!} z98>~O&iu^-@CL&$J9>J0{@uQPdqqo2%iUCXBsE~=%9Yr;b0>J7heDx{q>V@<0*}Xo zTeoh(=kuYvyL(lCf4_TbYRcBu)^beS_wL<4Cd!XUVL*9#dG@oOgIFv^ zii?X008&&`G$jZE8!xwKLA?f4S64s1wEzSo*&RYPIV?Dqf!%J0+wI1qM~`yC;qW^E zeqZPu>IU#U4*+O!{fRqXKW+NNZRe@c@xi+&Dk_@Y7KudGBY^?bUx+XagP|v(tS1iu z-iZ);ynZkYGk0^si!8}7IOrDv0EEOaeCH=jPX?*-=dD_U*Vmik?i=ulVB+qH4@nFV zr=H&Xfxr9l$9LaS=Vuj4lzx6T?!Mqu6nSZINn${r@+ob;VIAK3a1W+KlzRZbX2E^= zN)99qE=denw;~q+z;ZcQy`xHsCKkloD{|4F#_^IEP@q+!a$Ny_{%1@I`UUZ(UW@nn z*W@<<01lKGaG=B>6+Ja9uM0>?9*suP(b0j?(NSugcDo%`tCbp`qz3f%_TuQ#qf|NF zZZ~e+xIv9iQUfd&3(lN5gRwDs#jvunk{TBvu>ma0V*mdAQZ|t>mV6OhHb8CxazoM@ z5R1id<;oQ*!=P5HMRj#GG#U*BW&cA`1G>7pX5SFe!06~G4jno~jSrC6fX$mXqpq%w z$}p(WXs~P7E()riM=}GZGa=XO_2}&E%!ER6BrJkTr81odt5*^U4N$364+;wlGwKB| zI}#e;a5!Sywr%?*TVmuu(jvHVQ;zJ2@TF#rJC+S;xw z6pG^R?(SwkXTR^=yGMgEBlPw40RT9TgI23`CpK7E=P42IbcHEcH9-Bffl zB*h^u6&yc)T<3DRdb_&1o*S?=8V%HHNxrJbS#2olA;Zc<3x={ zW z|Kt84SeC^@26^8EgyK=aedECkC@R#^YPCL($K#DG%Thv%QWO;}EiL`d>2w|m%>|Za zbDG6sd0ACebq#l}hP^(czB0y}jzLuC6_bqHg4Jc|fbxzI40Yukr?F>MN_&+KT_F|8rS$ zb8~QFVxlhB94L4n$Of9GF+4nswzf9t^?Hz`u)Q%7iC}ws8*aB7Uawah4u`i%lB~2l2{$nsAzgLt?X}qXaqoJVzKA(?>$K#Cv-rV*RBtRmO;G6vrmi@;< z(qzT6av7vjDFA?Bn6gYhf+z8>=kLJWT;sRzUm=ya;+KRVp!@haWKXpJdVFyHE^nw{ z0SwC`8Nb3GyFVd$b;&CSK~X5LZ~Bh_rhu*#ETB>@#V>LNJ{;$D637XiT$0yEumE$t z8j-{el7;+S9PmU&qe(5#>nB)1l|qWonrnro;SIq8fWP*V#l=NLA`#B91VO-LGC`}= z=6B8jQ3M#Rg3V^*6)TDWwOWmEIE-jC$~l%KNmN%?^R6w5002;_ zR8Xl@Vx=n>5B^%^Q2+oO92`I?oDW2l2;2#u1pFp1$7P+}v7PTKb^SL|0c=h{xlc zikFp@fue+6wPu|Ijg5`w{r&y7e!oBOkuVqx;_1_;NF)-Rikr=5csw3XF}IObfYa$b zVi=}reSQ5$uh*ONpi)s$f%*A)oSmInI@-Umu<%7R8YSxM>(ScUD(G08Ml2SC&*#I+ z$_kRnBupmL?(*{T`&k3{v{2e?Hd~9)Xgn$|E*AY_x2C4%dSGDS^L!k5kH9}MIXS6| z#bPf~sgy!+GT=rgll?q9JNrW+&Y}poPdvU4+&3Nt+&BIN>5!ucpsW;#00000NkvXX Hu0mjfLgqhu literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/48x48@2/apps/mate-hud.png b/usr/share/icons/hicolor/48x48@2/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..e72bdcbc8a64f743f2419089add556a8f155879a GIT binary patch literal 2348 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 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/64x64/apps/mate-hud.png b/usr/share/icons/hicolor/64x64/apps/mate-hud.png new file mode 100644 index 0000000000000000000000000000000000000000..f382911e3618099cdc8c6d8a135cb7c4f71424af GIT binary patch literal 1610 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 literal 0 HcmV?d00001 diff --git a/usr/share/icons/hicolor/scalable/apps/mate-hud.svg b/usr/share/icons/hicolor/scalable/apps/mate-hud.svg new file mode 100644 index 0000000..bd64dfb --- /dev/null +++ b/usr/share/icons/hicolor/scalable/apps/mate-hud.svg @@ -0,0 +1,74 @@ + + diff --git a/usr/share/pixmaps/mate-hud.svg b/usr/share/pixmaps/mate-hud.svg new file mode 100644 index 0000000..bd64dfb --- /dev/null +++ b/usr/share/pixmaps/mate-hud.svg @@ -0,0 +1,74 @@ + +