mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 13:51:30 +11:00
Window icons (#497)
This commit is contained in:
parent
1e97103094
commit
102dd07456
|
@ -16,6 +16,8 @@
|
||||||
- On X11, drag and drop now works reliably in release mode.
|
- On X11, drag and drop now works reliably in release mode.
|
||||||
- Added `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` to X11, allowing for more optional hints to be set.
|
- Added `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` to X11, allowing for more optional hints to be set.
|
||||||
- Rework of the wayland backend, migrating it to use [Smithay's Client Toolkit](https://github.com/Smithay/client-toolkit).
|
- Rework of the wayland backend, migrating it to use [Smithay's Client Toolkit](https://github.com/Smithay/client-toolkit).
|
||||||
|
- Added `WindowBuilder::with_window_icon` and `Window::set_window_icon`, finally making it possible to set the window icon on Windows and X11. The `icon_loading` feature can be enabled to allow for icons to be easily loaded; see example program `window_icon.rs` for usage.
|
||||||
|
- Windows additionally has `WindowBuilderExt::with_taskbar_icon` and `WindowExt::set_taskbar_icon`.
|
||||||
|
|
||||||
# Version 0.13.1 (2018-04-26)
|
# Version 0.13.1 (2018-04-26)
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,13 @@ repository = "https://github.com/tomaka/winit"
|
||||||
documentation = "https://docs.rs/winit"
|
documentation = "https://docs.rs/winit"
|
||||||
categories = ["gui"]
|
categories = ["gui"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
icon_loading = ["image"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
image = { version = "0.19", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies.android_glue]
|
[target.'cfg(target_os = "android")'.dependencies.android_glue]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
|
|
BIN
examples/icon.png
Normal file
BIN
examples/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
95
examples/window_icon.rs
Normal file
95
examples/window_icon.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// Heads up: you need to compile this example with `--features icon_loading`.
|
||||||
|
// `Icon::from_path` won't be available otherwise, though for your own applications, you could use
|
||||||
|
// `Icon::from_rgba` if you don't want to depend on the `image` crate.
|
||||||
|
|
||||||
|
extern crate winit;
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
extern crate image;
|
||||||
|
|
||||||
|
use winit::Icon;
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
fn main() {
|
||||||
|
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
|
||||||
|
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
|
||||||
|
// since it seems to work well enough in most cases. Be careful about going too high, or
|
||||||
|
// you'll be bitten by the low-quality downscaling built into the WM.
|
||||||
|
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");
|
||||||
|
// While `Icon::from_path` is the most straightforward, you have a few other options. If you
|
||||||
|
// want to use the `include_bytes` macro, then pass the result to `Icon::from_bytes`. See the
|
||||||
|
// docs for the full list of options (you'll have to generate the docs with the `icon_loading`
|
||||||
|
// feature enabled).
|
||||||
|
let icon = Icon::from_path(path).expect("Failed to open icon");
|
||||||
|
|
||||||
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
|
|
||||||
|
let window = winit::WindowBuilder::new()
|
||||||
|
.with_title("An iconic window!")
|
||||||
|
// At present, this only does anything on Windows and X11, so if you want to save load
|
||||||
|
// time, you can put icon loading behind a function that returns `None` on other platforms.
|
||||||
|
.with_window_icon(Some(icon))
|
||||||
|
.build(&events_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
events_loop.run_forever(|event| {
|
||||||
|
if let winit::Event::WindowEvent { event, .. } = event {
|
||||||
|
use winit::WindowEvent::*;
|
||||||
|
match event {
|
||||||
|
CloseRequested => return winit::ControlFlow::Break,
|
||||||
|
DroppedFile(path) => {
|
||||||
|
use image::GenericImage;
|
||||||
|
|
||||||
|
let icon_image = image::open(path).expect("Failed to open window icon");
|
||||||
|
|
||||||
|
let (width, height) = icon_image.dimensions();
|
||||||
|
const DESIRED_SIZE: u32 = 32;
|
||||||
|
let (new_width, new_height) = if width == height {
|
||||||
|
(DESIRED_SIZE, DESIRED_SIZE)
|
||||||
|
} else {
|
||||||
|
// Note that this will never divide by zero, due to the previous condition.
|
||||||
|
let aspect_adjustment = DESIRED_SIZE as f64
|
||||||
|
/ std::cmp::max(width, height) as f64;
|
||||||
|
(
|
||||||
|
(width as f64 * aspect_adjustment) as u32,
|
||||||
|
(height as f64 * aspect_adjustment) as u32,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// By scaling the icon ourselves, we get higher-quality filtering and save
|
||||||
|
// some memory.
|
||||||
|
let icon = image::imageops::resize(
|
||||||
|
&icon_image,
|
||||||
|
new_width,
|
||||||
|
new_height,
|
||||||
|
image::FilterType::Lanczos3,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (offset_x, offset_y) = (
|
||||||
|
(DESIRED_SIZE - new_width) / 2,
|
||||||
|
(DESIRED_SIZE - new_height) / 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut canvas = image::ImageBuffer::new(DESIRED_SIZE, DESIRED_SIZE);
|
||||||
|
image::imageops::replace(
|
||||||
|
&mut canvas,
|
||||||
|
&icon,
|
||||||
|
offset_x,
|
||||||
|
offset_y,
|
||||||
|
);
|
||||||
|
|
||||||
|
window.set_window_icon(Some(canvas.into()));
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winit::ControlFlow::Continue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "icon_loading"))]
|
||||||
|
fn main() {
|
||||||
|
print!(
|
||||||
|
r#"This example requires the `icon_loading` feature:
|
||||||
|
cargo run --example window_icon --features icon_loading
|
||||||
|
"#);
|
||||||
|
}
|
160
src/icon.rs
Normal file
160
src/icon.rs
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
use std::{fmt, mem};
|
||||||
|
use std::error::Error;
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
use std::io::{BufRead, Seek};
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
use image;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct Pixel {
|
||||||
|
pub(crate) r: u8,
|
||||||
|
pub(crate) g: u8,
|
||||||
|
pub(crate) b: u8,
|
||||||
|
pub(crate) a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
/// An error produced when using `Icon::from_rgba` with invalid arguments.
|
||||||
|
pub enum BadIcon {
|
||||||
|
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
|
||||||
|
/// safely interpreted as 32bpp RGBA pixels.
|
||||||
|
ByteCountNotDivisibleBy4 {
|
||||||
|
byte_count: usize,
|
||||||
|
},
|
||||||
|
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
|
||||||
|
/// At least one of your arguments is incorrect.
|
||||||
|
DimensionsVsPixelCount {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
width_x_height: usize,
|
||||||
|
pixel_count: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BadIcon {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = match self {
|
||||||
|
&BadIcon::ByteCountNotDivisibleBy4 { byte_count } => format!(
|
||||||
|
"The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
|
||||||
|
byte_count,
|
||||||
|
),
|
||||||
|
&BadIcon::DimensionsVsPixelCount {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
width_x_height,
|
||||||
|
pixel_count,
|
||||||
|
} => format!(
|
||||||
|
"The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
|
||||||
|
width, height, pixel_count, width_x_height,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
write!(formatter, "{}", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for BadIcon {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"A valid icon cannot be created from these arguments"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&Error> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
/// An icon used for the window titlebar, taskbar, etc.
|
||||||
|
///
|
||||||
|
/// Enabling the `icon_loading` feature provides you with several convenience methods for creating
|
||||||
|
/// an `Icon` from any format supported by the [image](https://github.com/PistonDevelopers/image)
|
||||||
|
/// crate.
|
||||||
|
pub struct Icon {
|
||||||
|
pub(crate) rgba: Vec<u8>,
|
||||||
|
pub(crate) width: u32,
|
||||||
|
pub(crate) height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Icon {
|
||||||
|
/// Creates an `Icon` from 32bpp RGBA data.
|
||||||
|
///
|
||||||
|
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
||||||
|
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
||||||
|
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
|
||||||
|
if rgba.len() % PIXEL_SIZE != 0 {
|
||||||
|
return Err(BadIcon::ByteCountNotDivisibleBy4 { byte_count: rgba.len() });
|
||||||
|
}
|
||||||
|
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||||
|
if pixel_count != (width * height) as usize {
|
||||||
|
Err(BadIcon::DimensionsVsPixelCount {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
width_x_height: (width * height) as usize,
|
||||||
|
pixel_count,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(Icon { rgba, width, height })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
/// Loads an `Icon` from the path of an image on the filesystem.
|
||||||
|
pub fn from_path<P: AsRef<Path>>(path: P) -> image::ImageResult<Self> {
|
||||||
|
image::open(path).map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
/// Loads an `Icon` from anything implementing `BufRead` and `Seek`.
|
||||||
|
pub fn from_reader<R: BufRead + Seek>(
|
||||||
|
reader: R,
|
||||||
|
format: image::ImageFormat,
|
||||||
|
) -> image::ImageResult<Self> {
|
||||||
|
image::load(reader, format).map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
/// Loads an `Icon` from the unprocessed bytes of an image file.
|
||||||
|
/// Uses heuristics to determine format.
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> image::ImageResult<Self> {
|
||||||
|
image::load_from_memory(bytes).map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
/// Loads an `Icon` from the unprocessed bytes of an image.
|
||||||
|
pub fn from_bytes_with_format(
|
||||||
|
bytes: &[u8],
|
||||||
|
format: image::ImageFormat,
|
||||||
|
) -> image::ImageResult<Self> {
|
||||||
|
image::load_from_memory_with_format(bytes, format).map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
impl From<image::DynamicImage> for Icon {
|
||||||
|
fn from(image: image::DynamicImage) -> Self {
|
||||||
|
use image::{GenericImage, Pixel};
|
||||||
|
let (width, height) = image.dimensions();
|
||||||
|
let mut rgba = Vec::with_capacity((width * height) as usize * PIXEL_SIZE);
|
||||||
|
for (_, _, pixel) in image.pixels() {
|
||||||
|
rgba.extend_from_slice(&pixel.to_rgba().data);
|
||||||
|
}
|
||||||
|
Icon { rgba, width, height }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
impl From<image::RgbaImage> for Icon {
|
||||||
|
fn from(buf: image::RgbaImage) -> Self {
|
||||||
|
let (width, height) = buf.dimensions();
|
||||||
|
let mut rgba = Vec::with_capacity((width * height) as usize * PIXEL_SIZE);
|
||||||
|
for (_, _, pixel) in buf.enumerate_pixels() {
|
||||||
|
rgba.extend_from_slice(&pixel.data);
|
||||||
|
}
|
||||||
|
Icon { rgba, width, height }
|
||||||
|
}
|
||||||
|
}
|
11
src/lib.rs
11
src/lib.rs
|
@ -83,8 +83,9 @@
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
#[cfg(feature = "icon_loading")]
|
||||||
|
extern crate image;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -109,10 +110,12 @@ extern crate smithay_client_toolkit as sctk;
|
||||||
|
|
||||||
pub use events::*;
|
pub use events::*;
|
||||||
pub use window::{AvailableMonitorsIter, MonitorId};
|
pub use window::{AvailableMonitorsIter, MonitorId};
|
||||||
|
pub use icon::*;
|
||||||
|
|
||||||
mod platform;
|
mod platform;
|
||||||
mod events;
|
mod events;
|
||||||
mod window;
|
mod window;
|
||||||
|
mod icon;
|
||||||
|
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|
||||||
|
@ -439,6 +442,11 @@ pub struct WindowAttributes {
|
||||||
/// The default is `true`.
|
/// The default is `true`.
|
||||||
pub decorations: bool,
|
pub decorations: bool,
|
||||||
|
|
||||||
|
/// The window icon.
|
||||||
|
///
|
||||||
|
/// The default is `None`.
|
||||||
|
pub window_icon: Option<Icon>,
|
||||||
|
|
||||||
/// [iOS only] Enable multitouch,
|
/// [iOS only] Enable multitouch,
|
||||||
/// see [multipleTouchEnabled](https://developer.apple.com/documentation/uikit/uiview/1622519-multipletouchenabled)
|
/// see [multipleTouchEnabled](https://developer.apple.com/documentation/uikit/uiview/1622519-multipletouchenabled)
|
||||||
pub multitouch: bool,
|
pub multitouch: bool,
|
||||||
|
@ -457,6 +465,7 @@ impl Default for WindowAttributes {
|
||||||
visible: true,
|
visible: true,
|
||||||
transparent: false,
|
transparent: false,
|
||||||
decorations: true,
|
decorations: true,
|
||||||
|
window_icon: None,
|
||||||
multitouch: false,
|
multitouch: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
#![cfg(target_os = "windows")]
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use MonitorId;
|
|
||||||
use DeviceId;
|
|
||||||
use Window;
|
|
||||||
use WindowBuilder;
|
|
||||||
use winapi::shared::windef::HWND;
|
use winapi::shared::windef::HWND;
|
||||||
|
|
||||||
|
use {DeviceId, Icon, MonitorId, Window, WindowBuilder};
|
||||||
|
|
||||||
/// Additional methods on `Window` that are specific to Windows.
|
/// Additional methods on `Window` that are specific to Windows.
|
||||||
pub trait WindowExt {
|
pub trait WindowExt {
|
||||||
/// Returns the native handle that is used by this window.
|
/// Returns the native handle that is used by this window.
|
||||||
///
|
///
|
||||||
/// The pointer will become invalid when the native window was destroyed.
|
/// The pointer will become invalid when the native window was destroyed.
|
||||||
fn get_hwnd(&self) -> *mut libc::c_void;
|
fn get_hwnd(&self) -> *mut libc::c_void;
|
||||||
|
|
||||||
|
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
|
||||||
|
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowExt for Window {
|
impl WindowExt for Window {
|
||||||
|
@ -21,20 +23,34 @@ impl WindowExt for Window {
|
||||||
fn get_hwnd(&self) -> *mut libc::c_void {
|
fn get_hwnd(&self) -> *mut libc::c_void {
|
||||||
self.window.hwnd() as *mut _
|
self.window.hwnd() as *mut _
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
|
||||||
|
self.window.set_taskbar_icon(taskbar_icon)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional methods on `WindowBuilder` that are specific to Windows.
|
/// Additional methods on `WindowBuilder` that are specific to Windows.
|
||||||
pub trait WindowBuilderExt {
|
pub trait WindowBuilderExt {
|
||||||
|
/// Sets a parent to the window to be created.
|
||||||
fn with_parent_window(self, parent: HWND) -> WindowBuilder;
|
fn with_parent_window(self, parent: HWND) -> WindowBuilder;
|
||||||
|
|
||||||
|
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
|
||||||
|
fn with_taskbar_icon(self, taskbar_icon: Option<Icon>) -> WindowBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowBuilderExt for WindowBuilder {
|
impl WindowBuilderExt for WindowBuilder {
|
||||||
/// Sets a parent to the window to be created.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
|
fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
|
||||||
self.platform_specific.parent = Some(parent);
|
self.platform_specific.parent = Some(parent);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_taskbar_icon(mut self, taskbar_icon: Option<Icon>) -> WindowBuilder {
|
||||||
|
self.platform_specific.taskbar_icon = taskbar_icon;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional methods on `MonitorId` that are specific to Windows.
|
/// Additional methods on `MonitorId` that are specific to Windows.
|
||||||
|
|
|
@ -201,8 +201,8 @@ pub struct PlatformSpecificWindowBuilderAttributes;
|
||||||
pub struct PlatformSpecificHeadlessBuilderAttributes;
|
pub struct PlatformSpecificHeadlessBuilderAttributes;
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(_: &EventsLoop, win_attribs: &WindowAttributes,
|
pub fn new(_: &EventsLoop, win_attribs: WindowAttributes,
|
||||||
_: &PlatformSpecificWindowBuilderAttributes)
|
_: PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window, CreationError>
|
-> Result<Window, CreationError>
|
||||||
{
|
{
|
||||||
// not implemented
|
// not implemented
|
||||||
|
@ -323,6 +323,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||||
RootMonitorId{inner: MonitorId}
|
RootMonitorId{inner: MonitorId}
|
||||||
|
|
|
@ -347,8 +347,8 @@ fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(events_loop: &EventsLoop, attribs: &::WindowAttributes,
|
pub fn new(events_loop: &EventsLoop, attribs: ::WindowAttributes,
|
||||||
_pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
_pl_attribs: PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window, ::CreationError>
|
-> Result<Window, ::CreationError>
|
||||||
{
|
{
|
||||||
if events_loop.window.lock().unwrap().is_some() {
|
if events_loop.window.lock().unwrap().is_some() {
|
||||||
|
@ -543,6 +543,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> ::MonitorId {
|
pub fn get_current_monitor(&self) -> ::MonitorId {
|
||||||
::MonitorId{inner: MonitorId}
|
::MonitorId{inner: MonitorId}
|
||||||
|
|
|
@ -263,7 +263,7 @@ pub struct DeviceId;
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes;
|
pub struct PlatformSpecificWindowBuilderAttributes;
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(ev: &EventsLoop, _: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
|
pub fn new(ev: &EventsLoop, _: WindowAttributes, _: PlatformSpecificWindowBuilderAttributes)
|
||||||
-> Result<Window, CreationError>
|
-> Result<Window, CreationError>
|
||||||
{
|
{
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
|
@ -370,6 +370,11 @@ impl Window {
|
||||||
// N/A
|
// N/A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||||
RootMonitorId{inner: MonitorId}
|
RootMonitorId{inner: MonitorId}
|
||||||
|
|
|
@ -6,12 +6,20 @@ use std::ffi::CStr;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
// `std::os::raw::c_void` and `libc::c_void` are NOT interchangeable!
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
|
use {
|
||||||
|
CreationError,
|
||||||
|
CursorState,
|
||||||
|
EventsLoopClosed,
|
||||||
|
Icon,
|
||||||
|
MouseCursor,
|
||||||
|
ControlFlow,
|
||||||
|
WindowAttributes,
|
||||||
|
};
|
||||||
use window::MonitorId as RootMonitorId;
|
use window::MonitorId as RootMonitorId;
|
||||||
use self::x11::XConnection;
|
use self::x11::{XConnection, XError};
|
||||||
use self::x11::XError;
|
|
||||||
use self::x11::ffi::XVisualInfo;
|
use self::x11::ffi::XVisualInfo;
|
||||||
pub use self::x11::XNotSupported;
|
pub use self::x11::XNotSupported;
|
||||||
|
|
||||||
|
@ -109,18 +117,17 @@ impl MonitorId {
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(events_loop: &EventsLoop,
|
pub fn new(
|
||||||
window: &::WindowAttributes,
|
events_loop: &EventsLoop,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
attribs: WindowAttributes,
|
||||||
-> Result<Self, CreationError>
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
{
|
) -> Result<Self, CreationError> {
|
||||||
match *events_loop {
|
match *events_loop {
|
||||||
EventsLoop::Wayland(ref evlp) => {
|
EventsLoop::Wayland(ref events_loop) => {
|
||||||
wayland::Window::new(evlp, window).map(Window::Wayland)
|
wayland::Window::new(events_loop, attribs).map(Window::Wayland)
|
||||||
},
|
},
|
||||||
|
EventsLoop::X(ref events_loop) => {
|
||||||
EventsLoop::X(ref el) => {
|
x11::Window::new(events_loop, attribs, pl_attribs).map(Window::X)
|
||||||
x11::Window::new(el, window, pl_attribs).map(Window::X)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,6 +300,14 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||||
|
match self {
|
||||||
|
&Window::X(ref w) => w.set_window_icon(window_icon),
|
||||||
|
&Window::Wayland(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -23,9 +23,8 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError> {
|
pub fn new(evlp: &EventsLoop, attributes: WindowAttributes) -> Result<Window, CreationError> {
|
||||||
let (width, height) = attributes.dimensions.unwrap_or((800, 600));
|
let (width, height) = attributes.dimensions.unwrap_or((800, 600));
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
let size = Arc::new(Mutex::new((width, height)));
|
let size = Arc::new(Mutex::new((width, height)));
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,6 @@
|
||||||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
|
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
|
||||||
|
|
||||||
pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};
|
|
||||||
pub use self::window::{Window2, XWindow};
|
|
||||||
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
|
||||||
|
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
|
||||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
|
||||||
use {CreationError, Event, EventsLoopClosed, WindowEvent, DeviceEvent,
|
|
||||||
KeyboardInput, ControlFlow};
|
|
||||||
use events::ModifiersState;
|
|
||||||
|
|
||||||
use std::{mem, ptr, slice};
|
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use std::sync::atomic::{self, AtomicBool};
|
|
||||||
use std::sync::mpsc;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::os::raw::*;
|
|
||||||
|
|
||||||
use libc::{self, setlocale, LC_CTYPE};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
|
|
||||||
mod events;
|
mod events;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
mod window;
|
mod window;
|
||||||
|
@ -31,6 +9,33 @@ mod dnd;
|
||||||
mod ime;
|
mod ime;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};
|
||||||
|
pub use self::window::{Window2, XWindow};
|
||||||
|
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
||||||
|
|
||||||
|
use std::{mem, ptr, slice};
|
||||||
|
use std::sync::{Arc, mpsc, Weak};
|
||||||
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::os::raw::*;
|
||||||
|
|
||||||
|
use libc::{self, setlocale, LC_CTYPE};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use {
|
||||||
|
ControlFlow,
|
||||||
|
CreationError,
|
||||||
|
DeviceEvent,
|
||||||
|
Event,
|
||||||
|
EventsLoopClosed,
|
||||||
|
KeyboardInput,
|
||||||
|
WindowAttributes,
|
||||||
|
WindowEvent,
|
||||||
|
};
|
||||||
|
use events::ModifiersState;
|
||||||
|
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||||
use self::dnd::{Dnd, DndState};
|
use self::dnd::{Dnd, DndState};
|
||||||
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
||||||
|
|
||||||
|
@ -1150,10 +1155,11 @@ impl ::std::ops::Deref for Window {
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
x_events_loop: &EventsLoop,
|
x_events_loop: &EventsLoop,
|
||||||
window: &::WindowAttributes,
|
attribs: WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes
|
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
||||||
) -> Result<Self, CreationError> {
|
) -> Result<Self, CreationError> {
|
||||||
let win = Arc::new(Window2::new(&x_events_loop, window, pl_attribs)?);
|
let multitouch = attribs.multitouch;
|
||||||
|
let win = Arc::new(Window2::new(&x_events_loop, attribs, pl_attribs)?);
|
||||||
|
|
||||||
x_events_loop.shared_state
|
x_events_loop.shared_state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -1166,7 +1172,7 @@ impl Window {
|
||||||
|
|
||||||
x_events_loop.windows.lock().insert(win.id(), WindowData {
|
x_events_loop.windows.lock().insert(win.id(), WindowData {
|
||||||
config: Default::default(),
|
config: Default::default(),
|
||||||
multitouch: window.multitouch,
|
multitouch,
|
||||||
cursor_pos: None,
|
cursor_pos: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
34
src/platform/linux/x11/util/icon.rs
Normal file
34
src/platform/linux/x11/util/icon.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
use {Icon, Pixel, PIXEL_SIZE};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Pixel {
|
||||||
|
pub fn to_packed_argb(&self) -> Cardinal {
|
||||||
|
let mut cardinal = 0;
|
||||||
|
assert!(CARDINAL_SIZE >= PIXEL_SIZE);
|
||||||
|
let as_bytes = &mut cardinal as *mut _ as *mut u8;
|
||||||
|
unsafe {
|
||||||
|
*as_bytes.offset(0) = self.b;
|
||||||
|
*as_bytes.offset(1) = self.g;
|
||||||
|
*as_bytes.offset(2) = self.r;
|
||||||
|
*as_bytes.offset(3) = self.a;
|
||||||
|
}
|
||||||
|
cardinal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Icon {
|
||||||
|
pub fn to_cardinals(&self) -> Vec<Cardinal> {
|
||||||
|
assert_eq!(self.rgba.len() % PIXEL_SIZE, 0);
|
||||||
|
let pixel_count = self.rgba.len() / PIXEL_SIZE;
|
||||||
|
assert_eq!(pixel_count, (self.width * self.height) as usize);
|
||||||
|
let mut data = Vec::with_capacity(pixel_count);
|
||||||
|
data.push(self.width as Cardinal);
|
||||||
|
data.push(self.height as Cardinal);
|
||||||
|
let pixels = self.rgba.as_ptr() as *const Pixel;
|
||||||
|
for pixel_index in 0..pixel_count {
|
||||||
|
let pixel = unsafe { &*pixels.offset(pixel_index as isize) };
|
||||||
|
data.push(pixel.to_packed_argb());
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
mod atom;
|
mod atom;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod hint;
|
mod hint;
|
||||||
|
mod icon;
|
||||||
mod input;
|
mod input;
|
||||||
mod window_property;
|
mod window_property;
|
||||||
mod wm;
|
mod wm;
|
||||||
|
@ -11,6 +12,7 @@ mod wm;
|
||||||
pub use self::atom::*;
|
pub use self::atom::*;
|
||||||
pub use self::geometry::*;
|
pub use self::geometry::*;
|
||||||
pub use self::hint::*;
|
pub use self::hint::*;
|
||||||
|
pub use self::icon::*;
|
||||||
pub use self::input::*;
|
pub use self::input::*;
|
||||||
pub use self::window_property::*;
|
pub use self::window_property::*;
|
||||||
pub use self::wm::*;
|
pub use self::wm::*;
|
||||||
|
|
|
@ -3,6 +3,9 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub type Cardinal = c_long;
|
||||||
|
pub const CARDINAL_SIZE: usize = mem::size_of::<c_long>();
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum GetPropertyError {
|
pub enum GetPropertyError {
|
||||||
XError(XError),
|
XError(XError),
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
use MouseCursor;
|
use std::{cmp, mem};
|
||||||
use CreationError;
|
|
||||||
use CreationError::OsError;
|
|
||||||
use libc;
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::{mem, cmp};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::os::raw::*;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::os::raw::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use libc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use CursorState;
|
use {CursorState, Icon, MouseCursor, WindowAttributes};
|
||||||
use WindowAttributes;
|
use CreationError::{self, OsError};
|
||||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
|
||||||
|
|
||||||
use platform::MonitorId as PlatformMonitorId;
|
use platform::MonitorId as PlatformMonitorId;
|
||||||
|
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||||
use platform::x11::MonitorId as X11MonitorId;
|
use platform::x11::MonitorId as X11MonitorId;
|
||||||
use window::MonitorId as RootMonitorId;
|
|
||||||
|
|
||||||
use platform::x11::monitor::get_available_monitors;
|
use platform::x11::monitor::get_available_monitors;
|
||||||
|
use window::MonitorId as RootMonitorId;
|
||||||
|
|
||||||
use super::{ffi, util, XConnection, XError, WindowId, EventsLoop};
|
use super::{ffi, util, XConnection, XError, WindowId, EventsLoop};
|
||||||
|
|
||||||
|
@ -60,8 +55,8 @@ pub struct Window2 {
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &EventsLoop,
|
ctx: &EventsLoop,
|
||||||
window_attrs: &WindowAttributes,
|
window_attrs: WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes,
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<Window2, CreationError> {
|
) -> Result<Window2, CreationError> {
|
||||||
let xconn = &ctx.display;
|
let xconn = &ctx.display;
|
||||||
|
|
||||||
|
@ -241,6 +236,11 @@ impl Window2 {
|
||||||
}//.queue();
|
}//.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set window icons
|
||||||
|
if let Some(icon) = window_attrs.window_icon {
|
||||||
|
window.set_icon_inner(icon).queue();
|
||||||
|
}
|
||||||
|
|
||||||
// Opt into handling window close
|
// Opt into handling window close
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XSetWMProtocols)(
|
(xconn.xlib.XSetWMProtocols)(
|
||||||
|
@ -522,6 +522,53 @@ impl Window2 {
|
||||||
self.invalidate_cached_frame_extents();
|
self.invalidate_cached_frame_extents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_icon_inner(&self, icon: Icon) -> util::Flusher {
|
||||||
|
let xconn = &self.x.display;
|
||||||
|
|
||||||
|
let icon_atom = unsafe { util::get_atom(xconn, b"_NET_WM_ICON\0") }
|
||||||
|
.expect("Failed to call XInternAtom (_NET_WM_ICON)");
|
||||||
|
|
||||||
|
let data = icon.to_cardinals();
|
||||||
|
unsafe {
|
||||||
|
util::change_property(
|
||||||
|
xconn,
|
||||||
|
self.x.window,
|
||||||
|
icon_atom,
|
||||||
|
ffi::XA_CARDINAL,
|
||||||
|
util::Format::Long,
|
||||||
|
util::PropMode::Replace,
|
||||||
|
data.as_slice(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset_icon_inner(&self) -> util::Flusher {
|
||||||
|
let xconn = &self.x.display;
|
||||||
|
|
||||||
|
let icon_atom = unsafe { util::get_atom(xconn, b"_NET_WM_ICON\0") }
|
||||||
|
.expect("Failed to call XInternAtom (_NET_WM_ICON)");
|
||||||
|
|
||||||
|
let empty_data: [util::Cardinal; 0] = [];
|
||||||
|
unsafe {
|
||||||
|
util::change_property(
|
||||||
|
xconn,
|
||||||
|
self.x.window,
|
||||||
|
icon_atom,
|
||||||
|
ffi::XA_CARDINAL,
|
||||||
|
util::Format::Long,
|
||||||
|
util::PropMode::Replace,
|
||||||
|
&empty_data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_window_icon(&self, icon: Option<Icon>) {
|
||||||
|
match icon {
|
||||||
|
Some(icon) => self.set_icon_inner(icon),
|
||||||
|
None => self.unset_icon_inner(),
|
||||||
|
}.flush().expect("Failed to set icons");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XMapRaised)(self.x.display.display, self.x.window);
|
(self.x.display.xlib.XMapRaised)(self.x.display.display, self.x.window);
|
||||||
|
|
|
@ -25,8 +25,8 @@ impl ::std::ops::Deref for Window {
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
||||||
pub fn new(events_loop: &EventsLoop,
|
pub fn new(events_loop: &EventsLoop,
|
||||||
attributes: &::WindowAttributes,
|
attributes: ::WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
|
pl_attribs: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
|
||||||
{
|
{
|
||||||
let weak_shared = Arc::downgrade(&events_loop.shared);
|
let weak_shared = Arc::downgrade(&events_loop.shared);
|
||||||
let window = Arc::new(try!(Window2::new(weak_shared, attributes, pl_attribs)));
|
let window = Arc::new(try!(Window2::new(weak_shared, attributes, pl_attribs)));
|
||||||
|
|
|
@ -559,8 +559,8 @@ impl WindowExt for Window2 {
|
||||||
impl Window2 {
|
impl Window2 {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shared: Weak<Shared>,
|
shared: Weak<Shared>,
|
||||||
win_attribs: &WindowAttributes,
|
win_attribs: WindowAttributes,
|
||||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes,
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<Window2, CreationError> {
|
) -> Result<Window2, CreationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
|
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
|
||||||
|
@ -579,7 +579,7 @@ impl Window2 {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let window = match Window2::create_window(win_attribs, pl_attribs)
|
let window = match Window2::create_window(&win_attribs, &pl_attribs)
|
||||||
{
|
{
|
||||||
Some(window) => window,
|
Some(window) => window,
|
||||||
None => {
|
None => {
|
||||||
|
@ -700,8 +700,8 @@ impl Window2 {
|
||||||
|
|
||||||
fn create_window(
|
fn create_window(
|
||||||
attrs: &WindowAttributes,
|
attrs: &WindowAttributes,
|
||||||
pl_attrs: &PlatformSpecificWindowBuilderAttributes)
|
pl_attrs: &PlatformSpecificWindowBuilderAttributes
|
||||||
-> Option<IdRef> {
|
) -> Option<IdRef> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let autoreleasepool = NSAutoreleasePool::new(nil);
|
let autoreleasepool = NSAutoreleasePool::new(nil);
|
||||||
let screen = match attrs.fullscreen {
|
let screen = match attrs.fullscreen {
|
||||||
|
@ -1072,6 +1072,16 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
|
||||||
|
// macOS doesn't have window icons. Though, there is `setRepresentedFilename`, but that's
|
||||||
|
// semantically distinct and should only be used when the window is in some representing a
|
||||||
|
// specific file/directory. For instance, Terminal.app uses this for the CWD. Anyway, that
|
||||||
|
// should eventually be implemented as `WindowBuilderExt::with_represented_file` or
|
||||||
|
// something, and doesn't have anything to do with this.
|
||||||
|
// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/WinPanel/Tasks/SettingWindowTitle.html
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -279,8 +279,9 @@ impl EventsLoopProxy {
|
||||||
|
|
||||||
/// Executes a function in the background thread.
|
/// Executes a function in the background thread.
|
||||||
///
|
///
|
||||||
/// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent
|
/// Note that we use FnMut instead of FnOnce because boxing FnOnce won't work on stable Rust
|
||||||
/// to the unstable FnBox.
|
/// until 2030 when the design of Box is finally complete.
|
||||||
|
/// https://github.com/rust-lang/rust/issues/28796
|
||||||
///
|
///
|
||||||
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
|
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
|
||||||
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
|
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
|
||||||
|
@ -302,10 +303,7 @@ impl EventsLoopProxy {
|
||||||
);
|
);
|
||||||
// PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen
|
// PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen
|
||||||
// as the events loop is still alive) or if the queue is full.
|
// as the events loop is still alive) or if the queue is full.
|
||||||
assert!(
|
assert!(res != 0, "PostThreadMessage failed; is the messages queue full?");
|
||||||
res != 0,
|
|
||||||
"PostThreadMessage failed ; is the messages queue full?"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
112
src/platform/windows/icon.rs
Normal file
112
src/platform/windows/icon.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
use std::{self, mem, ptr};
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use winapi::ctypes::{c_int, wchar_t};
|
||||||
|
use winapi::shared::minwindef::{BYTE, LPARAM, WPARAM};
|
||||||
|
use winapi::shared::windef::{HICON, HWND};
|
||||||
|
use winapi::um::winuser;
|
||||||
|
|
||||||
|
use {Pixel, PIXEL_SIZE, Icon};
|
||||||
|
use platform::platform::util;
|
||||||
|
|
||||||
|
impl Pixel {
|
||||||
|
fn to_bgra(&mut self) {
|
||||||
|
mem::swap(&mut self.r, &mut self.b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum IconType {
|
||||||
|
Small = winuser::ICON_SMALL as isize,
|
||||||
|
Big = winuser::ICON_BIG as isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WinIcon {
|
||||||
|
pub handle: HICON,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WinIcon {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, util::WinError> {
|
||||||
|
let wide_path: Vec<u16> = path.as_ref().as_os_str().encode_wide().collect();
|
||||||
|
let handle = unsafe {
|
||||||
|
winuser::LoadImageW(
|
||||||
|
ptr::null_mut(),
|
||||||
|
wide_path.as_ptr() as *const wchar_t,
|
||||||
|
winuser::IMAGE_ICON,
|
||||||
|
0, // 0 indicates that we want to use the actual width
|
||||||
|
0, // and height
|
||||||
|
winuser::LR_LOADFROMFILE,
|
||||||
|
) as HICON
|
||||||
|
};
|
||||||
|
if !handle.is_null() {
|
||||||
|
Ok(WinIcon { handle })
|
||||||
|
} else {
|
||||||
|
Err(util::WinError::from_last_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_icon(icon: Icon) -> Result<Self, util::WinError> {
|
||||||
|
Self::from_rgba(icon.rgba, icon.width, icon.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_rgba(mut rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, util::WinError> {
|
||||||
|
assert_eq!(rgba.len() % PIXEL_SIZE, 0);
|
||||||
|
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||||
|
assert_eq!(pixel_count, (width * height) as usize);
|
||||||
|
let mut and_mask = Vec::with_capacity(pixel_count);
|
||||||
|
let pixels = rgba.as_mut_ptr() as *mut Pixel; // how not to write idiomatic Rust
|
||||||
|
for pixel_index in 0..pixel_count {
|
||||||
|
let pixel = unsafe { &mut *pixels.offset(pixel_index as isize) };
|
||||||
|
and_mask.push(pixel.a.wrapping_sub(std::u8::MAX)); // invert alpha channel
|
||||||
|
pixel.to_bgra();
|
||||||
|
}
|
||||||
|
assert_eq!(and_mask.len(), pixel_count);
|
||||||
|
let handle = unsafe {
|
||||||
|
winuser::CreateIcon(
|
||||||
|
ptr::null_mut(),
|
||||||
|
width as c_int,
|
||||||
|
height as c_int,
|
||||||
|
1,
|
||||||
|
(PIXEL_SIZE * 8) as BYTE,
|
||||||
|
and_mask.as_ptr() as *const BYTE,
|
||||||
|
rgba.as_ptr() as *const BYTE,
|
||||||
|
) as HICON
|
||||||
|
};
|
||||||
|
if !handle.is_null() {
|
||||||
|
Ok(WinIcon { handle })
|
||||||
|
} else {
|
||||||
|
Err(util::WinError::from_last_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
|
||||||
|
unsafe {
|
||||||
|
winuser::SendMessageW(
|
||||||
|
hwnd,
|
||||||
|
winuser::WM_SETICON,
|
||||||
|
icon_type as WPARAM,
|
||||||
|
self.handle as LPARAM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for WinIcon {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { winuser::DestroyIcon(self.handle) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
||||||
|
unsafe {
|
||||||
|
winuser::SendMessageW(
|
||||||
|
hwnd,
|
||||||
|
winuser::WM_SETICON,
|
||||||
|
icon_type as WPARAM,
|
||||||
|
0 as LPARAM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ pub use self::window::Window;
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
pub parent: Option<HWND>,
|
pub parent: Option<HWND>,
|
||||||
|
pub taskbar_icon: Option<::Icon>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
|
unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
|
||||||
|
@ -45,6 +46,7 @@ unsafe impl Sync for WindowId {}
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
mod events_loop;
|
mod events_loop;
|
||||||
|
mod icon;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
mod raw_input;
|
mod raw_input;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
|
use std::{self, mem, ptr};
|
||||||
use std::ops::BitAnd;
|
use std::ops::BitAnd;
|
||||||
|
|
||||||
use winapi::ctypes::wchar_t;
|
use winapi::ctypes::wchar_t;
|
||||||
|
use winapi::shared::minwindef::DWORD;
|
||||||
|
use winapi::um::errhandlingapi::GetLastError;
|
||||||
|
use winapi::um::winbase::{
|
||||||
|
FormatMessageW,
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
lstrlenW,
|
||||||
|
LocalFree,
|
||||||
|
};
|
||||||
|
use winapi::um::winnt::{
|
||||||
|
LPCWSTR,
|
||||||
|
MAKELANGID,
|
||||||
|
LANG_NEUTRAL,
|
||||||
|
SUBLANG_DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
||||||
where T:
|
where T:
|
||||||
|
@ -14,3 +31,42 @@ pub fn wchar_to_string(wchar: &[wchar_t]) -> String {
|
||||||
.trim_right_matches(0 as char)
|
.trim_right_matches(0 as char)
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||||
|
pub struct WinError(Option<String>);
|
||||||
|
|
||||||
|
impl WinError {
|
||||||
|
pub fn from_last_error() -> Self {
|
||||||
|
WinError(unsafe { get_last_error() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_last_error() -> Option<String> {
|
||||||
|
let err = GetLastError();
|
||||||
|
if err != 0 {
|
||||||
|
let buf_addr: LPCWSTR = {
|
||||||
|
let mut buf_addr: LPCWSTR = mem::uninitialized();
|
||||||
|
FormatMessageW(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||||
|
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||||
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
ptr::null(),
|
||||||
|
err,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as DWORD,
|
||||||
|
// This is a pointer to a pointer
|
||||||
|
&mut buf_addr as *mut LPCWSTR as *mut _,
|
||||||
|
0,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
buf_addr
|
||||||
|
};
|
||||||
|
if !buf_addr.is_null() {
|
||||||
|
let buf_len = lstrlenW(buf_addr) as usize;
|
||||||
|
let buf_slice = std::slice::from_raw_parts(buf_addr, buf_len);
|
||||||
|
let string = wchar_to_string(buf_slice);
|
||||||
|
LocalFree(buf_addr as *mut _);
|
||||||
|
return Some(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
#![cfg(target_os = "windows")]
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::io;
|
use std::{io, mem, ptr};
|
||||||
use std::mem;
|
|
||||||
use std::os::raw;
|
use std::os::raw;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::ptr;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
use platform::platform::events_loop::{self, DESTROY_MSG_ID};
|
use winapi::shared::minwindef::{BOOL, DWORD, UINT};
|
||||||
use platform::platform::EventsLoop;
|
use winapi::shared::windef::{HDC, HWND, POINT, RECT};
|
||||||
use platform::platform::PlatformSpecificWindowBuilderAttributes;
|
use winapi::um::{combaseapi, dwmapi, libloaderapi, processthreadsapi, winuser};
|
||||||
use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input;
|
use winapi::um::objbase::{COINIT_MULTITHREADED};
|
||||||
use platform::platform::WindowId;
|
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
|
||||||
|
use winapi::um::winnt::{HRESULT, LONG, LPCWSTR};
|
||||||
|
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use CursorState;
|
use CursorState;
|
||||||
|
use Icon;
|
||||||
|
use MonitorId as RootMonitorId;
|
||||||
use MouseCursor;
|
use MouseCursor;
|
||||||
use WindowAttributes;
|
use WindowAttributes;
|
||||||
use MonitorId as RootMonitorId;
|
|
||||||
|
|
||||||
use winapi::shared::minwindef::{UINT, DWORD, BOOL};
|
use platform::platform::{EventsLoop, PlatformSpecificWindowBuilderAttributes, WindowId};
|
||||||
use winapi::shared::windef::{HWND, HDC, RECT, POINT};
|
use platform::platform::events_loop::{self, DESTROY_MSG_ID};
|
||||||
use winapi::um::{winuser, dwmapi, libloaderapi, processthreadsapi};
|
use platform::platform::icon::{self, IconType, WinIcon};
|
||||||
use winapi::um::winnt::{LPCWSTR, LONG, HRESULT};
|
use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input;
|
||||||
use winapi::um::combaseapi;
|
|
||||||
use winapi::um::objbase::{COINIT_MULTITHREADED};
|
|
||||||
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
|
|
||||||
|
|
||||||
/// The Win32 implementation of the main `Window` object.
|
/// The Win32 implementation of the main `Window` object.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
@ -39,6 +35,9 @@ pub struct Window {
|
||||||
/// The current window state.
|
/// The current window state.
|
||||||
window_state: Arc<Mutex<events_loop::WindowState>>,
|
window_state: Arc<Mutex<events_loop::WindowState>>,
|
||||||
|
|
||||||
|
window_icon: Cell<Option<WinIcon>>,
|
||||||
|
taskbar_icon: Cell<Option<WinIcon>>,
|
||||||
|
|
||||||
// The events loop proxy.
|
// The events loop proxy.
|
||||||
events_loop_proxy: events_loop::EventsLoopProxy,
|
events_loop_proxy: events_loop::EventsLoopProxy,
|
||||||
}
|
}
|
||||||
|
@ -72,19 +71,19 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(events_loop: &EventsLoop, w_attr: &WindowAttributes,
|
pub fn new(
|
||||||
pl_attr: &PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>
|
events_loop: &EventsLoop,
|
||||||
{
|
w_attr: WindowAttributes,
|
||||||
let mut w_attr = Some(w_attr.clone());
|
pl_attr: PlatformSpecificWindowBuilderAttributes,
|
||||||
let mut pl_attr = Some(pl_attr.clone());
|
) -> Result<Window, CreationError> {
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
let proxy = events_loop.create_proxy();
|
let proxy = events_loop.create_proxy();
|
||||||
|
|
||||||
events_loop.execute_in_thread(move |inserter| {
|
events_loop.execute_in_thread(move |inserter| {
|
||||||
// We dispatch an `init` function because of code style.
|
// We dispatch an `init` function because of code style.
|
||||||
let win = unsafe { init(w_attr.take().unwrap(), pl_attr.take().unwrap(), inserter, proxy.clone()) };
|
// First person to remove the need for cloning here gets a cookie!
|
||||||
|
let win = unsafe { init(w_attr.clone(), pl_attr.clone(), inserter, proxy.clone()) };
|
||||||
let _ = tx.send(win);
|
let _ = tx.send(win);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -92,10 +91,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_title(&self, text: &str) {
|
pub fn set_title(&self, text: &str) {
|
||||||
unsafe {
|
let text = OsStr::new(text)
|
||||||
let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
|
.encode_wide()
|
||||||
|
.chain(Some(0).into_iter())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
unsafe {
|
||||||
winuser::SetWindowTextW(self.window.0, text.as_ptr() as LPCWSTR);
|
winuser::SetWindowTextW(self.window.0, text.as_ptr() as LPCWSTR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,6 +610,32 @@ impl Window {
|
||||||
inner: EventsLoop::get_current_monitor(self.window.0),
|
inner: EventsLoop::get_current_monitor(self.window.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, mut window_icon: Option<Icon>) {
|
||||||
|
let window_icon = window_icon
|
||||||
|
.take()
|
||||||
|
.map(|icon| WinIcon::from_icon(icon).expect("Failed to create `ICON_SMALL`"));
|
||||||
|
if let Some(ref window_icon) = window_icon {
|
||||||
|
window_icon.set_for_window(self.window.0, IconType::Small);
|
||||||
|
} else {
|
||||||
|
icon::unset_for_window(self.window.0, IconType::Small);
|
||||||
|
}
|
||||||
|
self.window_icon.replace(window_icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_taskbar_icon(&self, mut taskbar_icon: Option<Icon>) {
|
||||||
|
let taskbar_icon = taskbar_icon
|
||||||
|
.take()
|
||||||
|
.map(|icon| WinIcon::from_icon(icon).expect("Failed to create `ICON_BIG`"));
|
||||||
|
if let Some(ref taskbar_icon) = taskbar_icon {
|
||||||
|
taskbar_icon.set_for_window(self.window.0, IconType::Big);
|
||||||
|
} else {
|
||||||
|
icon::unset_for_window(self.window.0, IconType::Big);
|
||||||
|
}
|
||||||
|
self.taskbar_icon.replace(taskbar_icon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
|
@ -642,13 +668,44 @@ pub unsafe fn adjust_size(
|
||||||
(rect.right - rect.left, rect.bottom - rect.top)
|
(rect.right - rect.left, rect.bottom - rect.top)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
unsafe fn init(
|
||||||
inserter: events_loop::Inserter, events_loop_proxy: events_loop::EventsLoopProxy) -> Result<Window, CreationError> {
|
mut window: WindowAttributes,
|
||||||
let title = OsStr::new(&window.title).encode_wide().chain(Some(0).into_iter())
|
mut pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
|
inserter: events_loop::Inserter,
|
||||||
|
events_loop_proxy: events_loop::EventsLoopProxy,
|
||||||
|
) -> Result<Window, CreationError> {
|
||||||
|
let title = OsStr::new(&window.title)
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0).into_iter())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let window_icon = {
|
||||||
|
let icon = window.window_icon
|
||||||
|
.take()
|
||||||
|
.map(WinIcon::from_icon);
|
||||||
|
if icon.is_some() {
|
||||||
|
Some(icon.unwrap().map_err(|err| {
|
||||||
|
CreationError::OsError(format!("Failed to create `ICON_SMALL`: {:?}", err))
|
||||||
|
})?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let taskbar_icon = {
|
||||||
|
let icon = pl_attribs.taskbar_icon
|
||||||
|
.take()
|
||||||
|
.map(WinIcon::from_icon);
|
||||||
|
if icon.is_some() {
|
||||||
|
Some(icon.unwrap().map_err(|err| {
|
||||||
|
CreationError::OsError(format!("Failed to create `ICON_BIG`: {:?}", err))
|
||||||
|
})?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// registering the window class
|
// registering the window class
|
||||||
let class_name = register_window_class();
|
let class_name = register_window_class(&window_icon, &taskbar_icon);
|
||||||
|
|
||||||
// building a RECT object with coordinates
|
// building a RECT object with coordinates
|
||||||
let mut rect = RECT {
|
let mut rect = RECT {
|
||||||
|
@ -738,17 +795,21 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (transparent, maximized, fullscreen) = (
|
||||||
|
window.transparent.clone(), window.maximized.clone(), window.fullscreen.clone()
|
||||||
|
);
|
||||||
|
|
||||||
// Creating a mutex to track the current window state
|
// Creating a mutex to track the current window state
|
||||||
let window_state = Arc::new(Mutex::new(events_loop::WindowState {
|
let window_state = Arc::new(Mutex::new(events_loop::WindowState {
|
||||||
cursor: winuser::IDC_ARROW, // use arrow by default
|
cursor: winuser::IDC_ARROW, // use arrow by default
|
||||||
cursor_state: CursorState::Normal,
|
cursor_state: CursorState::Normal,
|
||||||
attributes: window.clone(),
|
attributes: window,
|
||||||
mouse_in_window: false,
|
mouse_in_window: false,
|
||||||
saved_window_info: None,
|
saved_window_info: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// making the window transparent
|
// making the window transparent
|
||||||
if window.transparent {
|
if transparent {
|
||||||
let bb = dwmapi::DWM_BLURBEHIND {
|
let bb = dwmapi::DWM_BLURBEHIND {
|
||||||
dwFlags: 0x1, // FIXME: DWM_BB_ENABLE;
|
dwFlags: 0x1, // FIXME: DWM_BB_ENABLE;
|
||||||
fEnable: 1,
|
fEnable: 1,
|
||||||
|
@ -762,12 +823,14 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild
|
||||||
let win = Window {
|
let win = Window {
|
||||||
window: real_window,
|
window: real_window,
|
||||||
window_state: window_state,
|
window_state: window_state,
|
||||||
events_loop_proxy
|
window_icon: Cell::new(window_icon),
|
||||||
|
taskbar_icon: Cell::new(taskbar_icon),
|
||||||
|
events_loop_proxy,
|
||||||
};
|
};
|
||||||
|
|
||||||
win.set_maximized(window.maximized);
|
win.set_maximized(maximized);
|
||||||
if let Some(_) = window.fullscreen {
|
if let Some(_) = fullscreen {
|
||||||
win.set_fullscreen(window.fullscreen);
|
win.set_fullscreen(fullscreen);
|
||||||
force_window_active(win.window.0);
|
force_window_active(win.window.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,9 +839,23 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild
|
||||||
Ok(win)
|
Ok(win)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn register_window_class() -> Vec<u16> {
|
unsafe fn register_window_class(
|
||||||
let class_name = OsStr::new("Window Class").encode_wide().chain(Some(0).into_iter())
|
window_icon: &Option<WinIcon>,
|
||||||
.collect::<Vec<_>>();
|
taskbar_icon: &Option<WinIcon>,
|
||||||
|
) -> Vec<u16> {
|
||||||
|
let class_name: Vec<_> = OsStr::new("Window Class")
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0).into_iter())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let h_icon = taskbar_icon
|
||||||
|
.as_ref()
|
||||||
|
.map(|icon| icon.handle)
|
||||||
|
.unwrap_or(ptr::null_mut());
|
||||||
|
let h_icon_small = window_icon
|
||||||
|
.as_ref()
|
||||||
|
.map(|icon| icon.handle)
|
||||||
|
.unwrap_or(ptr::null_mut());
|
||||||
|
|
||||||
let class = winuser::WNDCLASSEXW {
|
let class = winuser::WNDCLASSEXW {
|
||||||
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
|
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
|
||||||
|
@ -787,12 +864,12 @@ unsafe fn register_window_class() -> Vec<u16> {
|
||||||
cbClsExtra: 0,
|
cbClsExtra: 0,
|
||||||
cbWndExtra: 0,
|
cbWndExtra: 0,
|
||||||
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
|
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
|
||||||
hIcon: ptr::null_mut(),
|
hIcon: h_icon,
|
||||||
hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly
|
hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly
|
||||||
hbrBackground: ptr::null_mut(),
|
hbrBackground: ptr::null_mut(),
|
||||||
lpszMenuName: ptr::null(),
|
lpszMenuName: ptr::null(),
|
||||||
lpszClassName: class_name.as_ptr(),
|
lpszClassName: class_name.as_ptr(),
|
||||||
hIconSm: ptr::null_mut(),
|
hIconSm: h_icon_small,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We ignore errors because registering the same window class twice would trigger
|
// We ignore errors because registering the same window class twice would trigger
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use CursorState;
|
use CursorState;
|
||||||
use EventsLoop;
|
use EventsLoop;
|
||||||
|
use Icon;
|
||||||
use MouseCursor;
|
use MouseCursor;
|
||||||
use Window;
|
use Window;
|
||||||
use WindowBuilder;
|
use WindowBuilder;
|
||||||
|
@ -91,6 +92,24 @@ impl WindowBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||||
|
/// corner of the titlebar.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// This only has an effect on Windows and X11.
|
||||||
|
///
|
||||||
|
/// On Windows, this sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
|
||||||
|
/// recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
|
||||||
|
///
|
||||||
|
/// X11 has no universal guidelines for icon sizes, so you're at the whims of the WM. That
|
||||||
|
/// said, it's usually in the same ballpark as on Windows.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> WindowBuilder {
|
||||||
|
self.window.window_icon = window_icon;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Enables multitouch.
|
/// Enables multitouch.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_multitouch(mut self) -> WindowBuilder {
|
pub fn with_multitouch(mut self) -> WindowBuilder {
|
||||||
|
@ -103,22 +122,22 @@ impl WindowBuilder {
|
||||||
/// Error should be very rare and only occur in case of permission denied, incompatible system,
|
/// Error should be very rare and only occur in case of permission denied, incompatible system,
|
||||||
/// out of memory, etc.
|
/// out of memory, etc.
|
||||||
pub fn build(mut self, events_loop: &EventsLoop) -> Result<Window, CreationError> {
|
pub fn build(mut self, events_loop: &EventsLoop) -> Result<Window, CreationError> {
|
||||||
// resizing the window to the dimensions of the monitor when fullscreen
|
self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| {
|
||||||
if self.window.dimensions.is_none() {
|
|
||||||
if let Some(ref monitor) = self.window.fullscreen {
|
if let Some(ref monitor) = self.window.fullscreen {
|
||||||
self.window.dimensions = Some(monitor.get_dimensions());
|
// resizing the window to the dimensions of the monitor when fullscreen
|
||||||
}
|
monitor.get_dimensions()
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// default dimensions
|
// default dimensions
|
||||||
if self.window.dimensions.is_none() {
|
(1024, 768)
|
||||||
self.window.dimensions = Some((1024, 768));
|
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// building
|
// building
|
||||||
let w = try!(platform::Window::new(&events_loop.events_loop, &self.window, &self.platform_specific));
|
platform::Window::new(
|
||||||
|
&events_loop.events_loop,
|
||||||
Ok(Window { window: w })
|
self.window,
|
||||||
|
self.platform_specific,
|
||||||
|
).map(|window| Window { window })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,6 +363,19 @@ impl Window {
|
||||||
self.window.set_decorations(decorations)
|
self.window.set_decorations(decorations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left
|
||||||
|
/// corner of the titlebar.
|
||||||
|
///
|
||||||
|
/// For more usage notes, see `WindowBuilder::with_window_icon`.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// This only has an effect on Windows and X11.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||||
|
self.window.set_window_icon(window_icon)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the monitor on which the window currently resides
|
/// Returns the monitor on which the window currently resides
|
||||||
pub fn get_current_monitor(&self) -> MonitorId {
|
pub fn get_current_monitor(&self) -> MonitorId {
|
||||||
self.window.get_current_monitor()
|
self.window.get_current_monitor()
|
||||||
|
|
Loading…
Reference in a new issue