Skip to content

Commit

Permalink
Merge branch 'master' into macos-fix-ReceivedCharacter
Browse files Browse the repository at this point in the history
  • Loading branch information
hatoo committed Jan 4, 2020
2 parents 077962a + d1c6506 commit 22a8f6f
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 50 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Unreleased

- On macOS, fix not sending ReceivedCharacter event for specific keys combinations.
- On X11, fix `ModifiersChanged` emitting incorrect modifier change events

# 0.20.0 Alpha 6 (2020-01-03)

- On macOS, fix `set_cursor_visible` hides cursor outside of window.
- On macOS, fix `CursorEntered` and `CursorLeft` events fired at old window size.
- On macOS, fix error when `set_fullscreen` is called during fullscreen transition.
- On all platforms except mobile and WASM, implement `Window::set_minimized`.
Expand All @@ -23,6 +28,8 @@
- On Windows, fix `Window::set_visible` not setting internal flags correctly. This resulted in some weird behavior.
- Add `DeviceEvent::ModifiersChanged`.
- Deprecate `modifiers` fields in other events in favor of `ModifiersChanged`.
- On X11, `WINIT_HIDPI_FACTOR` now dominates `Xft.dpi` when picking DPI factor for output.
- On X11, add special value `randr` for `WINIT_HIDPI_FACTOR` to make winit use self computed DPI factor instead of the one from `Xft.dpi`.

# 0.20.0 Alpha 5 (2019-12-09)

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "winit"
version = "0.20.0-alpha5"
version = "0.20.0-alpha6"
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
description = "Cross-platform window creation library."
edition = "2018"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

```toml
[dependencies]
winit = "0.20.0-alpha5"
winit = "0.20.0-alpha6"
```

## [Documentation](https://docs.rs/winit)
Expand Down
6 changes: 3 additions & 3 deletions src/platform_impl/linux/x11/util/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ impl ModifiersState {

pub(crate) fn from_x11_mask(mask: c_uint) -> Self {
let mut m = ModifiersState::empty();
m.set(ModifiersState::SHIFT, mask & ffi::Mod1Mask != 0);
m.set(ModifiersState::CTRL, mask & ffi::ShiftMask != 0);
m.set(ModifiersState::ALT, mask & ffi::ControlMask != 0);
m.set(ModifiersState::ALT, mask & ffi::Mod1Mask != 0);
m.set(ModifiersState::SHIFT, mask & ffi::ShiftMask != 0);
m.set(ModifiersState::CTRL, mask & ffi::ControlMask != 0);
m.set(ModifiersState::LOGO, mask & ffi::Mod4Mask != 0);
m
}
Expand Down
70 changes: 51 additions & 19 deletions src/platform_impl/linux/x11/util/randr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,17 @@ use super::{
};
use crate::{dpi::validate_hidpi_factor, platform_impl::platform::x11::VideoMode};

/// Represents values of `WINIT_HIDPI_FACTOR`.
pub enum EnvVarDPI {
Randr,
Scale(f64),
NotSet,
}

pub fn calc_dpi_factor(
(width_px, height_px): (u32, u32),
(width_mm, height_mm): (u64, u64),
) -> f64 {
// Override DPI if `WINIT_HIDPI_FACTOR` variable is set
let dpi_override = env::var("WINIT_HIDPI_FACTOR")
.ok()
.and_then(|var| f64::from_str(&var).ok());
if let Some(dpi_override) = dpi_override {
if !validate_hidpi_factor(dpi_override) {
panic!(
"`WINIT_HIDPI_FACTOR` invalid; DPI factors must be normal floats greater than 0. Got `{}`",
dpi_override,
);
}
return dpi_override;
}

// See http://xpra.org/trac/ticket/728 for more information.
if width_mm == 0 || height_mm == 0 {
warn!("XRandR reported that the display's 0mm in size, which is certifiably insane");
Expand Down Expand Up @@ -107,16 +100,55 @@ impl XConnection {
(*output_info).nameLen as usize,
);
let name = String::from_utf8_lossy(name_slice).into();
let hidpi_factor = if let Some(dpi) = self.get_xft_dpi() {
dpi / 96.
} else {
calc_dpi_factor(
// Override DPI if `WINIT_HIDPI_FACTOR` variable is set
let dpi_env = env::var("WINIT_HIDPI_FACTOR").ok().map_or_else(
|| EnvVarDPI::NotSet,
|var| {
if var.to_lowercase() == "randr" {
EnvVarDPI::Randr
} else if let Ok(dpi) = f64::from_str(&var) {
EnvVarDPI::Scale(dpi)
} else if var.is_empty() {
EnvVarDPI::NotSet
} else {
panic!(
"`WINIT_HIDPI_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{}`",
var
);
}
},
);

let hidpi_factor = match dpi_env {
EnvVarDPI::Randr => calc_dpi_factor(
((*crtc).width as u32, (*crtc).height as u32),
(
(*output_info).mm_width as u64,
(*output_info).mm_height as u64,
),
)
),
EnvVarDPI::Scale(dpi_override) => {
if !validate_hidpi_factor(dpi_override) {
panic!(
"`WINIT_HIDPI_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{}`",
dpi_override,
);
}
dpi_override
}
EnvVarDPI::NotSet => {
if let Some(dpi) = self.get_xft_dpi() {
dpi / 96.
} else {
calc_dpi_factor(
((*crtc).width as u32, (*crtc).height as u32),
(
(*output_info).mm_width as u64,
(*output_info).mm_height as u64,
),
)
}
}
};

(self.xrandr.XRRFreeOutputInfo)(output_info);
Expand Down
38 changes: 37 additions & 1 deletion src/platform_impl/macos/util/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use cocoa::{
base::{id, nil},
foundation::{NSDictionary, NSPoint, NSString},
};
use objc::runtime::Sel;
use objc::{runtime::Sel, runtime::NO};
use std::cell::RefCell;

use crate::window::CursorIcon;

Expand Down Expand Up @@ -126,3 +127,38 @@ pub unsafe fn load_webkit_cursor(cursor_name: &str) -> id {
hotSpot:point
]
}

pub unsafe fn invisible_cursor() -> id {
// 16x16 GIF data for invisible cursor
// You can reproduce this via ImageMagick.
// $ convert -size 16x16 xc:none cursor.gif
static CURSOR_BYTES: &[u8] = &[
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x10, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x84, 0x8F, 0xA9, 0xCB, 0xED, 0x0F,
0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B,
];

thread_local! {
// We can't initialize this at startup.
static CURSOR_OBJECT: RefCell<id> = RefCell::new(nil);
}

CURSOR_OBJECT.with(|cursor_obj| {
if *cursor_obj.borrow() == nil {
// Create a cursor from `CURSOR_BYTES`
let cursor_data: id = msg_send![class!(NSData),
dataWithBytesNoCopy:CURSOR_BYTES as *const [u8]
length:CURSOR_BYTES.len()
freeWhenDone:NO
];

let ns_image: id = msg_send![class!(NSImage), alloc];
let _: id = msg_send![ns_image, initWithData: cursor_data];
let cursor: id = msg_send![class!(NSCursor), alloc];
*cursor_obj.borrow_mut() =
msg_send![cursor, initWithImage:ns_image hotSpot: NSPoint::new(0.0, 0.0)];
}
*cursor_obj.borrow()
})
}
31 changes: 25 additions & 6 deletions src/platform_impl/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,36 @@ use crate::{
window::WindowId,
};

pub struct CursorState {
pub visible: bool,
pub cursor: util::Cursor,
}

impl Default for CursorState {
fn default() -> Self {
Self {
visible: true,
cursor: Default::default(),
}
}
}

struct ViewState {
ns_window: id,
pub cursor: Arc<Mutex<util::Cursor>>,
pub cursor_state: Arc<Mutex<CursorState>>,
ime_spot: Option<(f64, f64)>,
raw_characters: Option<String>,
is_key_down: bool,
modifiers: ModifiersState,
tracking_rect: Option<NSInteger>,
}

pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<util::Cursor>>) {
let cursor = Default::default();
let cursor_access = Arc::downgrade(&cursor);
pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
let cursor_state = Default::default();
let cursor_access = Arc::downgrade(&cursor_state);
let state = ViewState {
ns_window,
cursor,
cursor_state,
ime_spot: None,
raw_characters: None,
is_key_down: false,
Expand Down Expand Up @@ -349,7 +363,12 @@ extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
let state = &mut *(state_ptr as *mut ViewState);

let bounds: NSRect = msg_send![this, bounds];
let cursor = state.cursor.lock().unwrap().load();
let cursor_state = state.cursor_state.lock().unwrap();
let cursor = if cursor_state.visible {
cursor_state.cursor.load()
} else {
util::invisible_cursor()
};
let _: () = msg_send![this,
addCursorRect:bounds
cursor:cursor
Expand Down
38 changes: 19 additions & 19 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
ffi,
monitor::{self, MonitorHandle, VideoMode},
util::{self, IdRef},
view::CursorState,
view::{self, new_view},
window_delegate::new_delegate,
OsError,
Expand Down Expand Up @@ -90,8 +91,8 @@ fn create_app(activation_policy: ActivationPolicy) -> Option<id> {
unsafe fn create_view(
ns_window: id,
pl_attribs: &PlatformSpecificWindowBuilderAttributes,
) -> Option<(IdRef, Weak<Mutex<util::Cursor>>)> {
let (ns_view, cursor) = new_view(ns_window);
) -> Option<(IdRef, Weak<Mutex<CursorState>>)> {
let (ns_view, cursor_state) = new_view(ns_window);
ns_view.non_nil().map(|ns_view| {
if !pl_attribs.disallow_hidpi {
ns_view.setWantsBestResolutionOpenGLSurface_(YES);
Expand All @@ -108,7 +109,7 @@ unsafe fn create_view(

ns_window.setContentView_(*ns_view);
ns_window.makeFirstResponder_(*ns_view);
(ns_view, cursor)
(ns_view, cursor_state)
})
}

Expand Down Expand Up @@ -290,8 +291,7 @@ pub struct UnownedWindow {
input_context: IdRef, // never changes
pub shared_state: Arc<Mutex<SharedState>>,
decorations: AtomicBool,
cursor: Weak<Mutex<util::Cursor>>,
cursor_visible: AtomicBool,
cursor_state: Weak<Mutex<CursorState>>,
}

unsafe impl Send for UnownedWindow {}
Expand Down Expand Up @@ -320,7 +320,7 @@ impl UnownedWindow {
os_error!(OsError::CreationError("Couldn't create `NSWindow`"))
})?;

let (ns_view, cursor) =
let (ns_view, cursor_state) =
unsafe { create_view(*ns_window, &pl_attribs) }.ok_or_else(|| {
unsafe { pool.drain() };
os_error!(OsError::CreationError("Couldn't create `NSView`"))
Expand Down Expand Up @@ -368,8 +368,7 @@ impl UnownedWindow {
input_context,
shared_state: Arc::new(Mutex::new(win_attribs.into())),
decorations: AtomicBool::new(decorations),
cursor,
cursor_visible: AtomicBool::new(true),
cursor_state,
});

let delegate = new_delegate(&window, fullscreen.is_some());
Expand Down Expand Up @@ -516,8 +515,8 @@ impl UnownedWindow {

pub fn set_cursor_icon(&self, cursor: CursorIcon) {
let cursor = util::Cursor::from(cursor);
if let Some(cursor_access) = self.cursor.upgrade() {
*cursor_access.lock().unwrap() = cursor;
if let Some(cursor_access) = self.cursor_state.upgrade() {
cursor_access.lock().unwrap().cursor = cursor;
}
unsafe {
let _: () = msg_send![*self.ns_window,
Expand All @@ -535,16 +534,17 @@ impl UnownedWindow {

#[inline]
pub fn set_cursor_visible(&self, visible: bool) {
let cursor_class = class!(NSCursor);
// macOS uses a "hide counter" like Windows does, so we avoid incrementing it more than once.
// (otherwise, `hide_cursor(false)` would need to be called n times!)
if visible != self.cursor_visible.load(Ordering::Acquire) {
if visible {
let _: () = unsafe { msg_send![cursor_class, unhide] };
} else {
let _: () = unsafe { msg_send![cursor_class, hide] };
if let Some(cursor_access) = self.cursor_state.upgrade() {
let mut cursor_state = cursor_access.lock().unwrap();
if visible != cursor_state.visible {
cursor_state.visible = visible;
drop(cursor_state);
unsafe {
let _: () = msg_send![*self.ns_window,
invalidateCursorRectsForView:*self.ns_view
];
}
}
self.cursor_visible.store(visible, Ordering::Release);
}
}

Expand Down

0 comments on commit 22a8f6f

Please sign in to comment.