Skip to content

Commit 9617880

Browse files
committed
scratchpads: improve and optimize the show flow
1 parent 4ebf005 commit 9617880

File tree

7 files changed

+33
-31
lines changed

7 files changed

+33
-31
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
- avoid logging when no flag is passed (only most important logs remains, use `--debug` to get the logs)
2-
- `scratchpads`: Fix initial display
3-
- add `show_delay` option to control the pre-show positioning delay
4-
- set to `0` to have no forced delay on first display (but leads to unpredictable animations)
5-
- needs to match your animations speed! Increase/decrease accordingly (default = 0.3s)
2+
- `scratchpads`: Fix initial display and remove some old workaround
3+
- fix some async operations usage
64
- misc fixes and improvements

pyprland/plugins/scratchpads/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ async def on_reload(self, reason: ReloadReason = ReloadReason.RELOAD) -> None:
158158
if not is_lazy:
159159
scratches_to_spawn.add(name)
160160

161+
# Register a noanim windowrule for the pypr_noanim tag.
162+
# This is used to skip Hyprland's window animation during offscreen pre-positioning
163+
# so that the show transition is instant (no need for show_delay).
164+
await self.backend.execute("windowrule no_anim on, match:tag pypr_noanim", base_command="keyword")
165+
161166
for name in scratches_to_spawn:
162167
if await self.ensure_alive(name):
163168
scratch = self.scratches.get(name)

pyprland/plugins/scratchpads/objects.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ async def initialize(self, ex: "_scratchpads_extension_m.Extension") -> None:
165165
raise RuntimeError(msg)
166166
self.client_info = m_client
167167
await ex.backend.execute(f"movetoworkspacesilent {mk_scratch_name(self.uid)},address:{self.full_address}")
168-
await asyncio.sleep(0.05) # workaround
169168
self.meta.initialized = True
170169

171170
async def is_alive(self) -> bool:

pyprland/plugins/scratchpads/schema.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ def _validate_animation(value: str) -> list[str]:
6565
ConfigField("restore_excluded", bool, default=False, description="Restore excluded on hide", category="behavior"),
6666
ConfigField("preserve_aspect", bool, default=False, description="Keep size/position across shows", category="behavior"),
6767
ConfigField("hide_delay", float, default=0.0, description="Delay before hide animation", category="behavior"),
68-
ConfigField("show_delay", float, default=0.3, description="Delay before show animation on first display", category="behavior"),
6968
ConfigField("force_monitor", str, default="", description="Always show on specific monitor", category="behavior"),
7069
ConfigField("alt_toggle", bool, default=False, description="Alternative toggle for multi-monitor", category="behavior"),
7170
ConfigField(

pyprland/plugins/scratchpads/transitions.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -168,18 +168,24 @@ async def _show_transition(self, scratch: Scratch, monitor: MonitorInfo, was_ali
168168
await self._handle_multiwindow(scratch, clients)
169169

170170
# FIX: initial animation
171-
if needs_offscreen_preposition:
172-
await self._update_infos(scratch, clients)
173-
174-
if scratch.client_info is not None and "size" in scratch.client_info:
175-
off_x, off_y = Placement.get_offscreen(
176-
animation_type,
177-
monitor,
178-
scratch.client_info,
179-
scratch.conf.get_int("margin"),
180-
)
181-
await self.backend.execute(f"movewindowpixel exact {off_x} {off_y},address:{scratch.full_address}")
182-
await asyncio.sleep(scratch.conf.get_float("show_delay"))
171+
# Tag the window with pypr_noanim to disable Hyprland's animation
172+
# during the offscreen pre-positioning move, then untag so the real
173+
# slide-in animation plays normally.
174+
if needs_offscreen_preposition and scratch.client_info is not None and "size" in scratch.client_info:
175+
off_x, off_y = Placement.get_offscreen(
176+
animation_type,
177+
monitor,
178+
scratch.client_info,
179+
scratch.conf.get_int("margin"),
180+
)
181+
await self.backend.execute(
182+
[
183+
f"tagwindow +pypr_noanim address:{scratch.full_address}",
184+
f"movewindowpixel exact {off_x} {off_y},address:{scratch.full_address}",
185+
]
186+
)
187+
await asyncio.sleep(0.001) # NOTE: let some time to process
188+
await self.backend.execute(f"tagwindow -pypr_noanim address:{scratch.full_address}")
183189

184190
# move
185191
move_commands: list[str] = []

site/scratchpads.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ Check your window's class with: `hyprctl clients | grep class`
8484

8585
Type of animation to use:
8686

87-
- `null` / `""` (no animation)
88-
- `fromTop` (stays close to upper screen border)
89-
- `fromBottom` (stays close to lower screen border)
90-
- `fromLeft` (stays close to left screen border)
91-
- `fromRight` (stays close to right screen border)
87+
- `fromTop` (default) stays close to upper screen border
88+
- `fromBottom` stays close to lower screen border
89+
- `fromLeft` stays close to left screen border
90+
- `fromRight` stays close to right screen border
91+
- `null` / `""` no sliding animation - also disables positioning relative to the border
92+
93+
It is recommended to set [position](#config-position) when disabling this configuration option.
9294

9395
### `size` <ConfigBadges plugin="scratchpads" option="size" /> {#config-size}
9496

site/scratchpads_advanced.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
Advanced configuration options
99

10-
<PluginConfig plugin="scratchpads" linkPrefix="config-" :filter="['use', 'pinned', 'excludes', 'restore_excluded', 'unfocus', 'hysteresis', 'preserve_aspect', 'offset', 'hide_delay', 'show_delay', 'force_monitor', 'alt_toggle', 'allow_special_workspaces', 'smart_focus', 'close_on_hide', 'monitor']" />
10+
<PluginConfig plugin="scratchpads" linkPrefix="config-" :filter="['use', 'pinned', 'excludes', 'restore_excluded', 'unfocus', 'hysteresis', 'preserve_aspect', 'offset', 'hide_delay', 'force_monitor', 'alt_toggle', 'allow_special_workspaces', 'smart_focus', 'close_on_hide', 'monitor']" />
1111

1212
### `use` <ConfigBadges plugin="scratchpads" option="use" /> {#config-use}
1313

@@ -78,13 +78,6 @@ Rule of thumb, if you have an animation with speed "7", as in:
7878
```
7979
You can divide the value by two and round to the lowest value, here `3`, then divide by 10, leading to `hide_delay = 0.3`.
8080

81-
### `show_delay` <ConfigBadges plugin="scratchpads" option="show_delay" /> {#config-show-delay}
82-
83-
Delay (in seconds) to wait for the initial positioning animation to complete before showing the scratchpad.
84-
This only affects the first time a scratchpad is displayed (or after its window is respawned) and when it moves across monitors.
85-
Increase the value if the scratchpad appears to slide diagonally on first show; decrease it for faster response.
86-
Set to `0` to disable the delay entirely.
87-
8881
### `force_monitor` <ConfigBadges plugin="scratchpads" option="force_monitor" /> {#config-force-monitor}
8982

9083
If set to some monitor name (eg: `"DP-1"`), it will always use this monitor to show the scratchpad.

0 commit comments

Comments
 (0)