Skip to content

Commit

Permalink
feat(animation): add window animations
Browse files Browse the repository at this point in the history
Work on this feature was first started by @thearturca in November 2023
before komorebi v0.1.21 in #597 and has undergone numerous revisions
to reach the point of this commit.

Although this is a single squashed commit, almost all of the heavy
lifting for this feature was done by @thearturca, which is where all of
the kudos and gratitude should be directed.

This commit adds a new static configuration block for animations, where
they can be enabled, and have their style, fps and duration set.
Corresponding SocketMessages and komorebic cli commands have also been
exposed.

There are some caveats to the use of this feature, which revolve around
the quality of the Windows compositor (it is not very good):

* There will be visual artifacts with various apps when animations are
  taking place - komorebi can't do anything about this as it is a
  limitation of the Windows compositor
* Since komorebi's borders are implemented as independent windows are
  are not a part of the windows they are drawn around, these borders
  will be hidden while animations are in progress
* If you wish to use borders with this feature, you'll probably better
  off using BorderImplementation::Windows, which uses the native thin
  "accent" borders, which are part of the windows they are drawn around,
  and can be moved with those windows during animations

As a result of these and other caveats, this feature will be marked as
"experimental" for the foreseeable future and will be off-by-default.

Below, a number of now-squashed commits that contributed to the
stabilization of this feature are referenced to help with code
archeology in the future.

fix(animation): Fixed cancelling logic
(57e9b2f)

Added static animation state manager for tracking "in_progress" and
"is_cancelled" states. The idea is not to have states in Animation
struct but to keep them in HashMap<hwnd, AnimationState> behind
reference (Arc<Mutex<>>). So we each animation frame we have access to
state and can cancel animation if we have to.

Need review and testings

refactor(animation): avoid unwrap
(fa6d5bb)

fix(animation): Move cancel call to Animation struct
(306513f)

Only focused window was cancelling its animation because we call cancel
in window::set_position and waiting for its cancelling. And because we
waiting for cancelling second window is still moving. Second window will stop
moving only after the first window. So I moved `cancel` call to
Animation struct so its happening in its own thread and doesn't block
others animation moves and cancels.

refactor(animation): renamed args parameters and variables names
(8abb4b9)

refactor(animation): inverse if-statement in `window::animate_position`
(3de2c6e)

There is was a bug when ease function generates `t` greater the
`SetWindowPos` function will be called instead of `move_window`.
`SetWindowPos` is only for last frame of animation.

fix(wm): add shadow rect to `move_window` calls
(b58620f)

This fixes a bug when windows get shunk during the animation
  • Loading branch information
LGUG2Z committed Jul 10, 2024
1 parent aebe879 commit 48f75f1
Show file tree
Hide file tree
Showing 14 changed files with 845 additions and 11 deletions.
42 changes: 42 additions & 0 deletions komorebi-core/src/animation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use clap::ValueEnum;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use strum::Display;
use strum::EnumString;

#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
pub enum AnimationStyle {
Linear,
EaseInSine,
EaseOutSine,
EaseInOutSine,
EaseInQuad,
EaseOutQuad,
EaseInOutQuad,
EaseInCubic,
EaseInOutCubic,
EaseInQuart,
EaseOutQuart,
EaseInOutQuart,
EaseInQuint,
EaseOutQuint,
EaseInOutQuint,
EaseInExpo,
EaseOutExpo,
EaseInOutExpo,
EaseInCirc,
EaseOutCirc,
EaseInOutCirc,
EaseInBack,
EaseOutBack,
EaseInOutBack,
EaseInElastic,
EaseOutElastic,
EaseInOutElastic,
EaseInBounce,
EaseOutBounce,
EaseInOutBounce,
}
6 changes: 6 additions & 0 deletions komorebi-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use serde::Serialize;
use strum::Display;
use strum::EnumString;

pub use animation::AnimationStyle;
pub use arrangement::Arrangement;
pub use arrangement::Axis;
pub use custom_layout::CustomLayout;
Expand All @@ -24,6 +25,7 @@ pub use layout::Layout;
pub use operation_direction::OperationDirection;
pub use rect::Rect;

pub mod animation;
pub mod arrangement;
pub mod config_generation;
pub mod custom_layout;
Expand Down Expand Up @@ -134,6 +136,10 @@ pub enum SocketMessage {
WatchConfiguration(bool),
CompleteConfiguration,
AltFocusHack(bool),
Animation(bool),
AnimationDuration(u64),
AnimationFps(u64),
AnimationStyle(AnimationStyle),
#[serde(alias = "ActiveWindowBorder")]
Border(bool),
#[serde(alias = "ActiveWindowBorderColour")]
Expand Down
10 changes: 10 additions & 0 deletions komorebi-core/src/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,14 @@ impl Rect {
bottom: (self.bottom * rect_dpi) / system_dpi,
}
}

#[must_use]
pub const fn rect(&self) -> RECT {
RECT {
left: self.left,
top: self.top,
right: self.left + self.right,
bottom: self.top + self.bottom,
}
}
}
6 changes: 2 additions & 4 deletions komorebi-gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ extern "system" fn enum_window(
lparam: windows::Win32::Foundation::LPARAM,
) -> windows::Win32::Foundation::BOOL {
let windows = unsafe { &mut *(lparam.0 as *mut Vec<Window>) };
let window = Window { hwnd: hwnd.0 };
let window = Window::from(hwnd.0);

if window.is_window()
&& !window.is_miminized()
Expand Down Expand Up @@ -246,9 +246,7 @@ impl eframe::App for KomorebiGui {
ui.set_width(ctx.screen_rect().width());
ui.collapsing("Debugging", |ui| {
ui.collapsing("Window Rules", |ui| {
let window = Window {
hwnd: self.debug_hwnd,
};
let window = Window::from(self.debug_hwnd);

let label = if let (Ok(title), Ok(exe)) = (window.title(), window.exe()) {
format!("{title} ({exe})")
Expand Down
Loading

0 comments on commit 48f75f1

Please sign in to comment.