Evan's Blog
EvanZhu0721 / 公开仓库

SBMS

镜像已同步

SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.

上游 GitHub
READ-ONLY MIRROR

README、源码与 Release 已保存到本站;源码视图固定到 commit a37d6c4b。

main/ root / src
a37d6c4b· 固定源码快照
src/win32_flyout.rs3.4 KB
1use std::mem::size_of;
2
3use raw_window_handle::{HasWindowHandle, RawWindowHandle};
4use slint::{PhysicalPosition, Window};
5use windows::Win32::Foundation::{HWND, POINT, RECT};
6use windows::Win32::Graphics::Gdi::{
7 GetMonitorInfoW, MONITOR_DEFAULTTONEAREST, MONITORINFO, MonitorFromPoint,
8};
9use windows::Win32::UI::WindowsAndMessaging::{GetCursorPos, SetForegroundWindow};
10const FLYOUT_GAP: i32 = 8;
11
12pub fn position(window: &Window) {
13 let anchor = crate::win32_tray::icon_rect().or_else(cursor_rect);
14 let Some(anchor) = anchor else {
15 return;
16 };
17 let center = POINT {
18 x: anchor.left + (anchor.right - anchor.left) / 2,
19 y: anchor.top + (anchor.bottom - anchor.top) / 2,
20 };
21 let monitor = unsafe { MonitorFromPoint(center, MONITOR_DEFAULTTONEAREST) };
22 let mut info = MONITORINFO {
23 cbSize: size_of::<MONITORINFO>() as u32,
24 rcMonitor: RECT::default(),
25 rcWork: RECT::default(),
26 dwFlags: 0,
27 };
28 if !unsafe { GetMonitorInfoW(monitor, &mut info) }.as_bool() {
29 return;
30 }
31
32 let size = window.size();
33 let width = size.width as i32;
34 let height = size.height as i32;
35 let edge = taskbar_edge(info.rcMonitor, info.rcWork, center);
36 let (x, y) = match edge {
37 Edge::Bottom => (
38 center.x - width / 2,
39 info.rcWork.bottom - height - FLYOUT_GAP,
40 ),
41 Edge::Top => (center.x - width / 2, info.rcWork.top + FLYOUT_GAP),
42 Edge::Left => (info.rcWork.left + FLYOUT_GAP, center.y - height / 2),
43 Edge::Right => (
44 info.rcWork.right - width - FLYOUT_GAP,
45 center.y - height / 2,
46 ),
47 };
48 let max_x = (info.rcWork.right - width).max(info.rcWork.left);
49 let max_y = (info.rcWork.bottom - height).max(info.rcWork.top);
50 let x = x.clamp(info.rcWork.left, max_x);
51 let y = y.clamp(info.rcWork.top, max_y);
52 window.set_position(PhysicalPosition::new(x, y));
53}
54
55pub fn activate(window: &Window) -> bool {
56 if let Some(hwnd) = hwnd(window) {
57 return unsafe { SetForegroundWindow(hwnd) }.as_bool();
58 }
59 false
60}
61
62fn hwnd(window: &Window) -> Option<HWND> {
63 let provider = window.window_handle();
64 let handle = provider.window_handle().ok()?;
65 match handle.as_raw() {
66 RawWindowHandle::Win32(handle) => Some(HWND(handle.hwnd.get() as *mut _)),
67 _ => None,
68 }
69}
70
71fn cursor_rect() -> Option<RECT> {
72 let mut cursor = POINT::default();
73 unsafe { GetCursorPos(&mut cursor) }.ok()?;
74 Some(RECT {
75 left: cursor.x,
76 top: cursor.y,
77 right: cursor.x + 1,
78 bottom: cursor.y + 1,
79 })
80}
81
82#[derive(Clone, Copy)]
83enum Edge {
84 Bottom,
85 Top,
86 Left,
87 Right,
88}
89
90fn taskbar_edge(monitor: RECT, work: RECT, anchor: POINT) -> Edge {
91 if work.bottom < monitor.bottom {
92 return Edge::Bottom;
93 }
94 if work.top > monitor.top {
95 return Edge::Top;
96 }
97 if work.left > monitor.left {
98 return Edge::Left;
99 }
100 if work.right < monitor.right {
101 return Edge::Right;
102 }
103
104 let distances = [
105 (anchor.y - monitor.top, Edge::Top),
106 (monitor.bottom - anchor.y, Edge::Bottom),
107 (anchor.x - monitor.left, Edge::Left),
108 (monitor.right - anchor.x, Edge::Right),
109 ];
110 distances
111 .into_iter()
112 .min_by_key(|(distance, _)| *distance)
113 .map(|(_, edge)| edge)
114 .unwrap_or(Edge::Bottom)
115}
116