2016-12-10 05:10:49 +00:00
|
|
|
// 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;
|
2018-11-10 16:08:48 +00:00
|
|
|
use std::fmt::Display;
|
2016-12-10 05:10:49 +00:00
|
|
|
|
|
|
|
use gl;
|
2017-07-20 17:50:50 +00:00
|
|
|
use glutin::GlContext;
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(windows)]
|
2018-11-10 16:08:48 +00:00
|
|
|
use glutin::Icon;
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
use image::ImageFormat;
|
2018-09-20 15:24:26 +00:00
|
|
|
use glutin::{
|
2018-11-10 16:08:48 +00:00
|
|
|
self, ContextBuilder, ControlFlow, Event, EventsLoop,
|
2018-09-20 15:24:26 +00:00
|
|
|
MouseCursor as GlutinMouseCursor, WindowBuilder,
|
|
|
|
};
|
2016-12-10 05:10:49 +00:00
|
|
|
|
2018-11-10 16:08:48 +00:00
|
|
|
use {LogicalPosition, LogicalSize, MouseCursor, PhysicalSize};
|
|
|
|
|
2017-12-24 20:15:42 +00:00
|
|
|
|
2018-06-07 16:53:16 +00:00
|
|
|
use cli::Options;
|
2018-09-20 15:24:26 +00:00
|
|
|
use config::{Decorations, WindowConfig};
|
2017-12-20 19:12:32 +00:00
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
static WINDOW_ICON: &'static [u8] = include_bytes!("../assets/windows/alacritty.ico");
|
|
|
|
|
2018-06-18 05:26:54 +00:00
|
|
|
/// Default text for the window's title bar, if not overriden.
|
|
|
|
///
|
|
|
|
/// In X11, this the default value for the `WM_NAME` property.
|
|
|
|
pub const DEFAULT_TITLE: &str = "Alacritty";
|
|
|
|
|
|
|
|
/// Default text for general window class, X11 specific.
|
|
|
|
///
|
|
|
|
/// In X11, this is the default value for the `WM_CLASS` property. The
|
|
|
|
/// second value of `WM_CLASS` is **never** changed to anything but
|
|
|
|
/// the default value.
|
|
|
|
///
|
|
|
|
/// ```ignore
|
|
|
|
/// $ xprop | grep WM_CLASS
|
|
|
|
/// WM_CLASS(STRING) = "Alacritty", "Alacritty"
|
|
|
|
/// ```
|
|
|
|
pub const DEFAULT_CLASS: &str = "Alacritty";
|
|
|
|
|
2016-12-10 05:10:49 +00:00
|
|
|
/// Window errors
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
/// Error creating the window
|
2017-07-20 17:50:50 +00:00
|
|
|
ContextCreation(glutin::CreationError),
|
2016-12-10 05:10:49 +00:00
|
|
|
|
|
|
|
/// 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 {
|
2017-07-20 17:50:50 +00:00
|
|
|
event_loop: EventsLoop,
|
|
|
|
window: glutin::GlWindow,
|
2018-11-01 17:23:49 +00:00
|
|
|
mouse_visible: bool,
|
2017-10-21 23:03:58 +00:00
|
|
|
|
|
|
|
/// Whether or not the window is the focused window.
|
|
|
|
pub is_focused: bool,
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Threadsafe APIs for the window
|
2016-12-11 06:44:13 +00:00
|
|
|
pub struct Proxy {
|
2017-07-20 17:50:50 +00:00
|
|
|
inner: glutin::EventsLoopProxy,
|
2016-12-11 06:44:13 +00:00
|
|
|
}
|
2016-12-10 05:10:49 +00:00
|
|
|
|
|
|
|
/// 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.
|
2018-11-10 16:08:48 +00:00
|
|
|
pub scale_factor: f64,
|
2016-12-10 19:27:42 +00:00
|
|
|
}
|
|
|
|
|
2016-12-10 05:10:49 +00:00
|
|
|
impl ::std::error::Error for Error {
|
|
|
|
fn cause(&self) -> Option<&::std::error::Error> {
|
|
|
|
match *self {
|
2017-07-20 17:50:50 +00:00
|
|
|
Error::ContextCreation(ref err) => Some(err),
|
2016-12-10 05:10:49 +00:00
|
|
|
Error::Context(ref err) => Some(err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match *self {
|
2017-07-20 17:50:50 +00:00
|
|
|
Error::ContextCreation(ref _err) => "Error creating gl context",
|
2016-12-10 05:10:49 +00:00
|
|
|
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 {
|
2018-09-20 15:24:26 +00:00
|
|
|
Error::ContextCreation(ref err) => write!(f, "Error creating GL context; {}", err),
|
|
|
|
Error::Context(ref err) => write!(f, "Error operating on render context; {}", err),
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<glutin::CreationError> for Error {
|
|
|
|
fn from(val: glutin::CreationError) -> Error {
|
2017-07-20 17:50:50 +00:00
|
|
|
Error::ContextCreation(val)
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<glutin::ContextError> for Error {
|
|
|
|
fn from(val: glutin::ContextError) -> Error {
|
|
|
|
Error::Context(val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 11:16:01 +00:00
|
|
|
fn create_gl_window(
|
|
|
|
window: WindowBuilder,
|
|
|
|
event_loop: &EventsLoop,
|
|
|
|
srgb: bool,
|
|
|
|
) -> ::std::result::Result<glutin::GlWindow, glutin::CreationError> {
|
2018-11-10 16:08:48 +00:00
|
|
|
let context = ContextBuilder::new()
|
|
|
|
.with_srgb(srgb)
|
|
|
|
.with_vsync(true)
|
|
|
|
.with_hardware_acceleration(None);
|
2018-03-13 11:16:01 +00:00
|
|
|
::glutin::GlWindow::new(window, context, event_loop)
|
|
|
|
}
|
|
|
|
|
2016-12-10 05:10:49 +00:00
|
|
|
impl Window {
|
|
|
|
/// Create a new window
|
|
|
|
///
|
|
|
|
/// This creates a window and fully initializes a window.
|
2018-09-20 15:24:26 +00:00
|
|
|
pub fn new(options: &Options, window_config: &WindowConfig) -> Result<Window> {
|
2017-07-20 17:50:50 +00:00
|
|
|
let event_loop = EventsLoop::new();
|
2017-07-25 00:54:06 +00:00
|
|
|
|
2018-06-18 05:26:54 +00:00
|
|
|
let title = options.title.as_ref().map_or(DEFAULT_TITLE, |t| t);
|
2018-10-16 17:02:52 +00:00
|
|
|
let class = options.class.as_ref().map_or(DEFAULT_TITLE, |c| c);
|
2018-09-20 15:24:26 +00:00
|
|
|
let window_builder = Window::get_platform_window(title, window_config);
|
2018-06-18 05:26:54 +00:00
|
|
|
let window_builder = Window::platform_builder_ext(window_builder, &class);
|
2018-05-15 03:21:06 +00:00
|
|
|
let window = create_gl_window(window_builder.clone(), &event_loop, false)
|
|
|
|
.or_else(|_| create_gl_window(window_builder, &event_loop, true))?;
|
2018-01-15 16:19:32 +00:00
|
|
|
window.show();
|
2016-12-10 05:10:49 +00:00
|
|
|
|
2017-10-22 18:34:31 +00:00
|
|
|
// Text cursor
|
2017-12-24 20:15:42 +00:00
|
|
|
window.set_cursor(GlutinMouseCursor::Text);
|
2017-10-22 18:34:31 +00:00
|
|
|
|
2017-09-28 00:29:44 +00:00
|
|
|
// Make the context current so OpenGL operations can run
|
2016-12-10 05:10:49 +00:00
|
|
|
unsafe {
|
|
|
|
window.make_current()?;
|
|
|
|
}
|
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
// Set OpenGL symbol loader. This call MUST be after window.make_current on windows.
|
|
|
|
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
|
|
|
|
|
2017-04-26 17:26:46 +00:00
|
|
|
let window = Window {
|
2018-03-04 22:40:15 +00:00
|
|
|
event_loop,
|
|
|
|
window,
|
2018-11-01 17:23:49 +00:00
|
|
|
mouse_visible: true,
|
2018-09-19 21:37:37 +00:00
|
|
|
is_focused: false,
|
2017-04-26 17:26:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
window.run_os_extensions();
|
|
|
|
|
|
|
|
Ok(window)
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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 {
|
2018-11-10 16:08:48 +00:00
|
|
|
scale_factor: self.window.get_hidpi_factor(),
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-10 16:08:48 +00:00
|
|
|
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);
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-11-10 16:08:48 +00:00
|
|
|
pub fn hidpi_factor(&self) -> f64 {
|
|
|
|
self.window.get_hidpi_factor()
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn create_window_proxy(&self) -> Proxy {
|
2016-12-11 06:44:13 +00:00
|
|
|
Proxy {
|
2017-07-20 17:50:50 +00:00
|
|
|
inner: self.event_loop.create_proxy(),
|
2016-12-11 06:44:13 +00:00
|
|
|
}
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn swap_buffers(&self) -> Result<()> {
|
2018-09-20 15:24:26 +00:00
|
|
|
self.window.swap_buffers().map_err(From::from)
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
2016-12-30 02:38:22 +00:00
|
|
|
/// Poll for any available events
|
2016-12-10 05:10:49 +00:00
|
|
|
#[inline]
|
2017-07-20 17:50:50 +00:00
|
|
|
pub fn poll_events<F>(&mut self, func: F)
|
2018-09-20 15:24:26 +00:00
|
|
|
where
|
|
|
|
F: FnMut(Event),
|
2017-07-20 17:50:50 +00:00
|
|
|
{
|
|
|
|
self.event_loop.poll_events(func);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-11-10 16:08:48 +00:00
|
|
|
pub fn resize(&self, size: PhysicalSize) {
|
|
|
|
self.window.resize(size);
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Block waiting for events
|
|
|
|
#[inline]
|
2017-07-20 17:50:50 +00:00
|
|
|
pub fn wait_events<F>(&mut self, func: F)
|
2018-09-20 15:24:26 +00:00
|
|
|
where
|
|
|
|
F: FnMut(Event) -> ControlFlow,
|
2017-07-20 17:50:50 +00:00
|
|
|
{
|
|
|
|
self.event_loop.run_forever(func);
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
2017-01-11 05:21:19 +00:00
|
|
|
|
|
|
|
/// Set the window title
|
|
|
|
#[inline]
|
2018-10-16 17:02:52 +00:00
|
|
|
pub fn set_title(&self, _title: &str) {
|
|
|
|
// Because winpty doesn't know anything about OSC escapes this gets set to an empty
|
|
|
|
// string on windows
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
self.window.set_title(_title);
|
2017-01-11 05:21:19 +00:00
|
|
|
}
|
2017-02-22 19:52:37 +00:00
|
|
|
|
2017-12-24 20:15:42 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn set_mouse_cursor(&self, cursor: MouseCursor) {
|
|
|
|
self.window.set_cursor(match cursor {
|
|
|
|
MouseCursor::Arrow => GlutinMouseCursor::Arrow,
|
|
|
|
MouseCursor::Text => GlutinMouseCursor::Text,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-01 17:23:49 +00:00
|
|
|
/// Set mouse cursor visible
|
|
|
|
pub fn set_mouse_visible(&mut self, visible: bool) {
|
|
|
|
if visible != self.mouse_visible {
|
|
|
|
self.mouse_visible = visible;
|
2018-11-10 16:08:48 +00:00
|
|
|
self.window.hide_cursor(!visible);
|
2017-02-22 20:46:08 +00:00
|
|
|
}
|
2017-02-22 19:52:37 +00:00
|
|
|
}
|
2017-05-28 03:08:28 +00:00
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
#[cfg(
|
|
|
|
any(
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "openbsd"
|
|
|
|
)
|
|
|
|
)]
|
2018-06-07 16:53:16 +00:00
|
|
|
fn platform_builder_ext(window_builder: WindowBuilder, wm_class: &str) -> WindowBuilder {
|
2018-05-15 03:21:06 +00:00
|
|
|
use glutin::os::unix::WindowBuilderExt;
|
2018-06-07 16:53:16 +00:00
|
|
|
window_builder.with_class(wm_class.to_owned(), "Alacritty".to_owned())
|
2017-07-25 00:54:06 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
#[cfg(
|
|
|
|
not(
|
|
|
|
any(
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "openbsd"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)]
|
2018-06-07 16:53:16 +00:00
|
|
|
fn platform_builder_ext(window_builder: WindowBuilder, _: &str) -> WindowBuilder {
|
2018-05-15 03:21:06 +00:00
|
|
|
window_builder
|
2017-07-25 00:54:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(not(any(target_os = "macos", windows)))]
|
2018-09-20 15:24:26 +00:00
|
|
|
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
|
|
|
|
let decorations = match window_config.decorations() {
|
|
|
|
Decorations::None => false,
|
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
|
|
|
|
WindowBuilder::new()
|
|
|
|
.with_title(title)
|
|
|
|
.with_visibility(false)
|
|
|
|
.with_transparency(true)
|
|
|
|
.with_decorations(decorations)
|
|
|
|
}
|
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
pub fn get_platform_window(title: &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_window_icon(Some(icon))
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
|
|
|
|
use glutin::os::macos::WindowBuilderExt;
|
|
|
|
|
|
|
|
let window = WindowBuilder::new()
|
|
|
|
.with_title(title)
|
|
|
|
.with_visibility(false)
|
|
|
|
.with_transparency(true);
|
|
|
|
|
|
|
|
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"
|
|
|
|
)
|
|
|
|
)]
|
2017-10-21 23:03:58 +00:00
|
|
|
pub fn set_urgent(&self, is_urgent: bool) {
|
|
|
|
use glutin::os::unix::WindowExt;
|
2018-05-15 03:21:06 +00:00
|
|
|
self.window.set_urgent(is_urgent);
|
2017-10-21 23:03:58 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
#[cfg(
|
|
|
|
not(
|
|
|
|
any(
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "openbsd"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)]
|
2018-05-15 03:21:06 +00:00
|
|
|
pub fn set_urgent(&self, _is_urgent: bool) {}
|
2017-10-21 23:03:58 +00:00
|
|
|
|
2018-11-10 16:08:48 +00:00
|
|
|
pub fn set_ime_spot(&self, pos: LogicalPosition) {
|
|
|
|
self.window.set_ime_spot(pos);
|
2017-07-25 00:54:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
2017-05-28 03:08:28 +00:00
|
|
|
pub fn get_window_id(&self) -> Option<usize> {
|
|
|
|
use glutin::os::unix::WindowExt;
|
|
|
|
|
2017-07-20 17:50:50 +00:00
|
|
|
match self.window.get_xlib_window() {
|
2017-05-28 03:08:28 +00:00
|
|
|
Some(xlib_window) => Some(xlib_window as usize),
|
2018-09-20 15:24:26 +00:00
|
|
|
None => None,
|
2017-05-28 03:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 17:02:52 +00:00
|
|
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
2017-05-28 03:08:28 +00:00
|
|
|
pub fn get_window_id(&self) -> Option<usize> {
|
|
|
|
None
|
|
|
|
}
|
2018-07-22 00:38:53 +00:00
|
|
|
|
|
|
|
/// Hide the window
|
|
|
|
pub fn hide(&self) {
|
|
|
|
self.window.hide();
|
|
|
|
}
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 17:26:46 +00:00
|
|
|
pub trait OsExtensions {
|
|
|
|
fn run_os_extensions(&self) {}
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
#[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")
|
|
|
|
)]
|
2017-04-26 17:26:46 +00:00
|
|
|
impl OsExtensions for Window {
|
|
|
|
fn run_os_extensions(&self) {
|
2017-07-20 17:50:50 +00:00
|
|
|
use glutin::os::unix::WindowExt;
|
|
|
|
use libc::getpid;
|
2018-09-20 15:24:26 +00:00
|
|
|
use std::ffi::CStr;
|
|
|
|
use std::ptr;
|
|
|
|
use x11_dl::xlib::{self, PropModeReplace, XA_CARDINAL};
|
2017-04-26 17:26:46 +00:00
|
|
|
|
2017-07-20 17:50:50 +00:00
|
|
|
let xlib_display = self.window.get_xlib_display();
|
|
|
|
let xlib_window = self.window.get_xlib_window();
|
2017-04-26 17:26:46 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2018-09-20 15:24:26 +00:00
|
|
|
(xlib.XChangeProperty)(
|
|
|
|
xlib_display as _,
|
|
|
|
xlib_window as _,
|
|
|
|
atom,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32,
|
|
|
|
PropModeReplace,
|
|
|
|
&pid as *const i32 as *const u8,
|
|
|
|
1,
|
|
|
|
);
|
2017-04-26 17:26:46 +00:00
|
|
|
}
|
|
|
|
// 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 {
|
2018-09-20 15:24:26 +00:00
|
|
|
(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(),
|
|
|
|
);
|
2017-04-26 17:26:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-10 05:10:49 +00:00
|
|
|
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) {
|
2017-07-20 17:50:50 +00:00
|
|
|
self.inner.wakeup().unwrap();
|
2016-12-10 05:10:49 +00:00
|
|
|
}
|
|
|
|
}
|