Skip to content

Commit

Permalink
feat: add monitor_from_point method, closes #187 (#608)
Browse files Browse the repository at this point in the history
* add monitor_from_point for macos

* add monitor_from_point to EventLoopWindowTarget

* add support for linux

* add support for windows

* Update src/platform_impl/windows/monitor.rs

Co-authored-by: Amr Bashir <[email protected]>

* Update src/platform_impl/windows/monitor.rs

Co-authored-by: Amr Bashir <[email protected]>

* Update src/event_loop.rs

Co-authored-by: Amr Bashir <[email protected]>

* Update src/window.rs

Co-authored-by: Amr Bashir <[email protected]>

* add stub function for ios and android

* fix typo

* Update src/platform_impl/linux/event_loop.rs

Co-authored-by: Amr Bashir <[email protected]>

* add CGRectContainsPoint to macos ffi module

* fix typo

* fix type of stub function

* add eventloop-target stub functions

* fix format error

* Cargo fmt

Co-authored-by: Amr Bashir <[email protected]>
Co-authored-by: Wu Wayne <[email protected]>
  • Loading branch information
3 people authored Dec 1, 2022
1 parent aa96fc2 commit c0d5a53
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 6 deletions.
13 changes: 13 additions & 0 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ impl<T> EventLoopWindowTarget<T> {
self.p.primary_monitor()
}

/// Returns the monitor that contains the given point.
///
/// ## Platform-specific:
///
/// - **Android / iOS:** Unsupported.
#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
self
.p
.monitor_from_point(x, y)
.map(|inner| MonitorHandle { inner })
}

/// Change [`DeviceEvent`] filter mode.
///
/// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
Expand Down
12 changes: 12 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,12 @@ impl<T: 'static> EventLoopWindowTarget<T> {
})
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
warn!("`Window::monitor_from_point` is ignored on Android");
return None;
}

pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
let mut v = VecDeque::with_capacity(1);
v.push_back(MonitorHandle);
Expand Down Expand Up @@ -546,6 +552,12 @@ impl Window {
v
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<monitor::MonitorHandle> {
warn!("`Window::monitor_from_point` is ignored on Android");
None
}

pub fn current_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ impl<T: 'static> EventLoopWindowTarget<T> {
unsafe { monitor::uiscreens() }
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
warn!("`Window::monitor_from_point` is ignored on iOS");
return None;
}

pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
// guaranteed to be on main thread
let monitor = unsafe { monitor::main_uiscreen() };
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ impl Inner {
unsafe { monitor::uiscreens() }
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<RootMonitorHandle> {
warn!("`Window::monitor_from_point` is ignored on iOS");
None
}

pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
let monitor = unsafe { monitor::main_uiscreen() };
Some(RootMonitorHandle { inner: monitor })
Expand Down
6 changes: 5 additions & 1 deletion src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::{

use super::{
keyboard,
monitor::MonitorHandle,
monitor::{self, MonitorHandle},
window::{WindowId, WindowRequest},
};

Expand All @@ -57,6 +57,10 @@ pub struct EventLoopWindowTarget<T> {
}

impl<T> EventLoopWindowTarget<T> {
#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
monitor::from_point(&self.display, x, y)
}
#[inline]
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
let mut handles = VecDeque::new();
Expand Down
13 changes: 13 additions & 0 deletions src/platform_impl/linux/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Copyright 2021-2022 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0

use gdk::Display;

use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
Expand Down Expand Up @@ -85,3 +87,14 @@ impl VideoMode {
panic!("VideoMode is unsupported on Linux.")
}
}

pub fn from_point(display: &Display, x: f64, y: f64) -> Option<MonitorHandle> {
if let Some(monitor) = display.monitor_at_point(x as i32, y as i32) {
(0..display.n_monitors())
.map(|i| (i, display.monitor(i).unwrap()))
.find(|cur| cur.1.geometry() == monitor.geometry())
.map(|x| MonitorHandle::new(display, x.0))
} else {
None
}
}
12 changes: 10 additions & 2 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ use crate::{
};

use super::{
event_loop::EventLoopWindowTarget, menu, monitor::MonitorHandle, Parent,
PlatformSpecificWindowBuilderAttributes,
event_loop::EventLoopWindowTarget,
menu,
monitor::{self, MonitorHandle},
Parent, PlatformSpecificWindowBuilderAttributes,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -749,6 +751,12 @@ impl Window {
Some(RootMonitorHandle { inner: handle })
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<RootMonitorHandle> {
let display = &self.window.display();
monitor::from_point(display, x, y).map(|inner| RootMonitorHandle { inner })
}

pub fn raw_window_handle(&self) -> RawWindowHandle {
// TODO: add wayland support
let mut window_handle = XlibWindowHandle::empty();
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/macos/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ impl<T: 'static> EventLoopWindowTarget<T> {
monitor::available_monitors()
}

#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
monitor::from_point(x, y)
}

#[inline]
pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
let monitor = monitor::primary_monitor();
Expand Down
5 changes: 4 additions & 1 deletion src/platform_impl/macos/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use std::ffi::c_void;

use cocoa::{
appkit::CGPoint,
base::id,
foundation::{NSInteger, NSUInteger},
};
Expand All @@ -23,7 +24,8 @@ use core_foundation::{
};
use core_graphics::{
base::CGError,
display::{CGDirectDisplayID, CGDisplayConfigRef},
display::{boolean_t, CGDirectDisplayID, CGDisplayConfigRef},
geometry::CGRect,
};
pub const NSNotFound: NSInteger = NSInteger::max_value();

Expand Down Expand Up @@ -221,6 +223,7 @@ extern "C" {
blueBlend: f32,
synchronous: Boolean,
) -> CGError;
pub fn CGRectContainsPoint(rect: CGRect, point: CGPoint) -> boolean_t;
pub fn CGReleaseDisplayFadeReservation(token: CGDisplayFadeReservationToken) -> CGError;
pub fn CGShieldingWindowLevel() -> CGWindowLevel;
pub fn CGDisplaySetDisplayMode(
Expand Down
20 changes: 18 additions & 2 deletions src/platform_impl/macos/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

use std::{collections::VecDeque, fmt};

use super::{ffi, util};
use super::{
ffi::{self, CGRectContainsPoint},
util,
};
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
};
use cocoa::{
appkit::NSScreen,
appkit::{CGPoint, NSScreen},
base::{id, nil},
foundation::NSUInteger,
};
Expand Down Expand Up @@ -158,6 +161,19 @@ pub fn primary_monitor() -> MonitorHandle {
MonitorHandle(CGDisplay::main().id)
}

// `from_point` get a monitor handle which contains the given point.
pub fn from_point(x: f64, y: f64) -> Option<MonitorHandle> {
unsafe {
for monitor in available_monitors() {
let bound = CGDisplayBounds(monitor.0);
if CGRectContainsPoint(bound, CGPoint::new(x, y)) > 0 {
return Some(monitor);
}
}
}
return None;
}

impl fmt::Debug for MonitorHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: Do this using the proper fmt API
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,10 @@ impl UnownedWindow {
pub fn current_monitor(&self) -> Option<RootMonitorHandle> {
Some(self.current_monitor_inner())
}
#[inline]
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<RootMonitorHandle> {
monitor::from_point(x, y).map(|inner| RootMonitorHandle { inner })
}

#[inline]
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ impl<T> EventLoopWindowTarget<T> {
Some(RootMonitorHandle { inner: monitor })
}

pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
monitor::from_point(x, y)
}

pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::Windows(WindowsDisplayHandle::empty())
}
Expand Down
21 changes: 21 additions & 0 deletions src/platform_impl/windows/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,23 @@ pub fn current_monitor(hwnd: HWND) -> MonitorHandle {
MonitorHandle::new(hmonitor)
}

pub fn from_point(x: f64, y: f64) -> Option<MonitorHandle> {
let hmonitor = unsafe {
MonitorFromPoint(
POINT {
x: x as i32,
y: y as i32,
},
MONITOR_DEFAULTTONULL,
)
};
if hmonitor.is_invalid() {
Some(MonitorHandle::new(hmonitor))
} else {
None
}
}

impl Window {
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
available_monitors()
Expand All @@ -132,6 +149,10 @@ impl Window {
let monitor = primary_monitor();
Some(RootMonitorHandle { inner: monitor })
}

pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<RootMonitorHandle> {
from_point(x, y).map(|inner| RootMonitorHandle { inner })
}
}

pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<MONITORINFOEXW, io::Error> {
Expand Down
10 changes: 10 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,16 @@ impl Window {
self.window.current_monitor()
}

#[inline]
/// Returns the monitor that contains the given point.
///
/// ## Platform-specific:
///
/// - **Android / iOS:** Unsupported.
pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
self.window.monitor_from_point(x, y)
}

/// Returns the list of all the monitors available on the system.
///
/// This is the same as `EventLoopWindowTarget::available_monitors`, and is provided for convenience.
Expand Down

0 comments on commit c0d5a53

Please sign in to comment.