Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/oversized.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
1893 app/src-tauri/src/lib.rs
1965 crates/linkunbound-shell/src/main.rs
1952 crates/linkunbound-shell/src/main.rs
121 changes: 114 additions & 7 deletions crates/linkunbound-shell/src/look.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,37 @@
use slint::ComponentHandle;

pub fn style(picker: &Picker, chosen: PickerStyle) {
let look = match chosen {
picker.set_look(match chosen {
PickerStyle::Classic => Look::List,
PickerStyle::Sheet => Look::Tiles,
PickerStyle::Compact => Look::Compact,
PickerStyle::Bear => Look::Bear,
};
let clear = native_glass();
picker.set_look(look);
});
settle(picker);
}

/// A remote session or energy saver can start between two links.
pub fn settle(picker: &Picker) {
dress_for(picker, !blends());

Check warning on line 19 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

delete ! in settle

Check warning on line 19 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace settle with ()

Check warning on line 19 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

delete ! in settle

Check warning on line 19 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace settle with ()
}

/// Unblended, the shadow and the bear would come out as black boxes.
fn dress_for(picker: &Picker, solid: bool) {
let look = picker.get_look();
let clear = !solid && native_glass();

Check warning on line 25 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

delete ! in dress_for

Check warning on line 25 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

delete ! in dress_for
let palette = picker.global::<Palette>();
palette.set_solid(solid);
palette.set_clear(clear);
palette.set_tint(tint());
palette.set_glass_corner(if cfg!(target_os = "macos") {
corner_of(picker) as f32
} else if solid && !dwm_rounds() {

Check warning on line 32 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

delete ! in dress_for

Check warning on line 32 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace && with || in dress_for

Check warning on line 32 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

delete ! in dress_for

Check warning on line 32 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace && with || in dress_for
0.0
} else {
DWM_CORNER
});
palette.set_see_through(see_through());
picker.set_halo(if look == Look::List || clear {
palette.set_see_through(!solid && see_through());

Check warning on line 37 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

delete ! in dress_for

Check warning on line 37 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace && with || in dress_for
picker.set_halo(if look == Look::List || clear || solid {

Check warning on line 38 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace == with != in dress_for

Check warning on line 38 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace || with && in dress_for

Check warning on line 38 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace || with && in dress_for
0.0
} else {
HALO
Expand Down Expand Up @@ -59,6 +72,10 @@
/// painted sheet and its shadow come back. Returns whether the window changed size.
pub fn wear_backdrop(picker: &Picker, handle: isize) -> bool {
let palette = picker.global::<Palette>();
if palette.get_solid() {
wear_solid(handle, !palette.get_light());

Check warning on line 76 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

delete ! in wear_backdrop
return false;
}
if !palette.get_clear() {
take_off_glass(handle);
return false;
Expand All @@ -74,6 +91,18 @@
true
}

pub fn dress_the_window(picker: &Picker) {
let Some(handle) = crate::native_handle(picker.window()) else {
return;
};
crate::host::keep_off_the_taskbar(handle, corner_of(picker));
if wear_backdrop(picker, handle) {
beside_the_pointer(picker);
}
follow(picker);
crate::host::take_the_keyboard(handle);

Check warning on line 103 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace dress_the_window with ()
}

/// The picker belongs to the click that summoned it, not to the middle of a screen.
pub fn beside_the_pointer(picker: &Picker) {
let Some(pointer) = crate::host::cursor() else {
Expand Down Expand Up @@ -156,6 +185,37 @@
}
}

#[cfg(windows)]
fn blends() -> bool {
linkunbound_win::transparency_is_on() && linkunbound_win::blends_windows()

Check warning on line 190 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace && with || in blends

Check warning on line 190 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace blends -> bool with false

Check warning on line 190 in crates/linkunbound-shell/src/look.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace blends -> bool with true
}

/// macOS blends every window; only the material can go.
#[cfg(not(windows))]
fn blends() -> bool {
true
}

#[cfg(windows)]
fn dwm_rounds() -> bool {
linkunbound_win::dwm_rounds_corners()
}

#[cfg(not(windows))]
fn dwm_rounds() -> bool {
false
}

#[cfg(windows)]
fn wear_solid(window: isize, dark: bool) {
if dwm_rounds() {
linkunbound_win::wear_solid(window, dark);
}
}

#[cfg(not(windows))]
fn wear_solid(_window: isize, _dark: bool) {}

#[cfg(windows)]
fn see_through() -> bool {
linkunbound_win::transparency_is_on()
Expand Down Expand Up @@ -216,7 +276,7 @@

#[cfg(test)]
mod tests {
use super::{corner_of, native_glass, place_near, style, wear_backdrop};
use super::{corner_of, dress_for, native_glass, place_near, style, wear_backdrop};
use linkunbound_core::PickerStyle;
use linkunbound_shell::{CLASSIC_CORNER, CORNER, HALO, Palette, Picker};
use slint::ComponentHandle;
Expand All @@ -234,11 +294,15 @@
let clear = native_glass();

style(&picker, PickerStyle::Sheet);

dress_for(&picker, false);
assert_eq!(picker.global::<Palette>().get_clear(), clear);
assert_eq!(picker.get_halo(), if clear { 0.0 } else { HALO });
assert!((corner_of(&picker) - CORNER).abs() < f64::EPSILON);

style(&picker, PickerStyle::Classic);

dress_for(&picker, false);
assert_eq!(picker.get_halo(), 0.0);
assert!((corner_of(&picker) - CLASSIC_CORNER).abs() < f64::EPSILON);
}
Expand All @@ -252,9 +316,13 @@
let near_the_top = (900, 2);

style(&picker, PickerStyle::Classic);

dress_for(&picker, false);
let (_, list_y) = place_near(&picker, near_the_top, screen);

style(&picker, PickerStyle::Bear);

dress_for(&picker, false);
picker.set_halo(0.0);
let (_, bear_y) = place_near(&picker, near_the_top, screen);
let rise = crate::mascot::rise(&picker);
Expand All @@ -273,13 +341,17 @@
let palette = picker.global::<Palette>();

style(&picker, PickerStyle::Sheet);

dress_for(&picker, false);
palette.set_clear(true);
picker.set_halo(0.0);
assert!(wear_backdrop(&picker, 0), "the tiles grow by their shadow");
assert!(!palette.get_clear());
assert_eq!(picker.get_halo(), HALO);

style(&picker, PickerStyle::Classic);

dress_for(&picker, false);
palette.set_clear(true);
assert!(!wear_backdrop(&picker, 0), "the list has no shadow to add");
assert!(!palette.get_clear());
Expand All @@ -289,4 +361,39 @@
"a painted sheet asks for nothing"
);
}

/// Unblended, every look fills its window with no shadow, material or bear.
#[test]
fn a_system_that_blends_nothing_gets_an_opaque_sheet() {
let picker = picker();
let palette = picker.global::<Palette>();

for chosen in [
PickerStyle::Classic,
PickerStyle::Sheet,
PickerStyle::Compact,
PickerStyle::Bear,
] {
style(&picker, chosen);
dress_for(&picker, true);
assert!(palette.get_solid());
assert!(!palette.get_clear());
assert!(!palette.get_see_through());
assert_eq!(picker.get_halo(), 0.0);
assert_eq!(
crate::mascot::rise(&picker),
0.0,
"{chosen:?} shows no bear"
);
}
assert!(
!wear_backdrop(&picker, 0),
"the opaque sheet keeps its size"
);

style(&picker, PickerStyle::Bear);
dress_for(&picker, false);
assert!(!palette.get_solid());
assert!(crate::mascot::rise(&picker) > 0.0, "the bear is back");
}
}
19 changes: 3 additions & 16 deletions crates/linkunbound-shell/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ fn present(picker: &Picker, words: &Strings, shown: &Rc<RefCell<Shown>>, arrival
else {
return false;
};
look::settle(picker);
let label = source.as_ref().map(|origin| origin.label.as_str());
let listed = rows(physical_icon_side(picker));
if listed.is_empty() {
Expand All @@ -522,14 +523,7 @@ fn present(picker: &Picker, words: &Strings, shown: &Rc<RefCell<Shown>>, arrival
}
look::beside_the_pointer(picker);
let _ = picker.show();
if let Some(handle) = native_handle(picker.window()) {
host::keep_off_the_taskbar(handle, look::corner_of(picker));
if look::wear_backdrop(picker, handle) {
look::beside_the_pointer(picker);
}
look::follow(picker);
host::take_the_keyboard(handle);
}
look::dress_the_window(picker);
return true;
}
dress(picker, words, &url, label, &listed);
Expand All @@ -548,14 +542,7 @@ fn present(picker: &Picker, words: &Strings, shown: &Rc<RefCell<Shown>>, arrival
if let Some(ui) = ui() {
ui.appeared.set(Some(std::time::Instant::now()));
}
if let Some(handle) = native_handle(picker.window()) {
host::keep_off_the_taskbar(handle, look::corner_of(picker));
if look::wear_backdrop(picker, handle) {
look::beside_the_pointer(picker);
}
look::follow(picker);
host::take_the_keyboard(handle);
}
look::dress_the_window(picker);
// The window reports a scale of one until it exists, which is only now: the first picker of
// a session on a dense display was placed for a window two thirds its size, and drew icons
// asked for at the wrong side.
Expand Down
6 changes: 4 additions & 2 deletions crates/linkunbound-shell/src/mascot.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The bear that peeks over the picker: its head under the glass, its paws on the edge.

use linkunbound_shell::{BearHead, BearPaws, Look, Picker};
use linkunbound_shell::{BearHead, BearPaws, Look, Palette, Picker};
use slint::ComponentHandle;

/// Sizes in logical pixels: the head, how far it rises over the edge, a paw, the room between
Expand All @@ -25,10 +25,12 @@ const COMPACT: Pose = Pose {
gap: 46.0,
};

/// The pose the look calls for, if the bear shows at all: only over the glass, since on a painted
/// The pose the look calls for, if the bear shows at all. Its head sits under the picker, so on
/// glass the hidden half shows blurred and on a painted sheet it is simply behind it.
fn pose(picker: &Picker) -> Option<&'static Pose> {
if picker.global::<Palette>().get_solid() {
return None;
}
match picker.get_look() {
Look::Bear => Some(&BEAR),
Look::Compact => Some(&COMPACT),
Expand Down
2 changes: 2 additions & 0 deletions crates/linkunbound-shell/ui/parts.slint
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export global Palette {
in property <float> tint: 0.77;
// DWM rounds Acrylic at its own 8px; on macOS the glass view is cut to the sheet's corner.
in property <length> glass-corner: 8px;
// Windows blends no window: the opaque sheet fills it.
in property <bool> solid: false;
out property <brush> veil: light
? @linear-gradient(180deg, #FFFFFF.with-alpha(tint) 0%, #F3F5F9.with-alpha(tint + 0.03) 100%)
: @linear-gradient(180deg, #282B36.with-alpha(tint) 0%, #1A1C23.with-alpha(tint + 0.03) 100%);
Expand Down
2 changes: 1 addition & 1 deletion crates/linkunbound-shell/ui/shell.slint
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export component Picker inherits Window {
y: root.halo;
width: root.sheet-width;
height: root.sheet-height;
border-radius: Palette.clear ? Palette.glass-corner : (root.look == Look.list ? 10px : 14px);
border-radius: Palette.clear || Palette.solid ? Palette.glass-corner : (root.look == Look.list ? 10px : 14px);
background: Palette.clear ? Palette.veil : Palette.pane;
border-width: Palette.clear && !root.private-on ? 0px : 1px;
border-color: root.private-on ? Palette.secret : Palette.glow;
Expand Down
2 changes: 2 additions & 0 deletions crates/linkunbound-win/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ windows = { version = "0.62", features = [
"Win32_Security_Authorization",
"Win32_System_IO",
"Win32_System_Pipes",
"Win32_System_Power",
"Win32_System_RemoteDesktop",
"Win32_System_Threading",
"Win32_UI_Shell",
Expand All @@ -38,6 +39,7 @@ windows = { version = "0.62", features = [
"Win32_System_Memory",
"Win32_System_Ole",
"Win32_Storage_FileSystem",
"Win32_UI_Accessibility",
"Win32_UI_Controls",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_WindowsAndMessaging",
Expand Down
12 changes: 6 additions & 6 deletions crates/linkunbound-win/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ pub use detect::installed_browsers;
pub use icons::cached_or_extract as icon_for;
#[cfg(windows)]
pub use native::{
attach_parent_console, copy_text, current_session, current_user_sid, cursor, digit_behind,
front_is_ours, front_window, is_in_front, keep_off_the_taskbar,
attach_parent_console, blends_windows, copy_text, current_session, current_user_sid, cursor,
digit_behind, front_is_ours, front_window, is_in_front, keep_off_the_taskbar,
let_whoever_opens_next_come_forward, never_activates, notify_associations_changed,
shift_is_down, source_app, strip_title_icon, take_the_keyboard, tuck_under, wear_acrylic,
work_area_at, write_line_to_pipe,
wear_solid, work_area_at, write_line_to_pipe,
};
#[cfg(windows)]
pub use registration::{
Registration, acrylic_is_available, association_report, default_apps_page, is_build_tree,
is_default_browser, sweep_legacy_edge_capture, taskbar_is_light, transparency_is_on,
windows_are_light,
Registration, acrylic_is_available, association_report, default_apps_page, dwm_rounds_corners,
is_build_tree, is_default_browser, sweep_legacy_edge_capture, taskbar_is_light,
transparency_is_on, windows_are_light,
};
#[cfg(windows)]
pub use startup::{
Expand Down
Loading
Loading