diff options
Diffstat (limited to 'src/window.rs')
-rw-r--r-- | src/window.rs | 497 |
1 files changed, 0 insertions, 497 deletions
diff --git a/src/window.rs b/src/window.rs deleted file mode 100644 index b6384600..00000000 --- a/src/window.rs +++ /dev/null @@ -1,497 +0,0 @@ -// Copyright 2016 Joe Wilm, The Alacritty Project Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -use std::convert::From; -use std::fmt::Display; - -use crate::gl; -use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -#[cfg(not(any(target_os = "macos", windows)))] -use glutin::os::unix::EventsLoopExt; -#[cfg(windows)] -use glutin::Icon; -use glutin::{ - self, ContextBuilder, ControlFlow, Event, EventsLoop, MouseCursor, PossiblyCurrent, - WindowBuilder, -}; -#[cfg(windows)] -use image::ImageFormat; - -use crate::cli::Options; -use crate::config::{Decorations, StartupMode, WindowConfig}; - -#[cfg(windows)] -static WINDOW_ICON: &'static [u8] = include_bytes!("../extra/windows/alacritty.ico"); - -/// Default Alacritty name, used for window title and class. -pub const DEFAULT_NAME: &str = "Alacritty"; - -/// Window errors -#[derive(Debug)] -pub enum Error { - /// Error creating the window - ContextCreation(glutin::CreationError), - - /// Error manipulating the rendering context - Context(glutin::ContextError), -} - -/// Result of fallible operations concerning a Window. -type Result<T> = ::std::result::Result<T, Error>; - -/// A window which can be used for displaying the terminal -/// -/// Wraps the underlying windowing library to provide a stable API in Alacritty -pub struct Window { - event_loop: EventsLoop, - windowed_context: glutin::WindowedContext<PossiblyCurrent>, - mouse_visible: bool, - - /// Whether or not the window is the focused window. - pub is_focused: bool, -} - -/// Threadsafe APIs for the window -pub struct Proxy { - inner: glutin::EventsLoopProxy, -} - -/// Information about where the window is being displayed -/// -/// Useful for subsystems like the font rasterized which depend on DPI and scale -/// factor. -pub struct DeviceProperties { - /// Scale factor for pixels <-> points. - /// - /// This will be 1. on standard displays and may have a different value on - /// hidpi displays. - pub scale_factor: f64, -} - -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&dyn (::std::error::Error)> { - match *self { - Error::ContextCreation(ref err) => Some(err), - Error::Context(ref err) => Some(err), - } - } - - fn description(&self) -> &str { - match *self { - Error::ContextCreation(ref _err) => "Error creating gl context", - Error::Context(ref _err) => "Error operating on render context", - } - } -} - -impl Display for Error { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - match *self { - Error::ContextCreation(ref err) => write!(f, "Error creating GL context; {}", err), - Error::Context(ref err) => write!(f, "Error operating on render context; {}", err), - } - } -} - -impl From<glutin::CreationError> for Error { - fn from(val: glutin::CreationError) -> Error { - Error::ContextCreation(val) - } -} - -impl From<glutin::ContextError> for Error { - fn from(val: glutin::ContextError) -> Error { - Error::Context(val) - } -} - -fn create_gl_window( - mut window: WindowBuilder, - event_loop: &EventsLoop, - srgb: bool, - dimensions: Option<LogicalSize>, -) -> Result<glutin::WindowedContext<PossiblyCurrent>> { - if let Some(dimensions) = dimensions { - window = window.with_dimensions(dimensions); - } - - let windowed_context = ContextBuilder::new() - .with_srgb(srgb) - .with_vsync(true) - .with_hardware_acceleration(None) - .build_windowed(window, event_loop)?; - - // Make the context current so OpenGL operations can run - let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, e)| e)? }; - - Ok(windowed_context) -} - -impl Window { - /// Create a new window - /// - /// This creates a window and fully initializes a window. - pub fn new( - event_loop: EventsLoop, - options: &Options, - window_config: &WindowConfig, - dimensions: Option<LogicalSize>, - ) -> Result<Window> { - let title = options.title.as_ref().map_or(DEFAULT_NAME, |t| t); - let class = options.class.as_ref().map_or(DEFAULT_NAME, |c| c); - let window_builder = Window::get_platform_window(title, class, window_config); - let windowed_context = - create_gl_window(window_builder.clone(), &event_loop, false, dimensions) - .or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?; - let window = windowed_context.window(); - window.show(); - - // Maximize window after mapping in X11 - #[cfg(not(any(target_os = "macos", windows)))] - { - if event_loop.is_x11() && window_config.startup_mode() == StartupMode::Maximized { - window.set_maximized(true); - } - } - - // Set window position - // - // TODO: replace `set_position` with `with_position` once available - // Upstream issue: https://github.com/tomaka/winit/issues/806 - let position = options.position().or_else(|| window_config.position()); - if let Some(position) = position { - let physical = PhysicalPosition::from((position.x, position.y)); - let logical = physical.to_logical(window.get_hidpi_factor()); - window.set_position(logical); - } - - if let StartupMode::Fullscreen = window_config.startup_mode() { - let current_monitor = window.get_current_monitor(); - window.set_fullscreen(Some(current_monitor)); - } - - #[cfg(target_os = "macos")] - { - if let StartupMode::SimpleFullscreen = window_config.startup_mode() { - use glutin::os::macos::WindowExt; - window.set_simple_fullscreen(true); - } - } - - // Text cursor - window.set_cursor(MouseCursor::Text); - - // Set OpenGL symbol loader. This call MUST be after window.make_current on windows. - gl::load_with(|symbol| windowed_context.get_proc_address(symbol) as *const _); - - let window = - Window { event_loop, windowed_context, mouse_visible: true, is_focused: false }; - - window.run_os_extensions(); - - Ok(window) - } - - /// Get some properties about the device - /// - /// Some window properties are provided since subsystems like font - /// rasterization depend on DPI and scale factor. - pub fn device_properties(&self) -> DeviceProperties { - DeviceProperties { scale_factor: self.window().get_hidpi_factor() } - } - - pub fn inner_size_pixels(&self) -> Option<LogicalSize> { - self.window().get_inner_size() - } - - pub fn set_inner_size(&mut self, size: LogicalSize) { - self.window().set_inner_size(size); - } - - #[inline] - pub fn hidpi_factor(&self) -> f64 { - self.window().get_hidpi_factor() - } - - #[inline] - pub fn create_window_proxy(&self) -> Proxy { - Proxy { inner: self.event_loop.create_proxy() } - } - - #[inline] - pub fn swap_buffers(&self) -> Result<()> { - self.windowed_context.swap_buffers().map_err(From::from) - } - - /// Poll for any available events - #[inline] - pub fn poll_events<F>(&mut self, func: F) - where - F: FnMut(Event), - { - self.event_loop.poll_events(func); - } - - #[inline] - pub fn resize(&self, size: PhysicalSize) { - self.windowed_context.resize(size); - } - - /// Block waiting for events - #[inline] - pub fn wait_events<F>(&mut self, func: F) - where - F: FnMut(Event) -> ControlFlow, - { - self.event_loop.run_forever(func); - } - - /// Set the window title - #[inline] - pub fn set_title(&self, title: &str) { - self.window().set_title(title); - } - - #[inline] - pub fn set_mouse_cursor(&self, cursor: MouseCursor) { - self.window().set_cursor(cursor); - } - - /// Set mouse cursor visible - pub fn set_mouse_visible(&mut self, visible: bool) { - if visible != self.mouse_visible { - self.mouse_visible = visible; - self.window().hide_cursor(!visible); - } - } - - #[cfg(not(any(target_os = "macos", windows)))] - pub fn get_platform_window( - title: &str, - class: &str, - window_config: &WindowConfig, - ) -> WindowBuilder { - use glutin::os::unix::WindowBuilderExt; - - let decorations = match window_config.decorations() { - Decorations::None => false, - _ => true, - }; - - WindowBuilder::new() - .with_title(title) - .with_visibility(false) - .with_transparency(true) - .with_decorations(decorations) - .with_maximized(window_config.startup_mode() == StartupMode::Maximized) - // X11 - .with_class(class.into(), DEFAULT_NAME.into()) - // Wayland - .with_app_id(class.into()) - } - - #[cfg(windows)] - pub fn get_platform_window( - title: &str, - _class: &str, - window_config: &WindowConfig, - ) -> WindowBuilder { - let icon = Icon::from_bytes_with_format(WINDOW_ICON, ImageFormat::ICO).unwrap(); - - let decorations = match window_config.decorations() { - Decorations::None => false, - _ => true, - }; - - WindowBuilder::new() - .with_title(title) - .with_visibility(cfg!(windows)) - .with_decorations(decorations) - .with_transparency(true) - .with_maximized(window_config.startup_mode() == StartupMode::Maximized) - .with_window_icon(Some(icon)) - } - - #[cfg(target_os = "macos")] - pub fn get_platform_window( - title: &str, - _class: &str, - window_config: &WindowConfig, - ) -> WindowBuilder { - use glutin::os::macos::WindowBuilderExt; - - let window = WindowBuilder::new() - .with_title(title) - .with_visibility(false) - .with_transparency(true) - .with_maximized(window_config.startup_mode() == StartupMode::Maximized); - - match window_config.decorations() { - Decorations::Full => window, - Decorations::Transparent => window - .with_title_hidden(true) - .with_titlebar_transparent(true) - .with_fullsize_content_view(true), - Decorations::Buttonless => window - .with_title_hidden(true) - .with_titlebar_buttons_hidden(true) - .with_titlebar_transparent(true) - .with_fullsize_content_view(true), - Decorations::None => window.with_titlebar_hidden(true), - } - } - - #[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" - ))] - pub fn set_urgent(&self, is_urgent: bool) { - use glutin::os::unix::WindowExt; - self.window().set_urgent(is_urgent); - } - - #[cfg(target_os = "macos")] - pub fn set_urgent(&self, is_urgent: bool) { - use glutin::os::macos::WindowExt; - self.window().request_user_attention(is_urgent); - } - - #[cfg(windows)] - pub fn set_urgent(&self, _is_urgent: bool) {} - - pub fn set_ime_spot(&self, pos: LogicalPosition) { - self.window().set_ime_spot(pos); - } - - #[cfg(not(any(target_os = "macos", target_os = "windows")))] - pub fn get_window_id(&self) -> Option<usize> { - use glutin::os::unix::WindowExt; - - match self.window().get_xlib_window() { - Some(xlib_window) => Some(xlib_window as usize), - None => None, - } - } - - #[cfg(any(target_os = "macos", target_os = "windows"))] - pub fn get_window_id(&self) -> Option<usize> { - None - } - - /// Hide the window - pub fn hide(&self) { - self.window().hide(); - } - - /// Fullscreens the window on the current monitor. - pub fn set_fullscreen(&self, fullscreen: bool) { - let glutin_window = self.window(); - if fullscreen { - let current_monitor = glutin_window.get_current_monitor(); - glutin_window.set_fullscreen(Some(current_monitor)); - } else { - glutin_window.set_fullscreen(None); - } - } - - #[cfg(target_os = "macos")] - pub fn set_simple_fullscreen(&self, fullscreen: bool) { - use glutin::os::macos::WindowExt; - self.window().set_simple_fullscreen(fullscreen); - } - - fn window(&self) -> &glutin::Window { - self.windowed_context.window() - } -} - -pub trait OsExtensions { - fn run_os_extensions(&self) {} -} - -#[cfg(not(any( - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -)))] -impl OsExtensions for Window {} - -#[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -))] -impl OsExtensions for Window { - fn run_os_extensions(&self) { - use glutin::os::unix::WindowExt; - use libc::getpid; - use std::ffi::CStr; - use std::ptr; - use x11_dl::xlib::{self, PropModeReplace, XA_CARDINAL}; - - let xlib_display = self.window().get_xlib_display(); - let xlib_window = self.window().get_xlib_window(); - - if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) { - let xlib = xlib::Xlib::open().expect("get xlib"); - - // Set _NET_WM_PID to process pid - unsafe { - let _net_wm_pid = CStr::from_ptr(b"_NET_WM_PID\0".as_ptr() as *const _); - let atom = (xlib.XInternAtom)(xlib_display as *mut _, _net_wm_pid.as_ptr(), 0); - let pid = getpid(); - - (xlib.XChangeProperty)( - xlib_display as _, - xlib_window as _, - atom, - XA_CARDINAL, - 32, - PropModeReplace, - &pid as *const i32 as *const u8, - 1, - ); - } - // Although this call doesn't actually pass any data, it does cause - // WM_CLIENT_MACHINE to be set. WM_CLIENT_MACHINE MUST be set if _NET_WM_PID is set - // (which we do above). - unsafe { - (xlib.XSetWMProperties)( - xlib_display as _, - xlib_window as _, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ); - } - } - } -} - -impl Proxy { - /// Wakes up the event loop of the window - /// - /// This is useful for triggering a draw when the renderer would otherwise - /// be waiting on user input. - pub fn wakeup_event_loop(&self) { - self.inner.wakeup().unwrap(); - } -} |