pyprland
pyprland copied to clipboard
[FEAT] [Scratchpads] Fully unmanaged scratchpads (eg: no command given)
Check #118 for the details.
Proposition:
- enabled when no
commandis provided - requires
match_by="class"(for performance reasons, to not query clients on each new window)
@kuba-gaj can you provide some feedback testing the latest git version ?
If you also want less automatic changes on the style you can may try preserve_aspect=true.
Note: match_by="class" will be forced, for performance reasons there is no other matching type when no command is provided.
thank you for the update,
I started testing it with one scratchpad like this:
[scratchpads.onepass]
animation = "fromBottom"
class = "1Password"
preserve_aspect = true
And I start the app myself with some initial rules:
exec-once=sleep 1 && 1password
windowrulev2 = float, class:^(1Password)$
windowrulev2 = pin, class:^(1Password)$
windowrulev2 = focusonactivate 1, class:^(1Password)$
It seems to kind of work.
- 1pass app starts and is visible
- First call to
togglejust moves the app down and keeps it visible - Subsequent calls to
togglework as expected
I think preferably I would like to be able to control if the scratchpad starts visible or not and not have an extra call to toggle that is currently required.
It also looks like preserve_aspect isn't really working at the moment.
It just occurred to me that maybe I could script running toggle after starting the app:
- one time to keep it visible and ready for toggling
- twice to have it ready for toggling and not visible
Ok so there is another small issue.
Steps:
- onepass app started, visible
- pyprland service started
- run
toggle- as mentioned above looks like first visibility check is failing and it just moves the visible window without hiding it - run
toggle- working fine but error message shows? why is that? how to disable it - after that multiple
togglesseem to be working as expected
Jul 20 13:07:26 arch pypr[8184]: scratchpads - run_toggle('onepass',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: scratchpads - visibility_check: ('', '') == ('2', 'DP-3') // __init__.py:456
Jul 20 13:07:26 arch pypr[8184]: scratchpads - onepass visibility: False and False // __init__.py:482
Jul 20 13:07:26 arch pypr[8184]: scratchpads - Showing onepass // __init__.py:559
Jul 20 13:07:26 arch pypr[8184]: scratchpads - clients // ipc.py:101
Jul 20 13:07:26 arch pypr[8184]: scratchpads - dispatch movetoworkspacesilent special:scratch_onepass,address:0x606241923de0 // ipc.py:144
Jul 20 13:07:26 arch pypr[8184]: pyprland - event_activewindowv2('606241829d20',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: pyprland - active_window = 0x606241829d20 // pyprland.py:76
Jul 20 13:07:26 arch pypr[8184]: scratchpads - monitors // ipc.py:101
Jul 20 13:07:26 arch pypr[8184]: scratchpads - clients (CACHE HIT) // ipc.py:98
Jul 20 13:07:26 arch pypr[8184]: scratchpads - dispatch ['moveworkspacetomonitor special:scratch_onepass DP-3', 'movetoworkspacesilent 2,address:0x606241923de0', 'alterzorder top,address:0x606241923de0'] // ipc.py:144
Jul 20 13:07:26 arch pypr[8184]: pyprland - event_activewindowv2('606241923de0',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: pyprland - active_window = 0x606241923de0 // pyprland.py:76
Jul 20 13:07:26 arch pypr[8184]: scratchpads - dispatch ['movewindowpixel exact 2160 780,address:0x606241923de0'] // ipc.py:144
Jul 20 13:07:26 arch pypr[8184]: scratchpads - dispatch focuswindow address:0x606241923de0 // ipc.py:144
Jul 20 13:07:26 arch pypr[8184]: pyprland - event_activewindowv2('606241923de0',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: pyprland - active_window = 0x606241923de0 // pyprland.py:76
Jul 20 13:07:26 arch pypr[8184]: scratchpads - event_activewindowv2('606241829d20',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: scratchpads - event_activewindowv2('606241923de0',) // command.py:202
Jul 20 13:07:26 arch pypr[8184]: scratchpads - event_activewindowv2('606241923de0',) // command.py:202
Jul 20 13:07:29 arch pypr[8184]: scratchpads - run_toggle('onepass',) // command.py:202
Jul 20 13:07:29 arch pypr[8184]: scratchpads - visibility_check: ('2', 'DP-3') == ('2', 'DP-3') // __init__.py:456
Jul 20 13:07:29 arch pypr[8184]: scratchpads - onepass visibility: True and True // __init__.py:482
Jul 20 13:07:29 arch pypr[8184]: scratchpads - clients // ipc.py:101
Jul 20 13:07:29 arch pypr[8184]: scratchpads - Hiding onepass // __init__.py:769
Jul 20 13:07:29 arch pypr[8184]: scratchpads - dispatch ['movewindowpixel 0 660,address:0x606241923de0'] // ipc.py:144
Jul 20 13:07:29 arch pypr[8184]: scratchpads - dispatch pin address:0x606241923de0 // ipc.py:144
Jul 20 13:07:29 arch pypr[8184]: scratchpads - dispatch movetoworkspacesilent special:scratch_onepass,address:0x606241923de0 // ipc.py:144
Jul 20 13:07:29 arch pypr[8184]: pyprland - event_activewindowv2('606241829d20',) // command.py:202
Jul 20 13:07:29 arch pypr[8184]: pyprland - active_window = 0x606241829d20 // pyprland.py:76
Jul 20 13:07:29 arch pypr[8184]: pypr - This could be a bug in Pyprland, if you think so, report on https://github.com/fdev31/pyprland/issues // command.py:210
Hmm, I think I got rid of above error by starting onepass after pyprland, or it's random atm :)
Now I toggled onepass a couple of times and killed the process.
When I run toggle I see error message (I would like not to as this is dummy mode without any tracking). What is even worse other scratchpad also stopped working:
Jul 20 13:36:18 arch pypr[8308]: scratchpads - run_toggle('onepass',) // command.py:202
Jul 20 13:36:18 arch pypr[8308]: scratchpads - visibility_check: ('2', 'DP-3') == ('2', 'DP-3') // __init__.py:456
Jul 20 13:36:18 arch pypr[8308]: scratchpads - onepass visibility: True and True // __init__.py:482
Jul 20 13:36:18 arch pypr[8308]: scratchpads - clients // ipc.py:101
Jul 20 13:36:18 arch pypr[8308]: ERROR:scratch:The client window 0x5574909ff800 vanished
Jul 20 13:36:18 arch pypr[8308]: pypr - scratchpads::run_toggle(('onepass',)) failed: // command.py:213
Jul 20 13:36:18 arch pypr[8308]: Traceback (most recent call last):
Jul 20 13:36:18 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/command.py", line 208, in _run_plugin_handler
Jul 20 13:36:18 arch pypr[8308]: await getattr(plugin, full_name)(*params)
Jul 20 13:36:18 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/__init__.py", line 487, in run_toggle
Jul 20 13:36:18 arch pypr[8308]: await asyncio.gather(*(asyncio.create_task(t()) for t in tasks))
Jul 20 13:36:18 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/__init__.py", line 755, in run_hide
Jul 20 13:36:18 arch pypr[8308]: await scratch.update_client_info(clients=clients)
Jul 20 13:36:18 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/objects.py", line 179, in update_client_info
Jul 20 13:36:18 arch pypr[8308]: raise KeyError(msg)
Jul 20 13:36:18 arch pypr[8308]: KeyError: 'Client window 0x5574909ff800 not found'
Jul 20 13:36:18 arch pypr[8308]: ipc - notify 0 5000 rgb(ff1010) Pypr error scratchpads::run_toggle: 'Client window 0x5574909ff800 not found' // ipc.py:144
Jul 20 13:36:33 arch pypr[10276]: [07/20/24, 13:36:33:387] info: [DND_V2] (T033J3T2Y) Checking for changes in DND status for the following members: U014H9J7CUD
Jul 20 13:36:33 arch pypr[10276]: [07/20/24, 13:36:33:388] info: [DND_V2] (T033J3T2Y) Will check for changes in DND status again in 5 minutes
Jul 20 13:36:39 arch pypr[8308]: pyprland - event_activewindowv2('55749097e450',) // command.py:202
Jul 20 13:36:39 arch pypr[8308]: pyprland - active_window = 0x55749097e450 // pyprland.py:76
Jul 20 13:36:39 arch pypr[8308]: scratchpads - event_activewindowv2('55749097e450',) // command.py:202
Jul 20 13:38:40 arch pypr[8308]: scratchpads - run_toggle('dropterm',) // command.py:202
Jul 20 13:38:40 arch pypr[8308]: scratchpads - visibility_check: ('2', 'DP-3') == ('2', 'DP-3') // __init__.py:456
Jul 20 13:38:40 arch pypr[8308]: scratchpads - dropterm visibility: False and False // __init__.py:482
Jul 20 13:38:40 arch pypr[8308]: scratchpads - Showing dropterm // __init__.py:559
Jul 20 13:38:40 arch pypr[8308]: scratchpads - keyword windowrule unset,^(term-drop)$ // ipc.py:144
Jul 20 13:38:40 arch pypr[8308]: scratchpads - clients // ipc.py:101
Jul 20 13:38:40 arch pypr[8308]: ERROR:scratch:The client window 0x5574909ff800 vanished
Jul 20 13:38:40 arch pypr[8308]: pypr - scratchpads::run_toggle(('dropterm',)) failed: // command.py:213
Jul 20 13:38:40 arch pypr[8308]: Traceback (most recent call last):
Jul 20 13:38:40 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/command.py", line 208, in _run_plugin_handler
Jul 20 13:38:40 arch pypr[8308]: await getattr(plugin, full_name)(*params)
Jul 20 13:38:40 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/__init__.py", line 487, in run_toggle
Jul 20 13:38:40 arch pypr[8308]: await asyncio.gather(*(asyncio.create_task(t()) for t in tasks))
Jul 20 13:38:40 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/__init__.py", line 573, in run_show
Jul 20 13:38:40 arch pypr[8308]: await self.run_hide(e_uid, flavor=HideFlavors.TRIGGERED_BY_AUTOHIDE | HideFlavors.IGNORE_TILED)
Jul 20 13:38:40 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/__init__.py", line 755, in run_hide
Jul 20 13:38:40 arch pypr[8308]: await scratch.update_client_info(clients=clients)
Jul 20 13:38:40 arch pypr[8308]: File "/usr/lib/python3.12/site-packages/pyprland/plugins/scratchpads/objects.py", line 179, in update_client_info
Jul 20 13:38:40 arch pypr[8308]: raise KeyError(msg)
Jul 20 13:38:40 arch pypr[8308]: KeyError: 'Client window 0x5574909ff800 not found'
Jul 20 13:38:40 arch pypr[8308]: ipc - notify 0 5000 rgb(ff1010) Pypr error scratchpads::run_toggle: 'Client window 0x5574909ff800 not found' // ipc.py:144
Jul 20 13:39:27 arch pypr[8308]: pyprland - event_activewindowv2('5574909bec30',) // command.py:202
Jul 20 13:39:27 arch pypr[8308]: pyprland - active_window = 0x5574909bec30 // pyprland.py:76
hyprctl
Window 557490ac5f10 -> tmux:
mapped: 1
hidden: 0
at: 1600,-1296
size: 1920,1296
workspace: -93 (special:scratch_dropterm)
Then I started onepass again but pyprland is still in broken state (window not found)
In the first log, you stopped it exactly at the line which starts to explain the error, so I can't help without the details.
The relevant content (eg: class) has also been removed from your second log.
- Can you provide full logs and configuration files in use?
- Does it also behaves the same using another app?
- What makes you think preserve_aspect is broken?
Can I close this one?
hey - of course you can - it's your project! :D I think that without changing architecture to not track pids it will often have issues with some apps. It is not an easy topic and reimplementing part of systemd functionality doesn't make sense. In systemd service can be simple, exec, forking, oneshot, dbus, notify and idle - and i don't think that covers everything, especially the electron bootloaders. Can be done in a bit hacky way with wrapper script and sd_notify?
I gave up chasing the issues for months :) Recently switched to more robust uwsm from my own systemd scripts for session handling, then switched most of my service files to uwsm app (actually compatible app2unit) and in the last days I started experimenting with hyprscratch - much smaller focused binary with more basic functionality but without process tracking and I managed to set it up. I guess if anyone else loves scratchpads (I have 15 - really core to my workflow) and went all in with systemd it may be a valid option
Thank you for your work, kudos for creating and maintaining pyprland, and great support, help debugging issues and patience :)
Actually pyprland's scratchpads don't only match by pid, it's configurable. Check the "match_by" configuration option.
I know, i was using match_by pretty extensively, but it stil had some issues:
- it was creating startup dependency between pyprland and these apps
- when the window started first toggle call would only postion the window by
pyprlandinstead of hiding it - in the event of window being closed and new created
pyprlandwas erroring with errors about window id not being found, maybe some caching issues?