Skip to content

Commit

Permalink
Merge pull request #387 from RedBearAK/dev_beta
Browse files Browse the repository at this point in the history
Prep for more direct handling of WMs
  • Loading branch information
RedBearAK authored Sep 10, 2024
2 parents 8a90493 + 94d4fd3 commit 5689335
Show file tree
Hide file tree
Showing 13 changed files with 720 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ On the other hand, if you are in a Wayland session, it is only possible to obtai

For Wayland+GNOME this requires at least one of the known compatible GNOME Shell extensions to be installed and enabled. See above in [**Requirements**](#requirements). I do not maintain the GNOME shell extensions, and they frequently need to be updated for new GNOME releases.

There are specific remaps or overrides of default remaps for several common desktop environments (or distros which have shortcut peculiarities in their default desktop setups). They become active if the desktop environment is detected correctly by the `env.py` environment evaluation module used by the config file. If that isn't working for some reason, the information about the desktop environment can be placed in some `OVERRIDE` variables in the config file. But open an issue if that seems to be necessary.
There are specific remaps or overrides of default remaps for several common desktop environments (or distros which have shortcut peculiarities in their default desktop setups). They become active if the desktop environment is detected correctly by the environment evaluation module used by the config file. If that isn't working for some reason, the information about the desktop environment can be placed in some `OVERRIDE` variables in the config file. But open an issue if that seems to be necessary.

Tiling window managers may need [some adjustments](https://github.com/RedBearAK/toshy/issues/294). The example issue at the link is for i3 WM, with the physical `Meta/Super/Win` key chosen as the `Mod` key in i3 config, on a PC keyboard type. Other WMs or other configuration choices will need modifications of the solution shown.

Expand Down
18 changes: 11 additions & 7 deletions cosmic-dbus-service/toshy_cosmic_dbus_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
# local imports now that path is prepped
import lib.env as env

from lib.env_context import EnvironmentInfo

from protocols.cosmic_toplevel_info_unstable_v1.zcosmic_toplevel_info_v1 import (
ZcosmicToplevelInfoV1,
ZcosmicToplevelInfoV1Proxy,
Expand Down Expand Up @@ -113,14 +115,16 @@ def clean_shutdown():

def check_environment():
"""Retrieve the current environment from env module"""
env_info: Dict[str, str] = env.get_env_info() # Returns a dict
# env_info_dct = env.get_env_info()
env_ctxt_getter = EnvironmentInfo()
env_info_dct = env_ctxt_getter.get_env_info()
global DISTRO_ID, DISTRO_VER, VARIANT_ID, SESSION_TYPE, DESKTOP_ENV, DE_MAJ_VER
DISTRO_ID = env_info.get('DISTRO_ID', 'keymissing')
DISTRO_VER = env_info.get('DISTRO_VER', 'keymissing')
VARIANT_ID = env_info.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = env_info.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = env_info.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = env_info.get('DE_MAJ_VER', 'keymissing')
DISTRO_ID = env_info_dct.get('DISTRO_ID', 'keymissing')
DISTRO_VER = env_info_dct.get('DISTRO_VER', 'keymissing')
VARIANT_ID = env_info_dct.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = env_info_dct.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = env_info_dct.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = env_info_dct.get('DE_MAJ_VER', 'keymissing')


check_environment()
Expand Down
29 changes: 29 additions & 0 deletions default-toshy-config/DO_NOT_EDIT_THESE_FILES_README
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
DO NOT EDIT THE FILES IN THIS FOLDER


The files in this folder are meant to be "clean" copies of the
default Toshy configuration files, to be used by the installer
or copied by the user into the parent folder in case there is
a major problem with the user's `toshy_config.py` config file.



The user's editable config file is located here in the parent folder:

~/.config/toshy/toshy_config.py



To replace your config file with a new default config:

mv ~/.config/toshy/toshy_config.py ~/.config/toshy/toshy_config.py.old
cp ~/.config/toshy/default-toshy-config/toshy_config.py ~/.config/toshy/toshy_config.py
toshy-services-restart



Or, if you were using the "barebones" config file:

mv ~/.config/toshy/toshy_config.py ~/.config/toshy/toshy_config.py.old
cp ~/.config/toshy/default-toshy-config/toshy_config_barebones.py ~/.config/toshy/toshy_config.py
toshy-services-restart
50 changes: 40 additions & 10 deletions default-toshy-config/toshy_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@
sys.path.insert(0, current_folder_path)

import lib.env

from lib.env_context import EnvironmentInfo
from lib.settings_class import Settings
from lib.notification_manager import NotificationManager

Expand All @@ -157,7 +159,7 @@
# Toshy config file
TOSHY_PART = 'config' # CUSTOMIZE TO SPECIFIC TOSHY COMPONENT! (gui, tray, config)
TOSHY_PART_NAME = 'Toshy Config file'
APP_VERSION = '2024.0804'
APP_VERSION = '2024.0904'

# Settings object used to tweak preferences "live" between gui, tray and config.
cnfg = Settings(current_folder_path)
Expand Down Expand Up @@ -191,6 +193,7 @@
OVERRIDE_SESSION_TYPE = None
OVERRIDE_DESKTOP_ENV = None
OVERRIDE_DE_MAJ_VER = None
OVERRIDE_WINDOW_MGR = None

wlroots_compositors = [
# Comma-separated list of Wayland desktop environments or window managers
Expand All @@ -204,46 +207,65 @@
### SLICE_MARK_END: env_overrides ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################

# leave all of this alone!
# Leave all of this alone! Don't try to override values here.
DISTRO_ID = None
DISTRO_VER = None
VARIANT_ID = None
SESSION_TYPE = None
DESKTOP_ENV = None
DE_MAJ_VER = None
WINDOW_MGR = None

# env_info: Dict[str, str] = lib.env.get_env_info()

# DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_info.get('DISTRO_ID', 'keymissing')
# DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_info.get('DISTRO_VER', 'keymissing')
# VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_info.get('VARIANT_ID', 'keymissing')
# SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_info.get('SESSION_TYPE', 'keymissing')
# DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_info.get('DESKTOP_ENV', 'keymissing')
# DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_info.get('DE_MAJ_VER', 'keymissing')

env_info: Dict[str, str] = lib.env.get_env_info()
env_ctxt_getter = EnvironmentInfo()
env_ctxt: Dict[str, str] = env_ctxt_getter.get_env_info()

DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_info.get('DISTRO_ID', 'keymissing')
DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_info.get('DISTRO_VER', 'keymissing')
VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_info.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_info.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_info.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_info.get('DE_MAJ_VER', 'keymissing')
DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_ctxt.get('DISTRO_ID', 'keymissing')
DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_ctxt.get('DISTRO_VER', 'keymissing')
VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_ctxt.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_ctxt.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_ctxt.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_ctxt.get('DE_MAJ_VER', 'keymissing')
WINDOW_MGR = locals().get('OVERRIDE_WINDOW_MGR') or env_ctxt.get('WINDOW_MGR', 'keymissing')

debug("")
debug( f'Toshy config sees this environment:'
f'\n\t{DISTRO_ID = }'
f'\n\t{DISTRO_VER = }'
f'\n\t{VARIANT_ID = }'
f'\n\t{SESSION_TYPE = }'
f'\n\t{DESKTOP_ENV = }'
f'\n\t{DE_MAJ_VER = }\n', ctx="CG")
f'\n\t{DE_MAJ_VER = }'
f'\n\t{WINDOW_MGR = }\n', ctx="CG")


# TODO: Add a list here to concat with 'wlroots_compositors', instead of
# continuing to add new environments into the 'wlroots' provider inside
# the keymapper.
known_wlroots_compositors = [
'hyprland',
'labwc', # untested but should work
'niri',
'qtile',
'river', # untested but should work
'sway',
'wayfire', # untested but should work
]

# Make sure the 'wlroots_compositors' list variable exists before checking it.
# Older config files won't have it in the 'env_overrides' slice.
wlroots_compositors = locals().get('wlroots_compositors', [])

all_wlroots_compositors = known_wlroots_compositors + wlroots_compositors

# Direct the keymapper to try to use `wlroots` window context for
# all DEs/WMs in user list, if list is not empty.
if wlroots_compositors and DESKTOP_ENV in wlroots_compositors:
Expand All @@ -253,6 +275,13 @@
elif DESKTOP_ENV in known_wlroots_compositors:
debug(f"DE/WM '{DESKTOP_ENV}' is in known 'wlroots' compositor list.", ctx="CG")
_desktop_env = 'wlroots'
elif (SESSION_TYPE, DESKTOP_ENV) == ('wayland', 'lxqt') and WINDOW_MGR == 'kwin_wayland':
# The Toshy KWin script must be installed in the LXQt/KWin environment for this to work!
debug(f"DE is LXQt, WM is '{WINDOW_MGR}', using 'kde' window context method.", ctx="CG")
_desktop_env = 'kde'
elif (SESSION_TYPE, DESKTOP_ENV) == ('wayland', 'lxqt') and WINDOW_MGR in all_wlroots_compositors:
debug(f"DE is LXQt, WM is '{WINDOW_MGR}', using 'wlroots' window context method.", ctx="CG")
_desktop_env = 'wlroots'
else:
_desktop_env = DESKTOP_ENV

Expand Down Expand Up @@ -1250,6 +1279,7 @@ def escape_markup(text: str):
f"<b> • SESSION_TYPE _________</b> '{SESSION_TYPE }' {nwln_str}"
f"<b> • DESKTOP_ENV __________</b> '{DESKTOP_ENV }' {nwln_str}"
f"<b> • DE_MAJ_VER ___________</b> '{DE_MAJ_VER }' {nwln_str}"
f"<b> • WINDOW_MGR ___________</b> '{WINDOW_MGR }' {nwln_str}"
f"{nwln_str}"
f"<b>Do any app class groups match on this window?:</b> {nwln_str}"
f"<b> • Terminals ____________</b> '{ctx_term}' {nwln_str}"
Expand Down
79 changes: 59 additions & 20 deletions default-toshy-config/toshy_config_barebones.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
sys.path.insert(0, current_folder_path)

import lib.env

from lib.env_context import EnvironmentInfo
from lib.settings_class import Settings
from lib.notification_manager import NotificationManager

Expand All @@ -87,7 +89,7 @@
# Toshy config file
TOSHY_PART = 'config' # CUSTOMIZE TO SPECIFIC TOSHY COMPONENT! (gui, tray, config)
TOSHY_PART_NAME = 'Toshy Barebones Config'
APP_VERSION = '2024.0801'
APP_VERSION = '2024.0904'

# Settings object used to tweak preferences "live" between gui, tray and config.
cnfg = Settings(current_folder_path)
Expand Down Expand Up @@ -121,6 +123,7 @@
OVERRIDE_SESSION_TYPE = None
OVERRIDE_DESKTOP_ENV = None
OVERRIDE_DE_MAJ_VER = None
OVERRIDE_WINDOW_MGR = None

wlroots_compositors = [
# Comma-separated list of Wayland desktop environments or window managers
Expand All @@ -134,30 +137,44 @@
### SLICE_MARK_END: env_overrides ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################

# leave all of this alone!
# Leave all of this alone! Don't try to override values here.
DISTRO_ID = None
DISTRO_VER = None
VARIANT_ID = None
SESSION_TYPE = None
DESKTOP_ENV = None
DE_MAJ_VER = None
WINDOW_MGR = None

# env_info: Dict[str, str] = lib.env.get_env_info()

# DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_info.get('DISTRO_ID', 'keymissing')
# DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_info.get('DISTRO_VER', 'keymissing')
# VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_info.get('VARIANT_ID', 'keymissing')
# SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_info.get('SESSION_TYPE', 'keymissing')
# DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_info.get('DESKTOP_ENV', 'keymissing')
# DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_info.get('DE_MAJ_VER', 'keymissing')

env_info: Dict[str, str] = lib.env.get_env_info()
env_ctxt_getter = EnvironmentInfo()
env_ctxt: Dict[str, str] = env_ctxt_getter.get_env_info()

DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_info.get('DISTRO_ID', 'keymissing')
DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_info.get('DISTRO_VER', 'keymissing')
VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_info.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_info.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_info.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_info.get('DE_MAJ_VER', 'keymissing')
DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_ctxt.get('DISTRO_ID', 'keymissing')
DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_ctxt.get('DISTRO_VER', 'keymissing')
VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_ctxt.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_ctxt.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_ctxt.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_ctxt.get('DE_MAJ_VER', 'keymissing')
WINDOW_MGR = locals().get('OVERRIDE_WINDOW_MGR') or env_ctxt.get('WINDOW_MGR', 'keymissing')

debug("")
debug( f'Toshy (barebones) config sees this environment:'
f'\n\t{DISTRO_ID = }'
f'\n\t{DISTRO_VER = }'
f'\n\t{VARIANT_ID = }'
f'\n\t{SESSION_TYPE = }'
f'\n\t{DESKTOP_ENV = }'
f'\n\t{DE_MAJ_VER = }\n', ctx="CG")
f'\n\t{DE_MAJ_VER = }'
f'\n\t{WINDOW_MGR = }\n', ctx="CG")


# TODO: Add a list here to concat with 'wlroots_compositors', instead of
Expand Down Expand Up @@ -209,7 +226,7 @@
# Establish important global variables here


startup_timestamp = time.time() # only gets evaluated once for each run of keymapper
STARTUP_TIMESTAMP = time.time() # only gets evaluated once for each run of keymapper

# Variable to hold the keyboard type
KBTYPE = None
Expand Down Expand Up @@ -542,6 +559,11 @@ def _isDoubleTap():
return _isDoubleTap


total_matchProps_iterations = 0
MAX_MATCHPROPS_ITERATIONS = 1000
MAX_MATCHPROPS_ITERATIONS_REACHED = False


# Correct syntax to reject all positional parameters: put `*,` at beginning
def matchProps(*,
# string parameters (positive matching)
Expand Down Expand Up @@ -605,15 +627,31 @@ def matchProps(*,
# https://stackoverflow.com/questions/406230/\
# regular-expression-to-match-a-line-that-doesnt-contain-a-word

logging_enabled = False
global MAX_MATCHPROPS_ITERATIONS_REACHED
global total_matchProps_iterations

# Return `False` immediately if screen does not have focus (e.g. Synergy),
# but only after the guard clauses have had a chance to evaluate on
# all possible uses of the function that may exist in the config.
if MAX_MATCHPROPS_ITERATIONS_REACHED and not cnfg.screen_has_focus:
return False

if total_matchProps_iterations >= MAX_MATCHPROPS_ITERATIONS:
MAX_MATCHPROPS_ITERATIONS_REACHED = True
bypass_guard_clauses = True
else:
total_matchProps_iterations += 1
current_timestamp = time.time()

current_timestamp = time.time()
time_elapsed = current_timestamp - startup_timestamp
# 'STARTUP_TIMESTAMP' is a global variable, set when config is executed
time_elapsed = current_timestamp - STARTUP_TIMESTAMP

# Bypass all guard clauses if more than a few seconds have passed since keymapper
# started and loaded the config file. Inputs never change until keymapper
# restarts and reloads the config file, so we don't need to keep checking.
bypass_guard_clauses = time_elapsed > 6
# Bypass all guard clauses if more than a few seconds have passed since keymapper
# started and loaded the config file. Inputs never change until keymapper
# restarts and reloads the config file, so we don't need to keep checking.
bypass_guard_clauses = time_elapsed > 6

logging_enabled = False

allowed_params = (clas, name, devn, not_clas, not_name, not_devn,
numlk, capslk, cse, lst, not_lst, dbg)
Expand All @@ -633,7 +671,7 @@ def matchProps(*,
'numlk', 'capslk', 'cse', 'lst', 'not_lst', 'dbg'
]

if not bypass_guard_clauses:
if not MAX_MATCHPROPS_ITERATIONS_REACHED or not bypass_guard_clauses:
if all([x is None for x in allowed_params]):
raise ValueError(f"\n\n(EE) matchProps(): Received no valid argument\n")
if any([x not in (True, False, None) for x in (numlk, capslk, cse)]):
Expand All @@ -655,7 +693,7 @@ def matchProps(*,
# process lists of conditions
if _lst is not None:

if not bypass_guard_clauses:
if not MAX_MATCHPROPS_ITERATIONS_REACHED or not bypass_guard_clauses:
if any([x is not None for x in lst_dct_params]):
raise TypeError(f"\n\n(EE) matchProps(): Param 'lst|not_lst' must be used alone\n")
if not isinstance(_lst, list) or not all(isinstance(item, dict) for item in _lst):
Expand Down Expand Up @@ -871,6 +909,7 @@ def escape_markup(text: str):
f"<b> • SESSION_TYPE _________</b> '{SESSION_TYPE }' {nwln_str}"
f"<b> • DESKTOP_ENV __________</b> '{DESKTOP_ENV }' {nwln_str}"
f"<b> • DE_MAJ_VER ___________</b> '{DE_MAJ_VER }' {nwln_str}"
f"<b> • WINDOW_MGR ___________</b> '{WINDOW_MGR }' {nwln_str}"
f"{nwln_str}"
f"<b> __________________________________________________ </b>{nwln_str}"
f"<i>Keyboard shortcuts (Ctrl+C/Cmd+C) may not work here.</i>{nwln_str}"
Expand Down
18 changes: 11 additions & 7 deletions kde-kwin-dbus-service/toshy_kde_dbus_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
# local imports now that path is prepped
import lib.env as env

from lib.env_context import EnvironmentInfo

if os.name == 'posix' and os.geteuid() == 0:
error("This app should not be run as root/superuser.")
sys.exit(1)
Expand Down Expand Up @@ -72,14 +74,16 @@ def signal_handler(sig, frame):

def check_environment():
"""Retrieve the current environment from env module"""
env_info: Dict[str, str] = env.get_env_info() # Returns a dict
# env_info_dct = env.get_env_info()
env_ctxt_getter = EnvironmentInfo()
env_info_dct = env_ctxt_getter.get_env_info()
global DISTRO_ID, DISTRO_VER, VARIANT_ID, SESSION_TYPE, DESKTOP_ENV, DE_MAJ_VER
DISTRO_ID = env_info.get('DISTRO_ID', 'keymissing')
DISTRO_VER = env_info.get('DISTRO_VER', 'keymissing')
VARIANT_ID = env_info.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = env_info.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = env_info.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = env_info.get('DE_MAJ_VER', 'keymissing')
DISTRO_ID = env_info_dct.get('DISTRO_ID', 'keymissing')
DISTRO_VER = env_info_dct.get('DISTRO_VER', 'keymissing')
VARIANT_ID = env_info_dct.get('VARIANT_ID', 'keymissing')
SESSION_TYPE = env_info_dct.get('SESSION_TYPE', 'keymissing')
DESKTOP_ENV = env_info_dct.get('DESKTOP_ENV', 'keymissing')
DE_MAJ_VER = env_info_dct.get('DE_MAJ_VER', 'keymissing')


check_environment()
Expand Down
Loading

0 comments on commit 5689335

Please sign in to comment.