diff --git a/.travis.yml b/.travis.yml
index 6f259699..486fc727 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,8 @@ rust:
- nightly
- stable
+cache: cargo
+
addons:
apt:
packages:
@@ -18,14 +20,6 @@ os:
- osx
after_success:
- - |
- [ $TRAVIS_BRANCH = master ] &&
- [ $TRAVIS_PULL_REQUEST = false ] &&
- cargo doc &&
- echo '' > target/doc/index.html &&
- sudo pip install ghp-import &&
- ghp-import -n target/doc &&
- git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
- |
[ $TRAVIS_BRANCH = master ] &&
[ $TRAVIS_PULL_REQUEST = false ] &&
diff --git a/Cargo.toml b/Cargo.toml
index e473053f..b2af1c94 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,27 +7,30 @@ keywords = ["windowing"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/tomaka/winit"
-documentation = "https://tomaka.github.io/winit/"
+documentation = "https://docs.rs/winit"
[dependencies]
-lazy_static = "0.1.10"
+lazy_static = "0.2.0"
libc = "0.2"
shared_library = "0.1.0"
-[target.arm-linux-androideabi.dependencies.android_glue]
+# [build-dependencies]
+# gl_generator = "0.5"
+
+[target.'cfg(target_os = "android")'.dependencies.android_glue]
version = "0.2"
-[target.'cfg(target_os="ios")'.dependencies]
+[target.'cfg(target_os = "ios")'.dependencies]
objc = "0.2"
-[target.'cfg(target_os="macos")'.dependencies]
+[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
cgl = "0.1"
-cocoa = "0.3"
+cocoa = "0.3.2"
core-foundation = "0"
core-graphics = "0.3"
-[target.'cfg(windows)'.dependencies]
+[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.2"
shell32-sys = "0.1"
gdi32-sys = "0.1"
diff --git a/README.md b/README.md
index ca079cbb..546a187f 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
[![](http://meritbadge.herokuapp.com/glutin)](https://crates.io/crates/glutin)
+[![Docs.rs](https://docs.rs/glutin/badge.svg)](https://docs.rs/glutin)
+
Alternative to GLFW in pure Rust.
[![Build Status](https://travis-ci.org/tomaka/glutin.png?branch=master)](https://travis-ci.org/tomaka/glutin)
@@ -13,7 +15,7 @@ Alternative to GLFW in pure Rust.
glutin = "*"
```
-## [Documentation](http://tomaka.github.io/glutin/)
+## [Documentation](https://docs.rs/glutin)
## Try it!
diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs
index 70f357e8..5ed2ecbc 100644
--- a/examples/fullscreen.rs
+++ b/examples/fullscreen.rs
@@ -30,7 +30,7 @@ fn main() {
};
let window = winit::WindowBuilder::new()
- .with_title("Hello world!".to_string())
+ .with_title("Hello world!")
.with_fullscreen(monitor)
.build()
.unwrap();
diff --git a/examples/grabbing.rs b/examples/grabbing.rs
index ec08eac5..6a1c47cf 100644
--- a/examples/grabbing.rs
+++ b/examples/grabbing.rs
@@ -31,7 +31,7 @@ fn main() {
Event::Closed => break,
- a @ Event::MouseMoved(_) => {
+ a @ Event::MouseMoved(_, _) => {
println!("{:?}", a);
},
diff --git a/src/api/android/ffi.rs b/src/api/android/ffi.rs
index 1398b772..af8c50b3 100644
--- a/src/api/android/ffi.rs
+++ b/src/api/android/ffi.rs
@@ -4,6 +4,7 @@
#![allow(non_upper_case_globals)]
use libc;
+use std::os::raw;
#[link(name = "android")]
#[link(name = "EGL")]
@@ -13,12 +14,12 @@ extern {}
/**
* asset_manager.h
*/
-pub type AAssetManager = ();
+pub type AAssetManager = raw::c_void;
/**
* native_window.h
*/
-pub type ANativeWindow = ();
+pub type ANativeWindow = raw::c_void;
extern {
pub fn ANativeWindow_getHeight(window: *const ANativeWindow) -> libc::int32_t;
diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs
index d1d2053b..d3973481 100644
--- a/src/api/android/mod.rs
+++ b/src/api/android/mod.rs
@@ -56,9 +56,9 @@ impl MonitorId {
}
}
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
pub struct PollEventsIterator<'a> {
diff --git a/src/api/cocoa/mod.rs b/src/api/cocoa/mod.rs
index 23a6e2a1..186578d7 100644
--- a/src/api/cocoa/mod.rs
+++ b/src/api/cocoa/mod.rs
@@ -6,6 +6,7 @@ use libc;
use WindowAttributes;
use native_monitor::NativeMonitorId;
+use os::macos::ActivationPolicy;
use objc::runtime::{Class, Object, Sel, BOOL, YES, NO};
use objc::declare::ClassDecl;
@@ -15,9 +16,7 @@ use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions, CGLSetParameter, kCGLCPSurfa
use cocoa::base::{id, nil};
use cocoa::foundation::{NSAutoreleasePool, NSDate, NSDefaultRunLoopMode, NSPoint, NSRect, NSSize,
NSString, NSUInteger};
-use cocoa::appkit;
-use cocoa::appkit::*;
-use cocoa::appkit::NSEventSubtype::*;
+use cocoa::appkit::{self, NSApplication, NSEvent, NSOpenGLContext, NSOpenGLPixelFormat, NSView, NSWindow};
use core_foundation::base::TCFType;
use core_foundation::string::CFString;
@@ -30,12 +29,9 @@ use std::collections::VecDeque;
use std::str::FromStr;
use std::str::from_utf8;
use std::sync::Mutex;
-use std::ascii::AsciiExt;
use std::ops::Deref;
-use events::ElementState::{Pressed, Released};
-use events::Event::{Awakened, MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput};
-use events::Event::{MouseWheel, Closed, Focused, TouchpadPressure};
+use events::ElementState;
use events::{self, MouseButton, TouchPhase};
pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};
@@ -72,7 +68,7 @@ impl WindowDelegate {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = state as *mut DelegateState;
- (*state).pending_events.lock().unwrap().push_back(Closed);
+ (*state).pending_events.lock().unwrap().push_back(Event::Closed);
}
YES
}
@@ -101,7 +97,7 @@ impl WindowDelegate {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = state as *mut DelegateState;
- (*state).pending_events.lock().unwrap().push_back(Focused(true));
+ (*state).pending_events.lock().unwrap().push_back(Event::Focused(true));
}
}
@@ -109,7 +105,7 @@ impl WindowDelegate {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = state as *mut DelegateState;
- (*state).pending_events.lock().unwrap().push_back(Focused(false));
+ (*state).pending_events.lock().unwrap().push_back(Event::Focused(false));
}
}
@@ -167,8 +163,10 @@ impl Drop for WindowDelegate {
}
}
-#[derive(Default)]
-pub struct PlatformSpecificWindowBuilderAttributes;
+#[derive(Clone, Default)]
+pub struct PlatformSpecificWindowBuilderAttributes {
+ pub activation_policy: ActivationPolicy,
+}
pub struct Window {
view: IdRef,
@@ -188,9 +186,9 @@ impl WindowProxy {
let pool = NSAutoreleasePool::new(nil);
let event =
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
- nil, NSApplicationDefined, NSPoint::new(0.0, 0.0), NSEventModifierFlags::empty(),
- 0.0, 0, nil, NSApplicationActivatedEventType, 0, 0);
- NSApp().postEvent_atStart_(event, NO);
+ nil, appkit::NSApplicationDefined, NSPoint::new(0.0, 0.0), appkit::NSEventModifierFlags::empty(),
+ 0.0, 0, nil, appkit::NSEventSubtype::NSApplicationActivatedEventType, 0, 0);
+ appkit::NSApp().postEvent_atStart_(event, NO);
pool.drain();
}
}
@@ -212,8 +210,8 @@ impl<'a> Iterator for PollEventsIterator<'a> {
unsafe {
let pool = NSAutoreleasePool::new(nil);
- let nsevent = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
- NSAnyEventMask.bits() | NSEventMaskPressure.bits(),
+ let nsevent = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
+ appkit::NSAnyEventMask.bits() | appkit::NSEventMaskPressure.bits(),
NSDate::distantPast(nil),
NSDefaultRunLoopMode,
YES);
@@ -241,8 +239,8 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
unsafe {
let pool = NSAutoreleasePool::new(nil);
- let nsevent = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
- NSAnyEventMask.bits() | NSEventMaskPressure.bits(),
+ let nsevent = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
+ appkit::NSAnyEventMask.bits() | appkit::NSEventMaskPressure.bits(),
NSDate::distantFuture(nil),
NSDefaultRunLoopMode,
YES);
@@ -252,7 +250,7 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
}
if event.is_none() {
- return Some(Awakened);
+ return Some(Event::Awakened);
} else {
return event;
}
@@ -261,14 +259,15 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
impl Window {
pub fn new(win_attribs: &WindowAttributes,
- _: &PlatformSpecificWindowBuilderAttributes)
- -> Result
+ pl_attribs: &PlatformSpecificWindowBuilderAttributes)
+ -> Result
{
// not implemented
assert!(win_attribs.min_dimensions.is_none());
assert!(win_attribs.max_dimensions.is_none());
- let app = match Window::create_app() {
+ // let app = match Window::create_app() {
+ let app = match Window::create_app(pl_attribs.activation_policy) {
Some(app) => app,
None => { return Err(OsError(format!("Couldn't create NSApplication"))); },
};
@@ -312,13 +311,13 @@ impl Window {
Ok(window)
}
- fn create_app() -> Option {
+ fn create_app(activation_policy: ActivationPolicy) -> Option {
unsafe {
- let app = NSApp();
+ let app = appkit::NSApp();
if app == nil {
None
} else {
- app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
+ app.setActivationPolicy_(activation_policy.into());
app.finishLaunching();
Some(app)
}
@@ -334,13 +333,13 @@ impl Window {
_ => panic!("OS X monitors should always have a numeric native ID")
};
let matching_screen = {
- let screens = NSScreen::screens(nil);
+ let screens = appkit::NSScreen::screens(nil);
let count: NSUInteger = msg_send![screens, count];
let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber"));
let mut matching_screen: Option = None;
for i in 0..count {
let screen = msg_send![screens, objectAtIndex:i as NSUInteger];
- let device_description = NSScreen::deviceDescription(screen);
+ let device_description = appkit::NSScreen::deviceDescription(screen);
let value: id = msg_send![device_description, objectForKey:*key];
if value != nil {
let screen_number: NSUInteger = msg_send![value, unsignedIntegerValue];
@@ -352,12 +351,12 @@ impl Window {
}
matching_screen
};
- Some(matching_screen.unwrap_or(NSScreen::mainScreen(nil)))
+ Some(matching_screen.unwrap_or(appkit::NSScreen::mainScreen(nil)))
},
None => None
};
let frame = match screen {
- Some(screen) => NSScreen::frame(screen),
+ Some(screen) => appkit::NSScreen::frame(screen),
None => {
let (width, height) = attrs.dimensions.unwrap_or((800, 600));
NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64))
@@ -366,42 +365,43 @@ impl Window {
let masks = if screen.is_some() || attrs.transparent {
// Fullscreen or transparent window
- NSBorderlessWindowMask as NSUInteger |
- NSResizableWindowMask as NSUInteger |
- NSTitledWindowMask as NSUInteger
+ appkit::NSBorderlessWindowMask as NSUInteger |
+ appkit::NSResizableWindowMask as NSUInteger |
+ appkit::NSTitledWindowMask as NSUInteger
} else if attrs.decorations {
// Classic opaque window with titlebar
- NSClosableWindowMask as NSUInteger |
- NSMiniaturizableWindowMask as NSUInteger |
- NSResizableWindowMask as NSUInteger |
- NSTitledWindowMask as NSUInteger
+ appkit::NSClosableWindowMask as NSUInteger |
+ appkit::NSMiniaturizableWindowMask as NSUInteger |
+ appkit::NSResizableWindowMask as NSUInteger |
+ appkit::NSTitledWindowMask as NSUInteger
} else {
// Opaque window without a titlebar
- NSClosableWindowMask as NSUInteger |
- NSMiniaturizableWindowMask as NSUInteger |
- NSResizableWindowMask as NSUInteger |
- NSTitledWindowMask as NSUInteger |
- NSFullSizeContentViewWindowMask as NSUInteger
+ appkit::NSClosableWindowMask as NSUInteger |
+ appkit::NSMiniaturizableWindowMask as NSUInteger |
+ appkit::NSResizableWindowMask as NSUInteger |
+ appkit::NSTitledWindowMask as NSUInteger |
+ appkit::NSFullSizeContentViewWindowMask as NSUInteger
};
let window = IdRef::new(NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
frame,
masks,
- NSBackingStoreBuffered,
+ appkit::NSBackingStoreBuffered,
NO,
));
window.non_nil().map(|window| {
let title = IdRef::new(NSString::alloc(nil).init_str(&attrs.title));
+ window.setReleasedWhenClosed_(NO);
window.setTitle_(*title);
window.setAcceptsMouseMovedEvents_(YES);
if !attrs.decorations {
- window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden);
+ window.setTitleVisibility_(appkit::NSWindowTitleVisibility::NSWindowTitleHidden);
window.setTitlebarAppearsTransparent_(YES);
}
if screen.is_some() {
- window.setLevel_(NSMainMenuWindowLevel as i64 + 1);
+ window.setLevel_(appkit::NSMainMenuWindowLevel as i64 + 1);
}
else {
window.center();
@@ -511,11 +511,11 @@ impl Window {
}
}
- unsafe fn modifier_event(event: id, keymask: NSEventModifierFlags, key: events::VirtualKeyCode, key_pressed: bool) -> Option {
+ unsafe fn modifier_event(event: id, keymask: appkit::NSEventModifierFlags, key: events::VirtualKeyCode, key_pressed: bool) -> Option {
if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) {
- return Some(KeyboardInput(Pressed, NSEvent::keyCode(event) as u8, Some(key)));
+ return Some(Event::KeyboardInput(ElementState::Pressed, NSEvent::keyCode(event) as u8, Some(key)));
} else if key_pressed && !NSEvent::modifierFlags(event).contains(keymask) {
- return Some(KeyboardInput(Released, NSEvent::keyCode(event) as u8, Some(key)));
+ return Some(Event::KeyboardInput(ElementState::Released, NSEvent::keyCode(event) as u8, Some(key)));
}
return None;
@@ -609,7 +609,10 @@ impl Window {
unsafe {
// TODO: Check for errors.
- let _ = CGWarpMouseCursorPosition(CGPoint { x: cursor_x as CGFloat, y: cursor_y as CGFloat });
+ let _ = CGWarpMouseCursorPosition(appkit::CGPoint {
+ x: cursor_x as appkit::CGFloat,
+ y: cursor_y as appkit::CGFloat,
+ });
let _ = CGAssociateMouseAndMouseCursorPosition(true);
}
@@ -661,22 +664,22 @@ impl Clone for IdRef {
}
}
-#[allow(non_snake_case)]
+#[allow(non_snake_case, non_upper_case_globals)]
unsafe fn NSEventToEvent(window: &Window, nsevent: id) -> Option {
if nsevent == nil { return None; }
let event_type = nsevent.eventType();
- NSApp().sendEvent_(if let NSKeyDown = event_type { nil } else { nsevent });
+ appkit::NSApp().sendEvent_(if let appkit::NSKeyDown = event_type { nil } else { nsevent });
match event_type {
- NSLeftMouseDown => { Some(MouseInput(Pressed, MouseButton::Left)) },
- NSLeftMouseUp => { Some(MouseInput(Released, MouseButton::Left)) },
- NSRightMouseDown => { Some(MouseInput(Pressed, MouseButton::Right)) },
- NSRightMouseUp => { Some(MouseInput(Released, MouseButton::Right)) },
- NSMouseMoved |
- NSLeftMouseDragged |
- NSOtherMouseDragged |
- NSRightMouseDragged => {
+ appkit::NSLeftMouseDown => { Some(Event::MouseInput(ElementState::Pressed, MouseButton::Left)) },
+ appkit::NSLeftMouseUp => { Some(Event::MouseInput(ElementState::Released, MouseButton::Left)) },
+ appkit::NSRightMouseDown => { Some(Event::MouseInput(ElementState::Pressed, MouseButton::Right)) },
+ appkit::NSRightMouseUp => { Some(Event::MouseInput(ElementState::Released, MouseButton::Right)) },
+ appkit::NSMouseMoved |
+ appkit::NSLeftMouseDragged |
+ appkit::NSOtherMouseDragged |
+ appkit::NSRightMouseDragged => {
let window_point = nsevent.locationInWindow();
let cWindow: id = msg_send![nsevent, window];
let view_point = if cWindow == nil {
@@ -688,29 +691,29 @@ unsafe fn NSEventToEvent(window: &Window, nsevent: id) -> Option {
let view_rect = NSView::frame(*window.view);
let scale_factor = window.hidpi_factor();
- Some(MouseMoved(((scale_factor * view_point.x as f32) as i32,
- (scale_factor * (view_rect.size.height - view_point.y) as f32) as i32)))
+ Some(Event::MouseMoved((scale_factor * view_point.x as f32) as i32,
+ (scale_factor * (view_rect.size.height - view_point.y) as f32) as i32))
},
- NSKeyDown => {
+ appkit::NSKeyDown => {
let mut events = VecDeque::new();
let received_c_str = nsevent.characters().UTF8String();
let received_str = CStr::from_ptr(received_c_str);
for received_char in from_utf8(received_str.to_bytes()).unwrap().chars() {
- events.push_back(ReceivedCharacter(received_char));
+ events.push_back(Event::ReceivedCharacter(received_char));
}
let vkey = event::vkeycode_to_element(NSEvent::keyCode(nsevent));
- events.push_back(KeyboardInput(Pressed, NSEvent::keyCode(nsevent) as u8, vkey));
+ events.push_back(Event::KeyboardInput(ElementState::Pressed, NSEvent::keyCode(nsevent) as u8, vkey));
let event = events.pop_front();
window.delegate.state.pending_events.lock().unwrap().extend(events.into_iter());
event
},
- NSKeyUp => {
+ appkit::NSKeyUp => {
let vkey = event::vkeycode_to_element(NSEvent::keyCode(nsevent));
- Some(KeyboardInput(Released, NSEvent::keyCode(nsevent) as u8, vkey))
+ Some(Event::KeyboardInput(ElementState::Released, NSEvent::keyCode(nsevent) as u8, vkey))
},
- NSFlagsChanged => {
+ appkit::NSFlagsChanged => {
let mut events = VecDeque::new();
let shift_modifier = Window::modifier_event(nsevent, appkit::NSShiftKeyMask, events::VirtualKeyCode::LShift, shift_pressed);
if shift_modifier.is_some() {
@@ -736,7 +739,7 @@ unsafe fn NSEventToEvent(window: &Window, nsevent: id) -> Option {
window.delegate.state.pending_events.lock().unwrap().extend(events.into_iter());
event
},
- NSScrollWheel => {
+ appkit::NSScrollWheel => {
use events::MouseScrollDelta::{LineDelta, PixelDelta};
let scale_factor = window.hidpi_factor();
let delta = if nsevent.hasPreciseScrollingDeltas() == YES {
@@ -747,14 +750,14 @@ unsafe fn NSEventToEvent(window: &Window, nsevent: id) -> Option {
scale_factor * nsevent.scrollingDeltaY() as f32)
};
let phase = match nsevent.phase() {
- NSEventPhaseMayBegin | NSEventPhaseBegan => TouchPhase::Started,
- NSEventPhaseEnded => TouchPhase::Ended,
+ appkit::NSEventPhaseMayBegin | appkit::NSEventPhaseBegan => TouchPhase::Started,
+ appkit::NSEventPhaseEnded => TouchPhase::Ended,
_ => TouchPhase::Moved,
};
- Some(MouseWheel(delta, phase))
+ Some(Event::MouseWheel(delta, phase))
},
- NSEventTypePressure => {
- Some(TouchpadPressure(nsevent.pressure(), nsevent.stage()))
+ appkit::NSEventTypePressure => {
+ Some(Event::TouchpadPressure(nsevent.pressure(), nsevent.stage()))
},
_ => { None },
}
diff --git a/src/api/ios/mod.rs b/src/api/ios/mod.rs
index afcc6f42..8bee5134 100644
--- a/src/api/ios/mod.rs
+++ b/src/api/ios/mod.rs
@@ -177,7 +177,7 @@ impl MonitorId {
}
}
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
impl Window {
diff --git a/src/api/wayland/events.rs b/src/api/wayland/events.rs
index 5e0c3fd0..92a0b95f 100644
--- a/src/api/wayland/events.rs
+++ b/src/api/wayland/events.rs
@@ -52,7 +52,7 @@ pub fn translate_event(
if known_surfaces.contains(&surface) {
focuses.pointer_on = Some(surface);
focuses.pointer_at = Some((x, y));
- Some((GlutinEvent::MouseMoved((x as i32, y as i32)), surface))
+ Some((GlutinEvent::MouseMoved(x as i32, y as i32), surface))
} else {
None
}
@@ -65,7 +65,7 @@ pub fn translate_event(
WlPointerEvent::Motion(_, x, y) => {
if let Some(surface) = focuses.pointer_on {
focuses.pointer_at = Some((x, y));
- Some((GlutinEvent::MouseMoved((x as i32, y as i32)), surface))
+ Some((GlutinEvent::MouseMoved(x as i32, y as i32), surface))
} else {
None
}
diff --git a/src/api/win32/callback.rs b/src/api/win32/callback.rs
index e2b74121..6f6bd2cb 100644
--- a/src/api/win32/callback.rs
+++ b/src/api/win32/callback.rs
@@ -136,15 +136,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
let x = winapi::GET_X_LPARAM(lparam) as i32;
let y = winapi::GET_Y_LPARAM(lparam) as i32;
- let mut mouse_track = winapi::TRACKMOUSEEVENT {
- cbSize: mem::size_of::() as winapi::DWORD,
- dwFlags: winapi::TME_HOVER | winapi::TME_LEAVE,
- hwndTrack: window,
- dwHoverTime: winapi::HOVER_DEFAULT
- };
- user32::TrackMouseEvent(&mut mouse_track);
-
- send_event(window, MouseMoved((x, y)));
+ send_event(window, MouseMoved(x, y));
0
},
diff --git a/src/api/x11/events.rs b/src/api/x11/events.rs
index 1c6668c3..4754b1dc 100644
--- a/src/api/x11/events.rs
+++ b/src/api/x11/events.rs
@@ -14,7 +14,7 @@ pub fn keycode_to_element(scancode: libc::c_uint) -> Option {
//ffi::XK_Sys_Req => events::VirtualKeyCode::Sys_req,
ffi::XK_Escape => events::VirtualKeyCode::Escape,
ffi::XK_Delete => events::VirtualKeyCode::Delete,
- //ffi::XK_Multi_key => events::VirtualKeyCode::Multi_key,
+ ffi::XK_Multi_key => events::VirtualKeyCode::Compose,
//ffi::XK_Kanji => events::VirtualKeyCode::Kanji,
//ffi::XK_Muhenkan => events::VirtualKeyCode::Muhenkan,
//ffi::XK_Henkan_Mode => events::VirtualKeyCode::Henkan_mode,
diff --git a/src/api/x11/input.rs b/src/api/x11/input.rs
index a05b22e1..310f1bcb 100644
--- a/src/api/x11/input.rs
+++ b/src/api/x11/input.rs
@@ -241,7 +241,7 @@ impl XInputEventHandler {
let new_cursor_pos = (event_data.event_x, event_data.event_y);
if new_cursor_pos != self.current_state.cursor_pos {
self.current_state.cursor_pos = new_cursor_pos;
- Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
+ Some(MouseMoved(new_cursor_pos.0 as i32, new_cursor_pos.1 as i32))
} else {
None
}
diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs
index 005fe6d2..b2013d23 100644
--- a/src/api/x11/window.rs
+++ b/src/api/x11/window.rs
@@ -3,7 +3,7 @@ use CreationError;
use CreationError::OsError;
use libc;
use std::borrow::Borrow;
-use std::{mem, ptr};
+use std::{mem, ptr, cmp};
use std::cell::Cell;
use std::sync::atomic::AtomicBool;
use std::collections::VecDeque;
@@ -285,11 +285,23 @@ impl Window {
pub fn new(display: &Arc, window_attrs: &WindowAttributes)
-> Result
{
- let dimensions = window_attrs.dimensions.unwrap_or((800, 600));
+ let dimensions = {
- // not implemented
- assert!(window_attrs.min_dimensions.is_none());
- assert!(window_attrs.max_dimensions.is_none());
+ // x11 only applies constraints when the window is actively resized
+ // by the user, so we have to manually apply the initial constraints
+ let mut dimensions = window_attrs.dimensions.unwrap_or((800, 600));
+ if let Some(max) = window_attrs.max_dimensions {
+ dimensions.0 = cmp::min(dimensions.0, max.0);
+ dimensions.1 = cmp::min(dimensions.1, max.1);
+ }
+
+ if let Some(min) = window_attrs.min_dimensions {
+ dimensions.0 = cmp::max(dimensions.0, min.0);
+ dimensions.1 = cmp::max(dimensions.1, min.1);
+ }
+ dimensions
+
+ };
let screen_id = match window_attrs.monitor {
Some(PlatformMonitorId::X(MonitorId(_, monitor))) => monitor as i32,
@@ -502,6 +514,32 @@ impl Window {
(display.xf86vmode.XF86VidModeSetViewPort)(display.display, screen_id, 0, 0);
display.check_errors().expect("Failed to call XF86VidModeSetViewPort");
}
+
+ } else {
+
+ // set size hints
+ let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() };
+ size_hints.flags = ffi::PSize;
+ size_hints.width = dimensions.0 as i32;
+ size_hints.height = dimensions.1 as i32;
+
+ if let Some(dimensions) = window_attrs.min_dimensions {
+ size_hints.flags |= ffi::PMinSize;
+ size_hints.min_width = dimensions.0 as i32;
+ size_hints.min_height = dimensions.1 as i32;
+ }
+
+ if let Some(dimensions) = window_attrs.max_dimensions {
+ size_hints.flags |= ffi::PMaxSize;
+ size_hints.max_width = dimensions.0 as i32;
+ size_hints.max_height = dimensions.1 as i32;
+ }
+
+ unsafe {
+ (display.xlib.XSetNormalHints)(display.display, window, &mut size_hints);
+ display.check_errors().expect("Failed to call XSetNormalHints");
+ }
+
}
// creating the window object
@@ -706,51 +744,115 @@ impl Window {
pub fn set_cursor(&self, cursor: MouseCursor) {
unsafe {
- use std::ffi::CString;
- let cursor_name = match cursor {
- MouseCursor::Alias => "link",
- MouseCursor::Arrow => "arrow",
- MouseCursor::Cell => "plus",
- MouseCursor::Copy => "copy",
- MouseCursor::Crosshair => "crosshair",
- MouseCursor::Default => "left_ptr",
- MouseCursor::Grabbing => "grabbing",
- MouseCursor::Hand | MouseCursor::Grab => "hand",
- MouseCursor::Help => "question_arrow",
- MouseCursor::Move => "move",
- MouseCursor::NoDrop => "circle",
- MouseCursor::NotAllowed => "crossed_circle",
- MouseCursor::Progress => "left_ptr_watch",
+ let load = |name: &str| {
+ self.load_cursor(name)
+ };
+
+ let loadn = |names: &[&str]| {
+ self.load_first_existing_cursor(names)
+ };
+
+ // Try multiple names in some cases where the name
+ // differs on the desktop environments or themes.
+ //
+ // Try the better looking (or more suiting) names first.
+ let mut xcursor = match cursor {
+ MouseCursor::Alias => load("link"),
+ MouseCursor::Arrow => load("arrow"),
+ MouseCursor::Cell => load("plus"),
+ MouseCursor::Copy => load("copy"),
+ MouseCursor::Crosshair => load("crosshair"),
+ MouseCursor::Default => load("left_ptr"),
+ MouseCursor::Hand => load("hand1"),
+ MouseCursor::Help => load("question_arrow"),
+ MouseCursor::Move => load("move"),
+ MouseCursor::Grab => loadn(&["openhand", "grab"]),
+ MouseCursor::Grabbing => loadn(&["closedhand", "grabbing"]),
+ MouseCursor::Progress => load("left_ptr_watch"),
+ MouseCursor::AllScroll => load("all-scroll"),
+ MouseCursor::ContextMenu => load("context-menu"),
+
+ MouseCursor::NoDrop => loadn(&["no-drop", "circle"]),
+ MouseCursor::NotAllowed => load("crossed_circle"),
+
/// Resize cursors
- MouseCursor::EResize => "right_side",
- MouseCursor::NResize => "top_side",
- MouseCursor::NeResize => "top_right_corner",
- MouseCursor::NwResize => "top_left_corner",
- MouseCursor::SResize => "bottom_side",
- MouseCursor::SeResize => "bottom_right_corner",
- MouseCursor::SwResize => "bottom_left_corner",
- MouseCursor::WResize => "left_side",
- MouseCursor::EwResize | MouseCursor::ColResize => "h_double_arrow",
- MouseCursor::NsResize | MouseCursor::RowResize => "v_double_arrow",
- MouseCursor::NwseResize => "bd_double_arrow",
- MouseCursor::NeswResize => "fd_double_arrow",
+ MouseCursor::EResize => load("right_side"),
+ MouseCursor::NResize => load("top_side"),
+ MouseCursor::NeResize => load("top_right_corner"),
+ MouseCursor::NwResize => load("top_left_corner"),
+ MouseCursor::SResize => load("bottom_side"),
+ MouseCursor::SeResize => load("bottom_right_corner"),
+ MouseCursor::SwResize => load("bottom_left_corner"),
+ MouseCursor::WResize => load("left_side"),
+ MouseCursor::EwResize => load("h_double_arrow"),
+ MouseCursor::NsResize => load("v_double_arrow"),
+ MouseCursor::NwseResize => loadn(&["bd_double_arrow", "size_bdiag"]),
+ MouseCursor::NeswResize => loadn(&["fd_double_arrow", "size_fdiag"]),
+ MouseCursor::ColResize => loadn(&["split_h", "h_double_arrow"]),
+ MouseCursor::RowResize => loadn(&["split_v", "v_double_arrow"]),
- MouseCursor::Text | MouseCursor::VerticalText => "xterm",
- MouseCursor::Wait => "watch",
+ MouseCursor::Text => loadn(&["text", "xterm"]),
+ MouseCursor::VerticalText => load("vertical-text"),
- /// TODO: Find matching X11 cursors
- MouseCursor::ContextMenu | MouseCursor::NoneCursor |
- MouseCursor::AllScroll | MouseCursor::ZoomIn |
- MouseCursor::ZoomOut => "left_ptr",
+ MouseCursor::Wait => load("watch"),
+
+ MouseCursor::ZoomIn => load("zoom-in"),
+ MouseCursor::ZoomOut => load("zoom-out"),
+
+ MouseCursor::NoneCursor => self.create_empty_cursor(),
};
- let c_string = CString::new(cursor_name.as_bytes().to_vec()).unwrap();
- let xcursor = (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr());
- self.x.display.check_errors().expect("Failed to call XcursorLibraryLoadCursor");
+
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor);
- (self.x.display.xlib.XFlush)(self.x.display.display);
- (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor);
- self.x.display.check_errors().expect("Failed to call XDefineCursor");
+ if xcursor != 0 {
+ (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor);
+ }
+ self.x.display.check_errors().expect("Failed to set or free the cursor");
+ }
+ }
+
+ fn load_cursor(&self, name: &str) -> ffi::Cursor {
+ use std::ffi::CString;
+ unsafe {
+ let c_string = CString::new(name.as_bytes()).unwrap();
+ (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr())
+ }
+ }
+
+ fn load_first_existing_cursor(&self, names :&[&str]) -> ffi::Cursor {
+ for name in names.iter() {
+ let xcursor = self.load_cursor(name);
+ if xcursor != 0 {
+ return xcursor;
+ }
+ }
+ 0
+ }
+
+ // TODO: This could maybe be cached. I don't think it's worth
+ // the complexity, since cursor changes are not so common,
+ // and this is just allocating a 1x1 pixmap...
+ fn create_empty_cursor(&self) -> ffi::Cursor {
+ use std::mem;
+
+ let data = 0;
+ unsafe {
+ let pixmap = (self.x.display.xlib.XCreateBitmapFromData)(self.x.display.display, self.x.window, &data, 1, 1);
+ if pixmap == 0 {
+ // Failed to allocate
+ return 0;
+ }
+
+ // We don't care about this color, since it only fills bytes
+ // in the pixmap which are not 0 in the mask.
+ let dummy_color: ffi::XColor = mem::uninitialized();
+ let cursor = (self.x.display.xlib.XCreatePixmapCursor)(self.x.display.display,
+ pixmap,
+ pixmap,
+ &dummy_color as *const _ as *mut _,
+ &dummy_color as *const _ as *mut _, 0, 0);
+ (self.x.display.xlib.XFreePixmap)(self.x.display.display, pixmap);
+ cursor
}
}
@@ -772,13 +874,10 @@ impl Window {
},
Normal => {},
Hide => {
+ // NB: Calling XDefineCursor with None (aka 0)
+ // as a value resets the cursor to the default.
unsafe {
- let xcursor = (self.x.display.xlib.XCreateFontCursor)(self.x.display.display, 68/*XC_left_ptr*/);
- self.x.display.check_errors().expect("Failed to call XCreateFontCursor");
- (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor);
- self.x.display.check_errors().expect("Failed to call XDefineCursor");
- (self.x.display.xlib.XFlush)(self.x.display.display);
- (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor);
+ (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, 0);
}
},
}
@@ -787,25 +886,20 @@ impl Window {
match state {
Normal => Ok(()),
Hide => {
- let data = &[0, 0, 0, 0, 0, 0, 0, 0];
unsafe {
- let mut black = ffi::XColor {
- red: 0, green: 0, blue: 0,
- pad: 0, pixel: 0, flags: 0,
- };
- let bitmap = (self.x.display.xlib.XCreateBitmapFromData)(self.x.display.display, self.x.window, data.as_ptr(), 8, 8);
- let cursor = (self.x.display.xlib.XCreatePixmapCursor)(self.x.display.display, bitmap, bitmap, &mut black, &mut black, 0, 0);
+ let cursor = self.create_empty_cursor();
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, cursor);
- self.x.display.check_errors().expect("Failed to call XDefineCursor");
- (self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor);
- (self.x.display.xlib.XFreePixmap)(self.x.display.display, bitmap);
+ if cursor != 0 {
+ (self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor);
+ }
+ self.x.display.check_errors().expect("Failed to call XDefineCursor or free the empty cursor");
}
Ok(())
},
Grab => {
unsafe {
match (self.x.display.xlib.XGrabPointer)(
- self.x.display.display, self.x.window, ffi::False,
+ self.x.display.display, self.x.window, ffi::True,
(ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask |
ffi::LeaveWindowMask | ffi::PointerMotionMask | ffi::PointerMotionHintMask |
ffi::Button1MotionMask | ffi::Button2MotionMask | ffi::Button3MotionMask |
diff --git a/src/events.rs b/src/events.rs
index 9fff1fb7..7186256c 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -28,7 +28,7 @@ pub enum Event {
/// The cursor has moved on the window.
///
/// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
- MouseMoved((i32, i32)),
+ MouseMoved(i32, i32),
/// A mouse wheel movement or touchpad scroll occurred.
MouseWheel(MouseScrollDelta, TouchPhase),
@@ -220,6 +220,9 @@ pub enum VirtualKeyCode {
/// The space bar.
Space,
+ /// The "Compose" key on Linux.
+ Compose,
+
Numlock,
Numpad0,
Numpad1,
diff --git a/src/lib.rs b/src/lib.rs
index dea319cc..e37b9bf4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -61,7 +61,7 @@ extern crate x11_dl;
extern crate wayland_client;
pub use events::*;
-pub use window::{WindowBuilder, WindowProxy, PollEventsIterator, WaitEventsIterator};
+pub use window::{WindowProxy, PollEventsIterator, WaitEventsIterator};
pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
pub use native_monitor::NativeMonitorId;
@@ -99,6 +99,16 @@ pub struct Window {
window: platform::Window,
}
+/// Object that allows you to build windows.
+#[derive(Clone)]
+pub struct WindowBuilder {
+ /// The attributes to use to create the window.
+ pub window: WindowAttributes,
+
+ /// Platform-specific configuration.
+ platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
+}
+
/// Error that can happen while creating a window or a headless renderer.
#[derive(Debug)]
pub enum CreationError {
@@ -128,7 +138,7 @@ impl std::error::Error for CreationError {
}
}
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MouseCursor {
/// The platform-dependent default cursor.
Default,
@@ -185,7 +195,7 @@ pub enum MouseCursor {
}
/// Describes how glutin handles the cursor.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CursorState {
/// Normal cursor behavior.
Normal,
diff --git a/src/os/macos.rs b/src/os/macos.rs
index 16ffe33c..06ea55c2 100644
--- a/src/os/macos.rs
+++ b/src/os/macos.rs
@@ -1,7 +1,9 @@
#![cfg(target_os = "macos")]
+use std::convert::From;
use std::os::raw::c_void;
-use Window;
+use cocoa::appkit::NSApplicationActivationPolicy;
+use {Window, WindowBuilder};
/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExt {
@@ -17,3 +19,47 @@ impl WindowExt for Window {
self.window.platform_window() as *mut c_void
}
}
+
+/// Corresponds to `NSApplicationActivationPolicy`.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum ActivationPolicy {
+ /// Corresponds to `NSApplicationActivationPolicyRegular`.
+ Regular,
+ /// Corresponds to `NSApplicationActivationPolicyAccessory`.
+ Accessory,
+ /// Corresponds to `NSApplicationActivationPolicyProhibited`.
+ Prohibited,
+}
+
+impl Default for ActivationPolicy {
+ fn default() -> Self {
+ ActivationPolicy::Regular
+ }
+}
+
+impl From for NSApplicationActivationPolicy {
+ fn from(activation_policy: ActivationPolicy) -> Self {
+ match activation_policy {
+ ActivationPolicy::Regular =>
+ NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular,
+ ActivationPolicy::Accessory =>
+ NSApplicationActivationPolicy::NSApplicationActivationPolicyAccessory,
+ ActivationPolicy::Prohibited =>
+ NSApplicationActivationPolicy::NSApplicationActivationPolicyProhibited,
+ }
+ }
+}
+
+/// Additional methods on `WindowBuilder` that are specific to MacOS.
+pub trait WindowBuilderExt<'a> {
+ fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder<'a>;
+}
+
+impl<'a> WindowBuilderExt<'a> for WindowBuilder<'a> {
+ /// Sets the activation policy for the window being built
+ #[inline]
+ fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder<'a> {
+ self.platform_specific.activation_policy = activation_policy;
+ self
+ }
+}
diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs
index ce8d201c..22cb5653 100644
--- a/src/platform/emscripten/mod.rs
+++ b/src/platform/emscripten/mod.rs
@@ -58,7 +58,7 @@ impl GlContext for HeadlessContext {
unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs
index 2e6fbec0..0b1a5509 100644
--- a/src/platform/ios/mod.rs
+++ b/src/platform/ios/mod.rs
@@ -8,7 +8,7 @@ use ContextError;
pub use api::ios::*;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
pub struct HeadlessContext(i32);
diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs
index 7e5e3e17..975cadaf 100644
--- a/src/platform/linux/api_dispatch.rs
+++ b/src/platform/linux/api_dispatch.rs
@@ -17,7 +17,7 @@ use api::x11::XConnection;
use api::x11::XError;
use api::x11::XNotSupported;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
enum Backend {
diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs
index 249ee157..76747ae2 100644
--- a/src/platform/windows/mod.rs
+++ b/src/platform/windows/mod.rs
@@ -9,9 +9,9 @@ use WindowAttributes;
use std::ops::{Deref, DerefMut};
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
/// The Win32 implementation of the main `Window` object.
diff --git a/src/window.rs b/src/window.rs
index 4142aa4b..d5603f74 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -1,26 +1,16 @@
use std::collections::vec_deque::IntoIter as VecDequeIter;
-use std::default::Default;
use CreationError;
use CursorState;
use Event;
use MouseCursor;
use Window;
-use WindowAttributes;
+use WindowBuilder;
use native_monitor::NativeMonitorId;
use libc;
use platform;
-/// Object that allows you to build windows.
-pub struct WindowBuilder {
- /// The attributes to use to create the window.
- pub window: WindowAttributes,
-
- /// Platform-specific configuration.
- platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
-}
-
impl WindowBuilder {
/// Initializes a new `WindowBuilder` with default values.
#[inline]
@@ -60,8 +50,8 @@ impl WindowBuilder {
/// Requests a specific title for the window.
#[inline]
- pub fn with_title(mut self, title: String) -> WindowBuilder {
- self.window.title = title;
+ pub fn with_title>(mut self, title: T) -> WindowBuilder {
+ self.window.title = title.into();
self
}