Window icons (#497)
This commit is contained in:
parent
1e97103094
commit
102dd07456
25 changed files with 831 additions and 137 deletions
|
|
@ -6,12 +6,20 @@ use std::ffi::CStr;
|
|||
use std::os::raw::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
// `std::os::raw::c_void` and `libc::c_void` are NOT interchangeable!
|
||||
use libc;
|
||||
|
||||
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
|
||||
use {
|
||||
CreationError,
|
||||
CursorState,
|
||||
EventsLoopClosed,
|
||||
Icon,
|
||||
MouseCursor,
|
||||
ControlFlow,
|
||||
WindowAttributes,
|
||||
};
|
||||
use window::MonitorId as RootMonitorId;
|
||||
use self::x11::XConnection;
|
||||
use self::x11::XError;
|
||||
use self::x11::{XConnection, XError};
|
||||
use self::x11::ffi::XVisualInfo;
|
||||
pub use self::x11::XNotSupported;
|
||||
|
||||
|
|
@ -109,18 +117,17 @@ impl MonitorId {
|
|||
|
||||
impl Window {
|
||||
#[inline]
|
||||
pub fn new(events_loop: &EventsLoop,
|
||||
window: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
|
||||
-> Result<Self, CreationError>
|
||||
{
|
||||
pub fn new(
|
||||
events_loop: &EventsLoop,
|
||||
attribs: WindowAttributes,
|
||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||
) -> Result<Self, CreationError> {
|
||||
match *events_loop {
|
||||
EventsLoop::Wayland(ref evlp) => {
|
||||
wayland::Window::new(evlp, window).map(Window::Wayland)
|
||||
EventsLoop::Wayland(ref events_loop) => {
|
||||
wayland::Window::new(events_loop, attribs).map(Window::Wayland)
|
||||
},
|
||||
|
||||
EventsLoop::X(ref el) => {
|
||||
x11::Window::new(el, window, pl_attribs).map(Window::X)
|
||||
EventsLoop::X(ref events_loop) => {
|
||||
x11::Window::new(events_loop, attribs, 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]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ pub struct 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));
|
||||
|
||||
// Create the window
|
||||
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"))]
|
||||
|
||||
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;
|
||||
|
||||
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 monitor;
|
||||
mod window;
|
||||
|
|
@ -31,6 +9,33 @@ mod dnd;
|
|||
mod ime;
|
||||
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::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
||||
|
||||
|
|
@ -1150,10 +1155,11 @@ impl ::std::ops::Deref for Window {
|
|||
impl Window {
|
||||
pub fn new(
|
||||
x_events_loop: &EventsLoop,
|
||||
window: &::WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes
|
||||
attribs: WindowAttributes,
|
||||
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
||||
) -> 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
|
||||
.borrow_mut()
|
||||
|
|
@ -1166,7 +1172,7 @@ impl Window {
|
|||
|
||||
x_events_loop.windows.lock().insert(win.id(), WindowData {
|
||||
config: Default::default(),
|
||||
multitouch: window.multitouch,
|
||||
multitouch,
|
||||
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 geometry;
|
||||
mod hint;
|
||||
mod icon;
|
||||
mod input;
|
||||
mod window_property;
|
||||
mod wm;
|
||||
|
|
@ -11,6 +12,7 @@ mod wm;
|
|||
pub use self::atom::*;
|
||||
pub use self::geometry::*;
|
||||
pub use self::hint::*;
|
||||
pub use self::icon::*;
|
||||
pub use self::input::*;
|
||||
pub use self::window_property::*;
|
||||
pub use self::wm::*;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ use std::fmt::Debug;
|
|||
|
||||
use super::*;
|
||||
|
||||
pub type Cardinal = c_long;
|
||||
pub const CARDINAL_SIZE: usize = mem::size_of::<c_long>();
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum GetPropertyError {
|
||||
XError(XError),
|
||||
|
|
|
|||
|
|
@ -1,24 +1,19 @@
|
|||
use MouseCursor;
|
||||
use CreationError;
|
||||
use CreationError::OsError;
|
||||
use libc;
|
||||
use std::{cmp, mem};
|
||||
use std::borrow::Borrow;
|
||||
use std::{mem, cmp};
|
||||
use std::sync::Arc;
|
||||
use std::os::raw::*;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libc;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use CursorState;
|
||||
use WindowAttributes;
|
||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||
|
||||
use {CursorState, Icon, MouseCursor, WindowAttributes};
|
||||
use CreationError::{self, OsError};
|
||||
use platform::MonitorId as PlatformMonitorId;
|
||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||
use platform::x11::MonitorId as X11MonitorId;
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
use platform::x11::monitor::get_available_monitors;
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
use super::{ffi, util, XConnection, XError, WindowId, EventsLoop};
|
||||
|
||||
|
|
@ -60,8 +55,8 @@ pub struct Window2 {
|
|||
impl Window2 {
|
||||
pub fn new(
|
||||
ctx: &EventsLoop,
|
||||
window_attrs: &WindowAttributes,
|
||||
pl_attribs: &PlatformSpecificWindowBuilderAttributes,
|
||||
window_attrs: WindowAttributes,
|
||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||
) -> Result<Window2, CreationError> {
|
||||
let xconn = &ctx.display;
|
||||
|
||||
|
|
@ -241,6 +236,11 @@ impl Window2 {
|
|||
}//.queue();
|
||||
}
|
||||
|
||||
// Set window icons
|
||||
if let Some(icon) = window_attrs.window_icon {
|
||||
window.set_icon_inner(icon).queue();
|
||||
}
|
||||
|
||||
// Opt into handling window close
|
||||
unsafe {
|
||||
(xconn.xlib.XSetWMProtocols)(
|
||||
|
|
@ -522,6 +522,53 @@ impl Window2 {
|
|||
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) {
|
||||
unsafe {
|
||||
(self.x.display.xlib.XMapRaised)(self.x.display.display, self.x.window);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue