Skip to content

Commit

Permalink
refactor: refactor opacity value
Browse files Browse the repository at this point in the history
  • Loading branch information
jackssrt committed Dec 4, 2024
1 parent 87e121a commit 9009457
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 89 deletions.
6 changes: 2 additions & 4 deletions packages/wm/src/common/commands/platform_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tokio::task;
use tracing::warn;

use crate::{
common::{platform::Platform, DisplayState, OpacityUnit, OpacityValue},
common::{platform::Platform, DisplayState, OpacityValue},
containers::{
traits::{CommonGetters, PositionGetters},
Container, WindowContainer,
Expand Down Expand Up @@ -300,9 +300,7 @@ fn apply_transparency_effect(
// enabled in one of the two window effect configurations. In
// this case, reset the opacity to default.
OpacityValue {
amount: 255.0,
unit: OpacityUnit::Alpha,
delta_sign: false,
amount: 255,
is_delta: false,
}
})
Expand Down
77 changes: 18 additions & 59 deletions packages/wm/src/common/opacity_value.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,20 @@
use std::str::FromStr;

use anyhow::{bail, Context};
use anyhow::Context;
use regex::Regex;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct OpacityValue {
pub amount: f32,
pub unit: OpacityUnit,
pub amount: i16,
pub is_delta: bool,
pub delta_sign: bool,
}

#[derive(Debug, Deserialize, Clone, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum OpacityUnit {
Alpha,
Percentage,
}

impl OpacityValue {
pub fn to_exact(&self) -> u8 {
match self.unit {
OpacityUnit::Alpha => self.amount as u8,
OpacityUnit::Percentage => (self.amount * 255.0) as u8,
}
}
}

impl Default for OpacityValue {
fn default() -> Self {
Self {
amount: 255.0,
unit: OpacityUnit::Alpha,
amount: 255,
is_delta: false,
delta_sign: false,
}
}
}
Expand All @@ -48,13 +28,11 @@ impl FromStr for OpacityValue {
///
/// Example:
/// ```
/// # use wm::common::{OpacityValue, OpacityUnit};
/// # use wm::common::{OpacityValue};
/// # use std::str::FromStr;
/// let check = OpacityValue {
/// amount: 0.75,
/// unit: OpacityUnit::Percentage,
/// amount: 191,
/// is_delta: false,
/// delta_sign: false,
/// };
/// let parsed = OpacityValue::from_str("75%");
/// assert_eq!(parsed.unwrap(), check);
Expand All @@ -72,34 +50,27 @@ impl FromStr for OpacityValue {
.context(err_msg.to_string())?;

let sign_str = captures.get(1).map_or("", |m| m.as_str());
let delta_sign = sign_str == "+";

// interpret value as a delta if it explicitly starts with a sign
// Interpret value as a delta if it explicitly starts with a sign.
let is_delta = !sign_str.is_empty();

let unit_str = captures.get(3).map_or("", |m| m.as_str());
let unit = match unit_str {
"" => OpacityUnit::Alpha,
"%" => OpacityUnit::Percentage,
_ => bail!(err_msg),
};

let amount = captures
.get(2)
.and_then(|amount_str| f32::from_str(amount_str.into()).ok())
// Store percentage units as a fraction of 1.
.map(|amount| match unit {
OpacityUnit::Alpha => amount,
OpacityUnit::Percentage => amount / 100.0,
// Convert percentages to 0-255 range.
.map(|amount| match unit_str {
"%" => (amount / 100.0 * 255.0).round() as i16,
_ => amount.round() as i16,
})
// Negate the value if it's a negative delta.
// Since an explicit sign tells us it's a delta,
// a negative Alpha value is impossible.
.map(|amount| if sign_str == "-" { -amount } else { amount })
.context(err_msg.to_string())?;

Ok(OpacityValue {
amount,
unit,
is_delta,
delta_sign,
})
Ok(OpacityValue { amount, is_delta })
}
}

Expand All @@ -112,26 +83,14 @@ impl<'de> Deserialize<'de> for OpacityValue {
#[derive(Deserialize)]
#[serde(untagged, rename_all = "camelCase")]
enum OpacityValueDe {
Struct {
amount: f32,
unit: OpacityUnit,
is_delta: bool,
delta_sign: bool,
},
Struct { amount: f32, is_delta: bool },
String(String),
}

match OpacityValueDe::deserialize(deserializer)? {
OpacityValueDe::Struct {
amount,
unit,
is_delta,
delta_sign,
} => Ok(Self {
amount,
unit,
OpacityValueDe::Struct { amount, is_delta } => Ok(Self {
amount: amount as i16,
is_delta,
delta_sign,
}),
OpacityValueDe::String(str) => {
Self::from_str(&str).map_err(serde::de::Error::custom)
Expand Down
44 changes: 18 additions & 26 deletions packages/wm/src/common/platform/native_window.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::mem::MaybeUninit;

use anyhow::{bail, Context};
use tracing::warn;
use windows::{
Expand Down Expand Up @@ -31,14 +29,14 @@ use windows::{
SendNotifyMessageW, SetForegroundWindow,
SetLayeredWindowAttributes, SetWindowLongPtrW, SetWindowPlacement,
SetWindowPos, ShowWindowAsync, GWL_EXSTYLE, GWL_STYLE, GW_OWNER,
HWND_NOTOPMOST, HWND_TOPMOST, LWA_ALPHA, LWA_COLORKEY,
SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED, SWP_NOACTIVATE,
SWP_NOCOPYBITS, SWP_NOMOVE, SWP_NOOWNERZORDER, SWP_NOSENDCHANGING,
SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE,
SW_RESTORE, SW_SHOWNA, WINDOWPLACEMENT, WINDOW_EX_STYLE,
WINDOW_STYLE, WM_CLOSE, WPF_ASYNCWINDOWPLACEMENT, WS_CAPTION,
WS_CHILD, WS_DLGFRAME, WS_EX_LAYERED, WS_EX_NOACTIVATE,
WS_EX_TOOLWINDOW, WS_MAXIMIZEBOX, WS_THICKFRAME,
HWND_NOTOPMOST, HWND_TOPMOST, LAYERED_WINDOW_ATTRIBUTES_FLAGS,
LWA_ALPHA, LWA_COLORKEY, SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED,
SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOMOVE, SWP_NOOWNERZORDER,
SWP_NOSENDCHANGING, SWP_NOSIZE, SWP_NOZORDER, SW_HIDE,
SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWNA, WINDOWPLACEMENT,
WINDOW_EX_STYLE, WINDOW_STYLE, WM_CLOSE, WPF_ASYNCWINDOWPLACEMENT,
WS_CAPTION, WS_CHILD, WS_DLGFRAME, WS_EX_LAYERED,
WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_MAXIMIZEBOX, WS_THICKFRAME,
},
},
},
Expand Down Expand Up @@ -407,7 +405,6 @@ impl NativeWindow {
unsafe { GetWindowLongPtrW(HWND(self.handle), GWL_EXSTYLE) };

if ex_style & WS_EX_LAYERED.0 as isize == 0 {
// Window doesn't have the layered style, so add it.
unsafe {
SetWindowLongPtrW(
HWND(self.handle),
Expand All @@ -418,18 +415,16 @@ impl NativeWindow {
}

// Get the window's opacity information.
let mut previous_opacity = MaybeUninit::uninit();
let mut flag = MaybeUninit::uninit();
let mut previous_opacity = u8::MAX; // Use maximum opacity as a default.
let mut flag = LAYERED_WINDOW_ATTRIBUTES_FLAGS::default();
unsafe {
GetLayeredWindowAttributes(
HWND(self.handle),
None,
Some(previous_opacity.as_mut_ptr()),
Some(flag.as_mut_ptr()),
Some(&mut previous_opacity),
Some(&mut flag),
)?;
}
let previous_opacity = unsafe { previous_opacity.assume_init() };
let flag = unsafe { flag.assume_init() };

// Fail if window uses color key.
if flag.contains(LWA_COLORKEY) {
Expand All @@ -439,19 +434,16 @@ impl NativeWindow {
}

// Calculate the new opacity value.
let exact_opacity_value = opacity_value.to_exact();
let new_opacity = if opacity_value.is_delta {
// TODO: Enable feature for saturing_sub_signed
// TODO: Use a signed value for delta
if !opacity_value.delta_sign {
previous_opacity.saturating_sub(exact_opacity_value)
} else {
previous_opacity.saturating_add(exact_opacity_value)
}
previous_opacity as i16 + opacity_value.amount
} else {
exact_opacity_value
opacity_value.amount
};

// Clamp new_opacity to a u8.
let new_opacity =
new_opacity.clamp(u8::MIN as i16, u8::MAX as i16) as u8;

// Set the new opacity if needed.
if new_opacity != previous_opacity {
unsafe {
Expand Down

0 comments on commit 9009457

Please sign in to comment.