Skip to content

Commit 8fd49a4

Browse files
Osspialaugust64
authored andcommitted
Add methods to get the position of a window's client area, relative to the desktop (#430)
* Add get_inner_position for windows, prototypes for other platforms * Fix linux builds * Implement get_inner_position for osx * Add get_inner_pos implementations for other platforms * Fixed get_inner_position on macOS * Corrected set_position on macOS * Added CHANGELOG entry
1 parent 1068891 commit 8fd49a4

File tree

10 files changed

+93
-23
lines changed

10 files changed

+93
-23
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
- Properly calculate the minimum and maximum window size on Windows, including window decorations.
1111
- Map more `MouseCursor` variants to cursor icons on Windows.
1212
- Discard the stray mouse down event being delivered after window resize on macOS.
13+
- Corrected `get_position` on macOS to return outer frame position, not content area position.
14+
- Corrected `set_position` on macOS to set outer frame position, not content area position.
15+
- Added `get_inner_position` method to `Window`, which gets the position of the window's client area. This is implemented on all applicable platforms (all desktop platforms other than Wayland, where this isn't possible).
1316

1417
# Version 0.12.0 (2018-04-06)
1518

src/platform/android/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ impl Window {
243243
None
244244
}
245245

246+
#[inline]
247+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
248+
None
249+
}
250+
246251
#[inline]
247252
pub fn set_position(&self, _x: i32, _y: i32) {
248253
}

src/platform/emscripten/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,11 @@ impl Window {
417417
Some((0, 0))
418418
}
419419

420+
#[inline]
421+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
422+
Some((0, 0))
423+
}
424+
420425
#[inline]
421426
pub fn set_position(&self, _: i32, _: i32) {
422427
}

src/platform/ios/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ impl Window {
288288
None
289289
}
290290

291+
#[inline]
292+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
293+
None
294+
}
295+
291296
#[inline]
292297
pub fn set_position(&self, _x: i32, _y: i32) {
293298
}

src/platform/linux/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ impl Window {
162162
}
163163
}
164164

165+
#[inline]
166+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
167+
match self {
168+
&Window::X(ref m) => m.get_inner_position(),
169+
&Window::Wayland(ref m) => m.get_inner_position(),
170+
}
171+
}
172+
165173
#[inline]
166174
pub fn set_position(&self, x: i32, y: i32) {
167175
match self {

src/platform/linux/wayland/window.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ impl Window {
113113
None
114114
}
115115

116+
#[inline]
117+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
118+
// Not possible with wayland
119+
None
120+
}
121+
116122
#[inline]
117123
pub fn set_position(&self, _x: i32, _y: i32) {
118124
// Not possible with wayland

src/platform/linux/x11/window.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,11 @@ impl Window2 {
919919
self.get_geometry().map(|geo| geo.get_position())
920920
}
921921

922+
#[inline]
923+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
924+
self.get_geometry().map(|geo| geo.get_inner_position())
925+
}
926+
922927
pub fn set_position(&self, mut x: i32, mut y: i32) {
923928
if let Some(ref wm_name) = self.wm_name {
924929
// There are a few WMs that set client area position rather than window position, so

src/platform/macos/window.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -543,41 +543,54 @@ impl Window2 {
543543
unsafe { NSWindow::orderOut_(*self.window, nil); }
544544
}
545545

546-
pub fn get_position(&self) -> Option<(i32, i32)> {
547-
unsafe {
548-
let content_rect = NSWindow::contentRectForFrameRect_(*self.window, NSWindow::frame(*self.window));
546+
// For consistency with other platforms, this will...
547+
// 1. translate the bottom-left window corner into the top-left window corner
548+
// 2. translate the coordinate from a bottom-left origin coordinate system to a top-left one
549+
fn bottom_left_to_top_left(rect: NSRect) -> i32 {
550+
(CGDisplay::main().pixels_high() as f64 - (rect.origin.y + rect.size.height)) as _
551+
}
549552

550-
// TODO: consider extrapolating the calculations for the y axis to
551-
// a private method
552-
Some((content_rect.origin.x as i32, (CGDisplay::main().pixels_high() as f64 - (content_rect.origin.y + content_rect.size.height)) as i32))
553-
}
553+
pub fn get_position(&self) -> Option<(i32, i32)> {
554+
let frame_rect = unsafe { NSWindow::frame(*self.window) };
555+
Some((
556+
frame_rect.origin.x as i32,
557+
Self::bottom_left_to_top_left(frame_rect),
558+
))
559+
}
560+
561+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
562+
let content_rect = unsafe {
563+
NSWindow::contentRectForFrameRect_(
564+
*self.window,
565+
NSWindow::frame(*self.window),
566+
)
567+
};
568+
Some((
569+
content_rect.origin.x as i32,
570+
Self::bottom_left_to_top_left(content_rect),
571+
))
554572
}
555573

556574
pub fn set_position(&self, x: i32, y: i32) {
575+
let dummy = NSRect::new(
576+
NSPoint::new(
577+
x as f64,
578+
// While it's true that we're setting the top-left position, it still needs to be
579+
// in a bottom-left coordinate system.
580+
CGDisplay::main().pixels_high() as f64 - y as f64,
581+
),
582+
NSSize::new(0f64, 0f64),
583+
);
557584
unsafe {
558-
let frame = NSWindow::frame(*self.view);
559-
560-
// NOTE: `setFrameOrigin` might not give desirable results when
561-
// setting window, as it treats bottom left as origin.
562-
// `setFrameTopLeftPoint` treats top left as origin (duh), but
563-
// does not equal the value returned by `get_window_position`
564-
// (there is a difference by 22 for me on yosemite)
565-
566-
// TODO: consider extrapolating the calculations for the y axis to
567-
// a private method
568-
let dummy = NSRect::new(NSPoint::new(x as f64, CGDisplay::main().pixels_high() as f64 - (frame.size.height + y as f64)), NSSize::new(0f64, 0f64));
569-
let conv = NSWindow::frameRectForContentRect_(*self.window, dummy);
570-
571-
// NSWindow::setFrameTopLeftPoint_(*self.window, conv.origin);
572-
NSWindow::setFrameOrigin_(*self.window, conv.origin);
585+
NSWindow::setFrameTopLeftPoint_(*self.window, dummy.origin);
573586
}
574587
}
575588

576589
#[inline]
577590
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
591+
let factor = self.hidpi_factor() as f64; // API convention is that size is in physical pixels
578592
unsafe {
579593
let view_frame = NSView::frame(*self.view);
580-
let factor = self.hidpi_factor() as f64; // API convention is that size is in physical pixels
581594
Some(((view_frame.size.width*factor) as u32, (view_frame.size.height*factor) as u32))
582595
}
583596
}

src/platform/windows/window.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ impl Window {
129129
Some((rect.left as i32, rect.top as i32))
130130
}
131131

132+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
133+
use std::mem;
134+
135+
let mut position: POINT = unsafe{ mem::zeroed() };
136+
if unsafe{ winuser::ClientToScreen(self.window.0, &mut position) } == 0 {
137+
return None;
138+
}
139+
140+
Some((position.x, position.y))
141+
}
142+
132143
/// See the docs in the crate root file.
133144
pub fn set_position(&self, x: i32, y: i32) {
134145
unsafe {

src/window.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ impl Window {
181181
self.window.get_position()
182182
}
183183

184+
/// Returns the position of the top-left hand corner of the window's client area relative to the
185+
/// top-left hand corner of the desktop.
186+
///
187+
/// The same conditions that apply to `get_position` apply to this method.
188+
#[inline]
189+
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
190+
self.window.get_inner_position()
191+
}
192+
184193
/// Modifies the position of the window.
185194
///
186195
/// See `get_position` for more information about the coordinates.

0 commit comments

Comments
 (0)