We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
2 parents 3b24198 + dd11af4 commit 82a67d8Copy full SHA for 82a67d8
15 files changed
build.rs
@@ -19,6 +19,7 @@ fn main() {
19
let sources = [
20
"src/runtime/qt",
21
"src/ui/qt/widget",
22
+ "src/ui/qt/monitor",
23
"src/ui/qt/msgbox",
24
"src/ui/qt/filebox",
25
"src/ui/qt/window",
examples/basic.rs
@@ -5,8 +5,8 @@ use compio_log::info;
5
use winio::{
6
App, BrushPen, Canvas, CanvasEvent, Child, Color, ColorTheme, Component, ComponentSender,
7
CustomButton, DrawingFontBuilder, Grid, HAlign, Layoutable, MessageBox, MessageBoxButton,
8
- MessageBoxResponse, MessageBoxStyle, MouseButton, Point, Rect, Size, SolidColorBrush, VAlign,
9
- Visible, Window, WindowEvent,
+ MessageBoxResponse, MessageBoxStyle, Monitor, MouseButton, Point, Rect, Size, SolidColorBrush,
+ VAlign, Visible, Window, WindowEvent,
10
};
11
12
fn main() {
@@ -46,6 +46,12 @@ impl Component for MainModel {
46
window.set_text("Basic example");
47
window.set_size(Size::new(800.0, 600.0));
48
49
+ {
50
+ let monitors = Monitor::all();
51
+ let region = monitors[0].client_scaled();
52
+ window.set_loc(region.origin + region.size / 2.0 - window.size() / 2.0);
53
+ }
54
+
55
let sender = sender.clone();
56
spawn(async move {
57
let mut interval = interval(Duration::from_secs(1));
src/ui/gtk/mod.rs
@@ -7,6 +7,9 @@ pub use canvas::*;
mod widget;
pub use widget::*;
+mod monitor;
+pub use monitor::*;
13
mod msgbox;
14
pub use msgbox::*;
15
src/ui/gtk/monitor.rs
@@ -0,0 +1,35 @@
1
+use gtk4::{
2
+ gdk::{
3
+ self,
4
+ prelude::{DisplayExt, MonitorExt},
+ },
+ glib::object::Cast,
+};
+use crate::{Monitor, Point, Rect, Size};
+pub fn monitor_get_all() -> Vec<Monitor> {
+ gdk::DisplayManager::get()
+ .list_displays()
+ .into_iter()
+ .flat_map(|d| {
16
+ d.monitors()
17
18
+ .filter_map(|m| m.ok().and_then(|m| m.downcast::<gdk::Monitor>().ok()))
+ .collect::<Vec<_>>()
+ })
+ .map(|m| {
+ let geo = rect_from(m.geometry());
+ let scale = m.scale();
+ Monitor::new(geo * scale, geo * scale, Size::new(scale, scale))
26
+ .collect()
27
+}
28
29
+#[inline]
30
+fn rect_from(r: gdk::Rectangle) -> Rect {
31
+ Rect::new(
32
+ Point::new(r.x() as _, r.y() as _),
33
+ Size::new(r.width() as _, r.height() as _),
34
+ )
35
src/ui/mac/mod.rs
@@ -4,6 +4,9 @@ pub use canvas::*;
mod window;
pub use window::*;
src/ui/mac/monitor.rs
@@ -0,0 +1,42 @@
+use objc2::{MainThreadMarker, rc::Retained};
+use objc2_app_kit::{NSDeviceResolution, NSScreen};
+use objc2_foundation::NSValue;
+use crate::{
+ Monitor, Point, Rect, Size,
+ ui::{from_cgsize, transform_cgrect},
+ let mtm = MainThreadMarker::new().unwrap();
+ let mut res = vec![];
+ for screen in NSScreen::screens(mtm) {
+ let frame = screen.frame();
+ let vframe = screen.visibleFrame();
+ let frame_size = from_cgsize(frame.size);
+ let frame = transform_cgrect(frame_size, frame);
+ let vframe = transform_cgrect(frame_size, vframe);
+ let dpi = screen
+ .deviceDescription()
+ .objectForKey(unsafe { NSDeviceResolution })
+ .map(|obj| from_cgsize(unsafe { Retained::cast_unchecked::<NSValue>(obj).sizeValue() }))
+ .unwrap_or(Size::new(1.0, 1.0));
+ res.push(Monitor::new(
+ rect_scale(frame, dpi),
+ rect_scale(vframe, dpi),
+ dpi,
+ ))
+ res
36
37
+fn rect_scale(r: Rect, dpi: Size) -> Rect {
38
39
+ Point::new(r.origin.x * dpi.width, r.origin.y * dpi.height),
40
+ Size::new(r.size.width * dpi.width, r.size.height * dpi.height),
41
42
src/ui/mod.rs
@@ -26,6 +26,7 @@ pub use sys::*;
mod canvas;
mod drawing;
mod filebox;
mod window_handle;
@@ -34,6 +35,7 @@ pub mod export {
canvas::*,
drawing::*,
filebox::*,
+ monitor::*,
msgbox::*,
sys::{Brush, Pen, RawWindow},
window_handle::*,
src/ui/monitor.rs
@@ -0,0 +1,66 @@
+use crate::{Point, Rect, Size, ui::sys};
+/// Represents the geometry of a monitor.
+#[derive(Debug, Clone, PartialEq)]
+pub struct Monitor {
+ region: Rect,
+ client: Rect,
+ dpi: Size,
+impl Monitor {
+ pub(crate) fn new(region: Rect, client: Rect, dpi: Size) -> Self {
+ Self {
+ region,
+ client,
+ /// Retrieve all monitors.
+ pub fn all() -> Vec<Self> {
+ sys::monitor_get_all()
+ /// The physical region.
+ pub fn region(&self) -> Rect {
+ self.region
+ /// The client region.
+ pub fn client(&self) -> Rect {
+ self.client
+ /// Dpi of the monitor, 1.0 if no scale. You should take it into
+ /// consideration when setting the location of windows.
+ /// See [`Monitor::region_scaled`] & [`Monitor::client_scaled`].
+ pub fn dpi(&self) -> Size {
+ self.dpi
+ /// Scaled physical region.
43
+ pub fn region_scaled(&self) -> Rect {
44
+ div_rect(self.region, self.dpi)
45
+ /// Scaled client region.
+ pub fn client_scaled(&self) -> Rect {
+ div_rect(self.client, self.dpi)
+fn div_rect(r: Rect, s: Size) -> Rect {
+ Rect::new(div_point(r.origin, s), div_size(r.size, s))
58
59
+fn div_point(p: Point, s: Size) -> Point {
60
+ Point::new(p.x / s.width, p.y / s.height)
61
62
63
64
+fn div_size(s1: Size, s2: Size) -> Size {
65
+ Size::new(s1.width / s2.width, s1.height / s2.height)
66
src/ui/qt/mod.rs
src/ui/qt/monitor.cpp
@@ -0,0 +1,12 @@
+#include "monitor.hpp"
+#include <QApplication>
+rust::Vec<Monitor> screen_all() {
+ rust::Vec<Monitor> res{};
+ for (QScreen *s : QApplication::screens()) {
+ res.push_back(Monitor{s->geometry(), s->availableGeometry(),
+ s->logicalDotsPerInchX(),
+ s->logicalDotsPerInchY()});
+ return res;
0 commit comments