winit-sonoma-fix/src/lib.rs

467 lines
15 KiB
Rust
Raw Normal View History

2017-06-22 05:10:23 +10:00
//! Winit allows you to build a window on as many platforms as possible.
2014-08-03 04:49:48 +10:00
//!
//! # Building a window
2014-09-04 19:38:33 +10:00
//!
2017-01-29 01:33:54 +11:00
//! Before you can build a window, you first need to build an `EventsLoop`. This is done with the
//! `EventsLoop::new()` function. Example:
2014-09-04 19:38:33 +10:00
//!
2017-01-29 01:33:54 +11:00
//! ```no_run
//! use winit::EventsLoop;
//! let events_loop = EventsLoop::new();
//! ```
//!
//! Once this is done there are two ways to create a window:
//!
//! - Calling `Window::new(&events_loop)`.
//! - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`.
2014-08-03 04:49:48 +10:00
//!
2016-11-03 19:49:19 +11:00
//! The first way is the simpliest way and will give you default values for everything.
2014-08-03 04:49:48 +10:00
//!
2016-11-03 19:49:19 +11:00
//! The second way allows you to customize the way your window will look and behave by modifying
//! the fields of the `WindowBuilder` object before you create the window.
2014-10-05 04:17:02 +11:00
//!
2016-11-03 19:49:19 +11:00
//! # Events handling
2014-10-05 04:17:02 +11:00
//!
2017-01-29 01:33:54 +11:00
//! Once a window has been created, it will *generate events*. For example whenever the user moves
//! the window, resizes the window, moves the mouse, etc. an event is generated.
//!
//! The events generated by a window can be retreived from the `EventsLoop` the window was created
//! with.
//!
//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will
//! retreive all the events pending on the windows and immediately return after no new event is
//! available. You usually want to use this method in application that render continuously on the
//! screen, such as video games.
//!
//! ```no_run
//! use winit::{Event, WindowEvent};
2017-01-29 01:33:54 +11:00
//! # use winit::EventsLoop;
//! # let mut events_loop = EventsLoop::new();
2017-01-29 01:33:54 +11:00
//!
//! loop {
//! events_loop.poll_events(|event| {
//! match event {
//! Event::WindowEvent { event: WindowEvent::Resized(w, h), .. } => {
//! println!("The window was resized to {}x{}", w, h);
//! },
//! _ => ()
//! }
//! });
//! }
//! ```
//!
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
//! forever unless it is stopped by returning `ControlFlow::Break`.
2017-01-29 01:33:54 +11:00
//!
//! ```no_run
//! use winit::{ControlFlow, Event, WindowEvent};
2017-01-29 01:33:54 +11:00
//! # use winit::EventsLoop;
//! # let mut events_loop = EventsLoop::new();
2017-01-29 01:33:54 +11:00
//!
//! events_loop.run_forever(|event| {
//! match event {
//! Event::WindowEvent { event: WindowEvent::Closed, .. } => {
//! println!("The window was closed ; stopping");
//! ControlFlow::Break
2017-01-29 01:33:54 +11:00
//! },
//! _ => ControlFlow::Continue,
2017-01-29 01:33:54 +11:00
//! }
//! });
//! ```
//!
//! If you use multiple windows, the `WindowEvent` event has a member named `window_id`. You can
//! compare it with the value returned by the `id()` method of `Window` in order to know which
//! window has received the event.
2014-10-05 04:17:02 +11:00
//!
2016-11-03 19:49:19 +11:00
//! # Drawing on the window
//!
//! Winit doesn't provide any function that allows drawing on a window. However it allows you to
//! retreive the raw handle of the window (see the `os` module for that), which in turn allows you
//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the window.
2014-10-05 04:17:02 +11:00
//!
2014-08-03 04:49:48 +10:00
2015-04-03 17:33:51 +11:00
#[macro_use]
extern crate lazy_static;
2014-07-27 18:55:37 +10:00
extern crate libc;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
2015-03-28 21:07:41 +11:00
extern crate kernel32;
#[cfg(target_os = "windows")]
2015-06-24 08:05:37 +10:00
extern crate shell32;
#[cfg(target_os = "windows")]
2015-03-30 14:58:13 +11:00
extern crate user32;
2015-05-21 02:46:10 +10:00
#[cfg(target_os = "windows")]
extern crate dwmapi;
2015-06-05 23:38:21 +10:00
#[cfg(any(target_os = "macos", target_os = "ios"))]
2015-03-22 16:31:32 +11:00
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
2015-05-07 21:20:25 +10:00
extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
2017-06-24 04:25:06 +10:00
#[macro_use]
extern crate wayland_client;
2014-07-30 21:11:49 +10:00
pub use events::*;
pub use window::{AvailableMonitorsIter, MonitorId};
2014-08-13 22:52:12 +10:00
2015-04-02 17:27:32 +11:00
mod platform;
2014-07-27 20:59:45 +10:00
mod events;
mod window;
2014-07-28 04:38:27 +10:00
pub mod os;
2016-11-03 19:49:19 +11:00
/// Represents a window.
///
/// # Example
///
2016-11-03 19:49:19 +11:00
/// ```no_run
/// use winit::{Event, EventsLoop, Window, WindowEvent, ControlFlow};
2017-01-29 01:33:54 +11:00
///
/// let mut events_loop = EventsLoop::new();
2017-01-29 01:33:54 +11:00
/// let window = Window::new(&events_loop).unwrap();
///
2017-01-29 01:33:54 +11:00
/// events_loop.run_forever(|event| {
/// match event {
/// Event::WindowEvent { event: WindowEvent::Closed, .. } => {
/// ControlFlow::Break
2017-01-29 01:33:54 +11:00
/// },
/// _ => ControlFlow::Continue,
/// }
2017-01-29 01:33:54 +11:00
/// });
/// ```
pub struct Window {
window: platform::Window,
2017-01-29 01:00:17 +11:00
}
2017-02-03 19:13:11 +11:00
/// Identifier of a window. Unique for each window.
///
/// Can be obtained with `window.id()`.
///
/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you
/// can then compare to the ids of your windows.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(platform::WindowId);
/// Identifier of an input device.
///
/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(platform::DeviceId);
/// Provides a way to retreive events from the system and from the windows that were registered to
/// the events loop.
///
/// An `EventsLoop` can be seen more or less as a "context". Calling `EventsLoop::new()`
/// initializes everything that will be required to create windows. For example on Linux creating
/// an events loop opens a connection to the X or Wayland server.
2017-06-22 05:10:23 +10:00
///
/// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs.
///
/// Note that the `EventsLoop` cannot be shared accross threads (due to platform-dependant logic
/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
/// `Window` created from this `EventsLoop` _can_ be sent to an other thread, and the
/// `EventsLoopProxy` allows you to wakeup an `EventsLoop` from an other thread.
2017-01-29 01:00:17 +11:00
pub struct EventsLoop {
events_loop: platform::EventsLoop,
_marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
}
/// Returned by the user callback given to the `EventsLoop::run_forever` method.
///
/// Indicates whether the `run_forever` method should continue or complete.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
/// Continue looping and waiting for events.
Continue,
/// Break from the event loop.
Break,
2017-01-29 01:00:17 +11:00
}
impl EventsLoop {
/// Builds a new events loop.
///
/// Usage will result in display backend initialisation, this can be controlled on linux
/// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
/// If it is not set, winit will try to connect to a wayland connection, and if it fails will
/// fallback on x11. If this variable is set with any other value, winit will panic.
2017-01-29 01:00:17 +11:00
pub fn new() -> EventsLoop {
EventsLoop {
events_loop: platform::EventsLoop::new(),
_marker: ::std::marker::PhantomData,
2017-01-29 01:00:17 +11:00
}
}
/// Returns the list of all the monitors available on the system.
///
// Note: should be replaced with `-> impl Iterator` once stable.
#[inline]
pub fn get_available_monitors(&self) -> AvailableMonitorsIter {
let data = self.events_loop.get_available_monitors();
AvailableMonitorsIter{ data: data.into_iter() }
}
/// Returns the primary monitor of the system.
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
MonitorId { inner: self.events_loop.get_primary_monitor() }
}
2017-01-29 01:33:54 +11:00
/// Fetches all the events that are pending, calls the callback function for each of them,
/// and returns.
2017-01-29 01:00:17 +11:00
#[inline]
pub fn poll_events<F>(&mut self, callback: F)
2017-01-29 01:00:17 +11:00
where F: FnMut(Event)
{
self.events_loop.poll_events(callback)
}
/// Calls `callback` every time an event is received. If no event is available, sleeps the
/// current thread and waits for an event. If the callback returns `ControlFlow::Break` then
/// `run_forever` will immediately return.
2017-01-29 01:00:17 +11:00
#[inline]
pub fn run_forever<F>(&mut self, callback: F)
where F: FnMut(Event) -> ControlFlow
2017-01-29 01:00:17 +11:00
{
self.events_loop.run_forever(callback)
}
2017-01-29 01:09:01 +11:00
/// Creates an `EventsLoopProxy` that can be used to wake up the `EventsLoop` from another
/// thread.
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy {
events_loop_proxy: self.events_loop.create_proxy(),
}
}
}
/// Used to wake up the `EventsLoop` from another thread.
2017-10-26 05:03:57 +11:00
#[derive(Clone)]
pub struct EventsLoopProxy {
events_loop_proxy: platform::EventsLoopProxy,
}
impl EventsLoopProxy {
/// Wake up the `EventsLoop` from which this proxy was created.
///
/// This causes the `EventsLoop` to emit an `Awakened` event.
///
/// Returns an `Err` if the associated `EventsLoop` no longer exists.
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
self.events_loop_proxy.wakeup()
}
}
/// The error that is returned when an `EventsLoopProxy` attempts to wake up an `EventsLoop` that
/// no longer exists.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EventsLoopClosed;
impl std::fmt::Display for EventsLoopClosed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", std::error::Error::description(self))
}
}
impl std::error::Error for EventsLoopClosed {
fn description(&self) -> &str {
"Tried to wake up a closed `EventsLoop`"
}
}
/// Object that allows you to build windows.
#[derive(Clone)]
pub struct WindowBuilder {
/// The attributes to use to create the window.
pub window: WindowAttributes,
2016-11-03 19:49:19 +11:00
// Platform-specific configuration. Private.
platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
}
/// Error that can happen while creating a window or a headless renderer.
2017-08-24 11:52:06 +10:00
#[derive(Debug, Clone)]
pub enum CreationError {
OsError(String),
2015-07-21 03:43:36 +10:00
/// TODO: remove this error
NotSupported,
}
2015-01-24 12:50:06 +11:00
impl CreationError {
fn to_string(&self) -> &str {
match *self {
2015-03-26 05:57:38 +11:00
CreationError::OsError(ref text) => &text,
CreationError::NotSupported => "Some of the requested attributes are not supported",
}
}
}
2015-01-24 12:50:06 +11:00
impl std::fmt::Display for CreationError {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
formatter.write_str(self.to_string())
}
}
impl std::error::Error for CreationError {
fn description(&self) -> &str {
self.to_string()
}
2015-12-19 21:24:09 +11:00
}
/// Describes the appearance of the mouse cursor.
2016-08-18 04:42:45 +10:00
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MouseCursor {
/// The platform-dependent default cursor.
Default,
/// A simple crosshair.
Crosshair,
/// A hand (often used to indicate links in web browsers).
Hand,
/// Self explanatory.
Arrow,
/// Indicates something is to be moved.
Move,
/// Indicates text that may be selected or edited.
Text,
/// Program busy indicator.
Wait,
/// Help indicator (often rendered as a "?")
Help,
/// Progress indicator. Shows that processing is being done. But in contrast
/// with "Wait" the user may still interact with the program. Often rendered
2015-01-26 14:28:12 +11:00
/// as a spinning beach ball, or an arrow with a watch or hourglass.
Progress,
/// Cursor showing that something cannot be done.
NotAllowed,
ContextMenu,
NoneCursor,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
/// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
/// is used when the movement starts from the south-east corner of the box.
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
2017-05-11 10:14:38 +10:00
/// Describes how winit handles the cursor.
2016-08-18 04:42:45 +10:00
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CursorState {
/// Normal cursor behavior.
Normal,
/// The cursor will be invisible when over the window.
Hide,
/// Grabs the mouse cursor. The cursor's motion will be confined to this
/// window and the window has exclusive access to further events regarding
/// the cursor.
///
/// This is useful for first-person cameras for example.
Grab,
}
/// Attributes to use when creating a window.
#[derive(Clone)]
pub struct WindowAttributes {
/// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
/// used.
///
/// The default is `None`.
pub dimensions: Option<(u32, u32)>,
/// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved).
///
/// The default is `None`.
pub min_dimensions: Option<(u32, u32)>,
/// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform.
///
/// The default is `None`.
pub max_dimensions: Option<(u32, u32)>,
/// Whether the window should be set as fullscreen upon creation.
///
/// The default is `None`.
Move fullscreen modes to not touch physical resolutions (#270) * Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
2017-09-07 18:33:46 +10:00
pub fullscreen: Option<MonitorId>,
/// The title of the window in the title bar.
///
2017-05-11 10:14:38 +10:00
/// The default is `"winit window"`.
pub title: String,
/// Whether the window should be maximized upon creation.
///
/// The default is `false`.
pub maximized: bool,
/// Whether the window should be immediately visible upon creation.
///
/// The default is `true`.
pub visible: bool,
/// Whether the the window should be transparent. If this is true, writing colors
/// with alpha values different than `1.0` will produce a transparent window.
///
/// The default is `false`.
pub transparent: bool,
/// Whether the window should have borders and bars.
///
/// The default is `true`.
pub decorations: bool,
2015-09-22 02:57:35 +10:00
/// [iOS only] Enable multitouch, see [UIView#multipleTouchEnabled]
/// (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/multipleTouchEnabled)
pub multitouch: bool,
}
impl Default for WindowAttributes {
2015-09-21 22:42:05 +10:00
#[inline]
fn default() -> WindowAttributes {
WindowAttributes {
dimensions: None,
min_dimensions: None,
max_dimensions: None,
2017-05-11 10:14:38 +10:00
title: "winit window".to_owned(),
maximized: false,
Move fullscreen modes to not touch physical resolutions (#270) * Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
2017-09-07 18:33:46 +10:00
fullscreen: None,
visible: true,
transparent: false,
decorations: true,
multitouch: false,
}
}
}