Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow compiling winit to wasm32-unknown-unknown target #2

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Unreleased

# Version 0.19.1 (2019-04-08)

- On Wayland, added a `get_wayland_display` function to `EventsLoopExt`.
- On Windows, fix `CursorMoved(0, 0)` getting dispatched on window focus.
- On macOS, fix command key event left and right reverse.
- On FreeBSD, NetBSD, and OpenBSD, fix build of X11 backend.
- On Windows, fix icon not showing up in corner of window.
- On X11, change DPI scaling factor behavior. First, winit tries to read it from "Xft.dpi" XResource, and uses DPI calculation from xrandr dimensions as fallback behavior.

# Version 0.19.0 (2019-03-06)

- On X11, we will use the faster `XRRGetScreenResourcesCurrent` function instead of `XRRGetScreenResources` when available.
- On macOS, fix keycodes being incorrect when using a non-US keyboard layout.
- On Wayland, fix `with_title()` not setting the windows title
- On Wayland, add `set_wayland_theme()` to control client decoration color theme
Expand All @@ -11,6 +23,10 @@
- On Windows, hiding the cursor no longer hides the cursor for all Winit windows - just the one `hide_cursor` was called on.
- On Windows, cursor grabs used to get perpetually canceled when the grabbing window lost focus. Now, cursor grabs automatically get re-initialized when the window regains focus and the mouse moves over the client area.
- On Windows, only vertical mouse wheel events were handled. Now, horizontal mouse wheel events are also handled.
- On Windows, ignore the AltGr key when populating the `ModifersState` type.
- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes
- On macOS, the numpad's subtract key has been added to the `Subtract` mapping
- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes

# Version 0.18.1 (2018-12-30)

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.18.1"
version = "0.19.1"
authors = ["The winit contributors", "Pierre Krieger <[email protected]>"]
description = "Cross-platform window creation library."
keywords = ["windowing"]
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@

```toml
[dependencies]
winit = "0.18.1"
winit = "0.19.1"
```

## [Documentation](https://docs.rs/winit)

## Contact Us

Join us in any of these:

[![Freenode](https://img.shields.io/badge/freenode.net-%23glutin-red.svg)](http://webchat.freenode.net?channels=%23glutin&uio=MTY9dHJ1ZSYyPXRydWUmND10cnVlJjExPTE4NSYxMj10cnVlJjE1PXRydWU7a)
[![Matrix](https://img.shields.io/badge/Matrix-%23Glutin%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#Glutin:matrix.org)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tomaka/glutin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

## Usage

Winit is a window creation and management library. It can create windows and lets you handle
Expand Down
15 changes: 15 additions & 0 deletions src/os/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ pub trait EventsLoopExt {

#[doc(hidden)]
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;

/// Returns a pointer to the `wl_display` object of wayland that is used by this `EventsLoop`.
///
/// Returns `None` if the `EventsLoop` doesn't use wayland (if it uses xlib for example).
///
/// The pointer will become invalid when the glutin `EventsLoop` is destroyed.
fn get_wayland_display(&self) -> Option<*mut raw::c_void>;
}

impl EventsLoopExt for EventsLoop {
Expand Down Expand Up @@ -152,6 +159,14 @@ impl EventsLoopExt for EventsLoop {
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
self.events_loop.x_connection().cloned()
}

#[inline]
fn get_wayland_display(&self) -> Option<*mut raw::c_void> {
match self.events_loop {
LinuxEventsLoop::Wayland(ref e) => Some(e.get_display().c_ptr() as *mut _),
_ => None
}
}
}

/// Additional methods on `Window` that are specific to Unix.
Expand Down
2 changes: 1 addition & 1 deletion src/platform/emscripten/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(target_os = "emscripten")]
#![cfg(any(target_os = "emscripten", target_arch = "wasm32"))]

mod ffi;

Expand Down
4 changes: 4 additions & 0 deletions src/platform/linux/wayland/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ impl EventsLoop {
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
get_available_monitors(&self.env.outputs)
}

pub fn get_display(&self) -> &Display {
&*self.display
}
}

/*
Expand Down
7 changes: 7 additions & 0 deletions src/platform/linux/wayland/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,13 @@ fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma),
keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter),
keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals),
keysyms::XKB_KEY_KP_Add => Some(VirtualKeyCode::Add),
keysyms::XKB_KEY_KP_Subtract => Some(VirtualKeyCode::Subtract),
keysyms::XKB_KEY_KP_Divide => Some(VirtualKeyCode::Divide),
keysyms::XKB_KEY_KP_Page_Up => Some(VirtualKeyCode::PageUp),
keysyms::XKB_KEY_KP_Page_Down => Some(VirtualKeyCode::PageDown),
keysyms::XKB_KEY_KP_Home => Some(VirtualKeyCode::Home),
keysyms::XKB_KEY_KP_End => Some(VirtualKeyCode::End),
// => Some(VirtualKeyCode::OEM102),
// => Some(VirtualKeyCode::Period),
// => Some(VirtualKeyCode::Playpause),
Expand Down
6 changes: 3 additions & 3 deletions src/platform/linux/x11/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
ffi::XK_KP_Delete => events::VirtualKeyCode::Delete,
ffi::XK_KP_Equal => events::VirtualKeyCode::NumpadEquals,
//ffi::XK_KP_Multiply => events::VirtualKeyCode::NumpadMultiply,
//ffi::XK_KP_Add => events::VirtualKeyCode::NumpadAdd,
ffi::XK_KP_Add => events::VirtualKeyCode::Add,
//ffi::XK_KP_Separator => events::VirtualKeyCode::Kp_separator,
//ffi::XK_KP_Subtract => events::VirtualKeyCode::NumpadSubtract,
ffi::XK_KP_Subtract => events::VirtualKeyCode::Subtract,
//ffi::XK_KP_Decimal => events::VirtualKeyCode::Kp_decimal,
//ffi::XK_KP_Divide => events::VirtualKeyCode::NumpadDivide,
ffi::XK_KP_Divide => events::VirtualKeyCode::Divide,
ffi::XK_KP_0 => events::VirtualKeyCode::Numpad0,
ffi::XK_KP_1 => events::VirtualKeyCode::Numpad1,
ffi::XK_KP_2 => events::VirtualKeyCode::Numpad2,
Expand Down
8 changes: 7 additions & 1 deletion src/platform/linux/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ use std::collections::HashMap;
use std::ffi::CStr;
use std::ops::Deref;
use std::os::raw::*;
use libc::{select, fd_set, FD_SET, FD_ZERO, FD_ISSET, EINTR, EINVAL, ENOMEM, EBADF, __errno_location};
use libc::{select, fd_set, FD_SET, FD_ZERO, FD_ISSET, EINTR, EINVAL, ENOMEM, EBADF};
#[cfg(target_os = "linux")]
use libc::__errno_location;
#[cfg(target_os = "freebsd")]
use libc::__error as __errno_location;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
use libc::__errno as __errno_location;
use std::sync::{Arc, mpsc, Weak};
use std::sync::atomic::{self, AtomicBool};

Expand Down
11 changes: 8 additions & 3 deletions src/platform/linux/x11/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,14 @@ impl XConnection {
fn query_monitor_list(&self) -> Vec<MonitorId> {
unsafe {
let root = (self.xlib.XDefaultRootWindow)(self.display);
// WARNING: this function is supposedly very slow, on the order of hundreds of ms.
// Upon failure, `resources` will be null.
let resources = (self.xrandr.XRRGetScreenResources)(self.display, root);
let resources = if version_is_at_least(1, 3) {
(self.xrandr.XRRGetScreenResourcesCurrent)(self.display, root)
} else {
// WARNING: this function is supposedly very slow, on the order of hundreds of ms.
// Upon failure, `resources` will be null.
(self.xrandr.XRRGetScreenResources)(self.display, root)
};

if resources.is_null() {
panic!("[winit] `XRRGetScreenResources` returned NULL. That should only happen if the root window doesn't exist.");
}
Expand Down
31 changes: 27 additions & 4 deletions src/platform/linux/x11/util/randr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,24 @@ impl From<*mut ffi::XRRCrtcInfo> for MonitorRepr {
}

impl XConnection {
// Retrieve DPI from Xft.dpi property
pub unsafe fn get_xft_dpi(&self) -> Option<f64> {
(self.xlib.XrmInitialize)();
let resource_manager_str = (self.xlib.XResourceManagerString)(self.display);
if resource_manager_str == ptr::null_mut() {
return None;
}
if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() {
let name : &str = "Xft.dpi:\t";
for pair in res.split("\n") {
if pair.starts_with(&name) {
let res = &pair[name.len()..];
return f64::from_str(&res).ok();
}
}
}
None
}
pub unsafe fn get_output_info(
&self,
resources: *mut ffi::XRRScreenResources,
Expand All @@ -101,10 +119,15 @@ impl XConnection {
(*output_info).nameLen as usize,
);
let name = String::from_utf8_lossy(name_slice).into();
let hidpi_factor = calc_dpi_factor(
repr.get_dimensions(),
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
);
let hidpi_factor = if let Some(dpi) = self.get_xft_dpi() {
dpi / 96.
} else {
calc_dpi_factor(
repr.get_dimensions(),
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
)
};

(self.xrandr.XRRFreeOutputInfo)(output_info);
Some((name, hidpi_factor))
}
Expand Down
5 changes: 3 additions & 2 deletions src/platform/macos/events_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,8 @@ pub fn scancode_to_keycode(code: c_ushort) -> Option<events::VirtualKeyCode> {
0x33 => events::VirtualKeyCode::Back,
//0x34 => unkown,
0x35 => events::VirtualKeyCode::Escape,
0x36 => events::VirtualKeyCode::LWin,
0x37 => events::VirtualKeyCode::RWin,
0x36 => events::VirtualKeyCode::RWin,
0x37 => events::VirtualKeyCode::LWin,
0x38 => events::VirtualKeyCode::LShift,
//0x39 => Caps lock,
0x3a => events::VirtualKeyCode::LAlt,
Expand All @@ -683,6 +683,7 @@ pub fn scancode_to_keycode(code: c_ushort) -> Option<events::VirtualKeyCode> {
0x4a => events::VirtualKeyCode::VolumeDown,
0x4b => events::VirtualKeyCode::Divide,
0x4c => events::VirtualKeyCode::NumpadEnter,
0x4e => events::VirtualKeyCode::Subtract,
//0x4d => unkown,
0x4e => events::VirtualKeyCode::Subtract,
0x4f => events::VirtualKeyCode::F18,
Expand Down
5 changes: 3 additions & 2 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ mod platform;
#[cfg(target_os = "ios")]
#[path="ios/mod.rs"]
mod platform;
#[cfg(target_os = "emscripten")]
#[cfg(any(target_os = "emscripten", target_arch = "wasm32"))]
#[path="emscripten/mod.rs"]
mod platform;

#[cfg(all(not(target_os = "ios"), not(target_os = "windows"), not(target_os = "linux"),
not(target_os = "macos"), not(target_os = "android"), not(target_os = "dragonfly"),
not(target_os = "freebsd"), not(target_os = "netbsd"), not(target_os = "openbsd"),
not(target_os = "emscripten")))]
not(target_os = "emscripten"),
not(target_arch = "wasm32")))]
compile_error!("The platform you're compiling for is not supported by winit");
80 changes: 67 additions & 13 deletions src/platform/windows/event.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,85 @@
use std::char;
use std::{char, ptr};
use std::os::raw::c_int;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

use events::VirtualKeyCode;
use events::ModifiersState;

use winapi::shared::minwindef::{WPARAM, LPARAM, UINT};
use winapi::shared::minwindef::{WPARAM, LPARAM, UINT, HKL, HKL__};
use winapi::um::winuser;

use ScanCode;

fn key_pressed(vkey: c_int) -> bool {
unsafe {
(winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15)
}
}

pub fn get_key_mods() -> ModifiersState {
let mut mods = ModifiersState::default();
let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU);

mods.shift = key_pressed(winuser::VK_SHIFT);
mods.ctrl = key_pressed(winuser::VK_CONTROL) && !filter_out_altgr;
mods.alt = key_pressed(winuser::VK_MENU) && !filter_out_altgr;
mods.logo = key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN);
mods
}

unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
let mut unicode_bytes = [0u16; 5];
let len = winuser::ToUnicodeEx(v_key, 0, keyboard_state.as_ptr(), unicode_bytes.as_mut_ptr(), unicode_bytes.len() as _, 0, hkl);
if len >= 1 {
char::decode_utf16(unicode_bytes.into_iter().cloned()).next().and_then(|c| c.ok())
} else {
None
}
}

/// Figures out if the keyboard layout has an AltGr key instead of an Alt key.
///
/// Unfortunately, the Windows API doesn't give a way for us to conveniently figure that out. So,
/// we use a technique blatantly stolen from [the Firefox source code][source]: iterate over every
/// possible virtual key and compare the `char` output when AltGr is pressed vs when it isn't. If
/// pressing AltGr outputs characters that are different from the standard characters, the layout
/// uses AltGr. Otherwise, it doesn't.
///
/// [source]: https://github.com/mozilla/gecko-dev/blob/265e6721798a455604328ed5262f430cfcc37c2f/widget/windows/KeyboardLayout.cpp#L4356-L4416
fn layout_uses_altgr() -> bool {
unsafe {
if winuser::GetKeyState(winuser::VK_SHIFT) & (1 << 15) == (1 << 15) {
mods.shift = true;
}
if winuser::GetKeyState(winuser::VK_CONTROL) & (1 << 15) == (1 << 15) {
mods.ctrl = true;
}
if winuser::GetKeyState(winuser::VK_MENU) & (1 << 15) == (1 << 15) {
mods.alt = true;
static ACTIVE_LAYOUT: AtomicPtr<HKL__> = AtomicPtr::new(ptr::null_mut());
static USES_ALTGR: AtomicBool = AtomicBool::new(false);

let hkl = winuser::GetKeyboardLayout(0);
let old_hkl = ACTIVE_LAYOUT.swap(hkl, Ordering::SeqCst);

if hkl == old_hkl {
return USES_ALTGR.load(Ordering::SeqCst);
}
if (winuser::GetKeyState(winuser::VK_LWIN) | winuser::GetKeyState(winuser::VK_RWIN)) & (1 << 15) == (1 << 15) {
mods.logo = true;

let mut keyboard_state_altgr = [0u8; 256];
// AltGr is an alias for Ctrl+Alt for... some reason. Whatever it is, those are the keypresses
// we have to emulate to do an AltGr test.
keyboard_state_altgr[winuser::VK_MENU as usize] = 0x80;
keyboard_state_altgr[winuser::VK_CONTROL as usize] = 0x80;

let keyboard_state_empty = [0u8; 256];

for v_key in 0..=255 {
let key_noaltgr = get_char(&keyboard_state_empty, v_key, hkl);
let key_altgr = get_char(&keyboard_state_altgr, v_key, hkl);
if let (Some(noaltgr), Some(altgr)) = (key_noaltgr, key_altgr) {
if noaltgr != altgr {
USES_ALTGR.store(true, Ordering::SeqCst);
return true;
}
}
}

USES_ALTGR.store(false, Ordering::SeqCst);
false
}
mods
}

pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
Expand Down
12 changes: 1 addition & 11 deletions src/platform/windows/events_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,22 +1052,12 @@ unsafe fn callback_inner(
}

winuser::WM_SETFOCUS => {
use events::WindowEvent::{Focused, CursorMoved};
use events::WindowEvent::Focused;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Focused(true)
});

let x = windowsx::GET_X_LPARAM(lparam) as f64;
let y = windowsx::GET_Y_LPARAM(lparam) as f64;
let dpi_factor = get_hwnd_scale_factor(window);
let position = LogicalPosition::from_physical((x, y), dpi_factor);

send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
});

0
},

Expand Down
3 changes: 0 additions & 3 deletions src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,9 +625,6 @@ unsafe fn init(
format!("{}", io::Error::last_os_error()))));
}

winuser::SetWindowLongW(handle, winuser::GWL_STYLE, 0);
winuser::SetWindowLongW(handle, winuser::GWL_EXSTYLE, 0);

WindowWrapper(handle)
};

Expand Down
2 changes: 1 addition & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ impl MonitorId {
///
/// ## Platform-specific
///
/// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable.
/// - **X11:** This respects Xft.dpi XResource, and can be overridden using the `WINIT_HIDPI_FACTOR` environment variable.
/// - **Android:** Always returns 1.0.
#[inline]
pub fn get_hidpi_factor(&self) -> f64 {
Expand Down