#![allow(non_snake_case)]
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::ffi::OsString;
use std::mem;
use std::ptr::{null, null_mut};
use std::rc::{Rc, Weak};
use std::sync::{Arc, Mutex};
use winapi::Interface;
use winapi::ctypes::{c_int, c_void};
use winapi::shared::basetsd::*;
use winapi::shared::dxgi::*;
use winapi::shared::dxgi1_2::*;
use winapi::shared::dxgitype::*;
use winapi::shared::dxgiformat::*;
use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::shared::winerror::*;
use winapi::um::d2d1::*;
use winapi::um::unknwnbase::*;
use winapi::um::wingdi::*;
use winapi::um::winnt::*;
use winapi::um::winuser::*;
use direct2d;
use direct2d::math::SizeU;
use direct2d::render_target::{GenericRenderTarget, HwndRenderTarget, RenderTarget};
use Error;
use dialog::{FileDialogOptions, FileDialogType, get_file_dialog_path};
use dcomp::{D3D11Device, DCompositionDevice, DCompositionTarget, DCompositionVisual};
use menu::Menu;
use paint::{self, PaintCtx};
use util::{OPTIONAL_FUNCTIONS, as_result, FromWide, ToWide};
extern "system" {
pub fn DwmFlush();
}
pub struct WindowBuilder {
handler: Option<Box<WinHandler>>,
dwStyle: DWORD,
title: String,
cursor: Cursor,
menu: Option<Menu>,
present_strategy: PresentStrategy,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PresentStrategy {
Hwnd,
Sequential,
Flip,
FlipRedirect,
}
#[derive(Clone, Default)]
pub struct WindowHandle(Weak<WindowState>);
#[derive(Clone)]
pub struct IdleHandle {
pub(crate) hwnd: HWND,
queue: Arc<Mutex<Vec<Box<IdleCallback>>>>,
}
trait IdleCallback: Send {
fn call(self: Box<Self>, a: &Any);
}
impl<F: FnOnce(&Any) + Send> IdleCallback for F {
fn call(self: Box<F>, a: &Any) {
(*self)(a)
}
}
struct WindowState {
hwnd: Cell<HWND>,
dpi: Cell<f32>,
wndproc: Box<WndProc>,
idle_queue: Arc<Mutex<Vec<Box<IdleCallback>>>>,
}
pub trait WinHandler {
fn connect(&self, handle: &WindowHandle);
#[allow(unused_variables)]
fn size(&self, width: u32, height: u32) {}
fn paint(&self, ctx: &mut PaintCtx) -> bool;
fn rebuild_resources(&self) {}
#[allow(unused_variables)]
fn command(&self, id: u32) {}
#[allow(unused_variables)]
fn char(&self, ch: u32, mods: u32) {}
#[allow(unused_variables)]
fn keydown(&self, vkey_code: i32, mods: u32) -> bool { false }
#[allow(unused_variables)]
fn mouse_wheel(&self, delta: i32, mods: u32) {}
#[allow(unused_variables)]
fn mouse_hwheel(&self, delta: i32, mods: u32) {}
#[allow(unused_variables)]
fn mouse_move(&self, x: i32, y: i32, mods: u32) {}
#[allow(unused_variables)]
fn mouse(&self, event: &MouseEvent) {}
fn destroy(&self) {}
fn as_any(&self) -> &Any;
}
#[derive(Debug)]
pub struct MouseEvent {
pub x: i32,
pub y: i32,
pub mods: u32,
pub which: MouseButton,
pub ty: MouseType,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum MouseButton {
Left,
Middle,
Right,
X1,
X2,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum MouseType {
Down,
DoubleClick,
Up,
}
pub enum Cursor {
Arrow,
IBeam,
}
trait WndProc {
fn connect(&self, handle: &WindowHandle, state: WndState);
fn window_proc(&self, hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
-> Option<LRESULT>;
}
pub const M_ALT: u32 = 1;
pub const M_CTRL: u32 = 2;
pub const M_SHIFT: u32 = 4;
struct MyWndProc {
handler: Box<WinHandler>,
handle: RefCell<WindowHandle>,
d2d_factory: direct2d::Factory,
state: RefCell<Option<WndState>>,
}
struct WndState {
render_target: Option<GenericRenderTarget>,
dcomp_state: Option<DCompState>,
dpi: f32,
}
struct DCompState {
swap_chain: *mut IDXGISwapChain1,
dcomp_device: DCompositionDevice,
dcomp_target: DCompositionTarget,
swapchain_visual: DCompositionVisual,
sizing: bool,
}
const XI_RUN_IDLE: UINT = WM_USER;
impl Default for PresentStrategy {
fn default() -> PresentStrategy {
PresentStrategy::FlipRedirect
}
}
fn get_mod_state(lparam: LPARAM) -> u32 {
unsafe {
let mut mod_state = 0;
if (lparam & (1 << 29)) != 0 { mod_state |= MOD_ALT as u32; }
if GetKeyState(VK_CONTROL) < 0 { mod_state |= MOD_CONTROL as u32; }
if GetKeyState(VK_SHIFT) < 0 { mod_state |= MOD_SHIFT as u32; }
mod_state
}
}
impl MyWndProc {
fn rebuild_render_target(&self) {
unsafe {
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
let swap_chain = s.dcomp_state.as_ref().unwrap().swap_chain;
let rt = paint::create_render_target_dxgi(&self.d2d_factory, swap_chain, s.dpi)
.map(|rt| rt.as_generic());
s.render_target = rt.ok();
}
}
fn render(&self) {
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
let rt = s.render_target.as_mut().unwrap();
rt.begin_draw();
let anim = self.handler.paint(&mut PaintCtx {
d2d_factory: &self.d2d_factory,
render_target: rt,
});
let res = rt.end_draw();
if let Err(e) = res {
println!("EndDraw error: {:?}", e);
}
if anim {
let handle = self.handle.borrow().get_idle_handle().unwrap();
let handle2 = handle.clone();
handle.add_idle(move |_| handle2.invalidate());
}
}
}
impl WndProc for MyWndProc {
fn connect(&self, handle: &WindowHandle, state: WndState) {
*self.handle.borrow_mut() = handle.clone();
self.handler.connect(handle);
*self.state.borrow_mut() = Some(state);
}
fn window_proc(&self, hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
-> Option<LRESULT>
{
match msg {
WM_ERASEBKGND => {
Some(0)
}
WM_PAINT => unsafe {
if self.state.borrow().as_ref().unwrap().render_target.is_none() {
let rt = paint::create_render_target(&self.d2d_factory, hwnd)
.map(|rt| rt.as_generic());
self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
}
self.render();
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
if let Some(ref mut ds) = s.dcomp_state {
if !ds.sizing {
(*ds.swap_chain).Present(1, 0);
let _ = ds.dcomp_device.commit();
}
}
ValidateRect(hwnd, null_mut());
Some(0)
},
WM_ENTERSIZEMOVE => unsafe {
if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
let rt = paint::create_render_target(&self.d2d_factory, hwnd)
.map(|rt| rt.as_generic());
self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
self.handler.rebuild_resources();
self.render();
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
if let Some(ref mut ds) = s.dcomp_state {
let _ = ds.dcomp_target.clear_root();
let _ = ds.dcomp_device.commit();
ds.sizing = true;
}
}
None
}
WM_EXITSIZEMOVE => unsafe {
if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
let mut rect: RECT = mem::uninitialized();
GetClientRect(hwnd, &mut rect);
let width = (rect.right - rect.left) as u32;
let height = (rect.bottom - rect.top) as u32;
let res = (*self.state.borrow_mut().as_mut().unwrap()
.dcomp_state.as_mut().unwrap().swap_chain)
.ResizeBuffers(2, width, height, DXGI_FORMAT_UNKNOWN, 0);
if SUCCEEDED(res) {
self.handler.rebuild_resources();
self.rebuild_render_target();
self.render();
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
(*s.dcomp_state.as_ref().unwrap().swap_chain).Present(0, 0);
} else {
println!("ResizeBuffers failed: 0x{:x}", res);
}
DwmFlush();
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
if let Some(ref mut ds) = s.dcomp_state {
let _ = ds.dcomp_target.set_root(&mut ds.swapchain_visual);
let _ = ds.dcomp_device.commit();
ds.sizing = false;
}
}
None
}
WM_SIZE => unsafe {
let width = LOWORD(lparam as u32) as u32;
let height = HIWORD(lparam as u32) as u32;
self.handler.size(width, height);
let use_hwnd = if let Some(ref dcomp_state) =
self.state.borrow().as_ref().unwrap().dcomp_state
{
dcomp_state.sizing
} else {
true
};
if use_hwnd {
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
if let Some(ref mut rt) = s.render_target {
if let Some(hrt) = cast_to_hwnd(rt) {
let width = LOWORD(lparam as u32) as u32;
let height = HIWORD(lparam as u32) as u32;
let size = SizeU(D2D1_SIZE_U { width, height });
let _ = hrt.resize(size);
}
}
InvalidateRect(hwnd, null_mut(), FALSE);
} else {
let res;
{
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
s.render_target = None;
res = (*s.dcomp_state.as_mut().unwrap().swap_chain)
.ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0);
}
if SUCCEEDED(res) {
self.rebuild_render_target();
self.render();
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
if let Some(ref mut dcomp_state) = s.dcomp_state {
(*dcomp_state.swap_chain).Present(0, 0);
let _ = dcomp_state.dcomp_device.commit();
}
ValidateRect(hwnd, null_mut());
} else {
println!("ResizeBuffers failed: 0x{:x}", res);
}
}
Some(0)
},
WM_COMMAND => {
self.handler.command(LOWORD(wparam as u32) as u32);
Some(0)
}
WM_CHAR => {
let mods = get_mod_state(lparam);
self.handler.char(wparam as u32, mods);
Some(0)
}
WM_KEYDOWN | WM_SYSKEYDOWN => {
let mods = get_mod_state(lparam);
let handled = self.handler.keydown(wparam as i32, mods);
if handled {
Some(0)
} else {
None
}
}
WM_MOUSEWHEEL => {
let delta = HIWORD(wparam as u32) as i16 as i32;
let mods = LOWORD(wparam as u32) as u32;
self.handler.mouse_wheel(delta, mods);
Some(0)
}
WM_MOUSEHWHEEL => {
let delta = HIWORD(wparam as u32) as i16 as i32;
let mods = LOWORD(wparam as u32) as u32;
self.handler.mouse_hwheel(delta, mods);
Some(0)
}
WM_MOUSEMOVE => {
let x = LOWORD(lparam as u32) as i16 as i32;
let y = HIWORD(lparam as u32) as i16 as i32;
let mods = LOWORD(wparam as u32) as u32;
self.handler.mouse_move(x, y, mods);
Some(0)
}
WM_LBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP |
WM_MBUTTONDBLCLK | WM_MBUTTONDOWN | WM_MBUTTONUP |
WM_RBUTTONDBLCLK | WM_RBUTTONDOWN | WM_RBUTTONUP |
WM_XBUTTONDBLCLK | WM_XBUTTONDOWN | WM_XBUTTONUP =>
{
let which = match msg {
WM_LBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP => MouseButton::Left,
WM_MBUTTONDBLCLK | WM_MBUTTONDOWN | WM_MBUTTONUP => MouseButton::Middle,
WM_RBUTTONDBLCLK | WM_RBUTTONDOWN | WM_RBUTTONUP => MouseButton::Right,
WM_XBUTTONDBLCLK | WM_XBUTTONDOWN | WM_XBUTTONUP =>
match HIWORD(wparam as u32) {
1 => MouseButton::X1,
2 => MouseButton::X2,
_ => {
println!("unexpected X button event");
return None;
}
},
_ => unreachable!()
};
let ty = match msg {
WM_LBUTTONDOWN | WM_MBUTTONDOWN | WM_RBUTTONDOWN | WM_XBUTTONDOWN =>
MouseType::Down,
WM_LBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_RBUTTONDBLCLK | WM_XBUTTONDBLCLK =>
MouseType::DoubleClick,
WM_LBUTTONUP | WM_MBUTTONUP | WM_RBUTTONUP | WM_XBUTTONUP =>
MouseType::Up,
_ => unreachable!(),
};
let x = LOWORD(lparam as u32) as i16 as i32;
let y = HIWORD(lparam as u32) as i16 as i32;
let mods = LOWORD(wparam as u32) as u32;
let event = MouseEvent { x, y, mods, which, ty };
self.handler.mouse(&event);
Some(0)
}
WM_DESTROY => {
self.handler.destroy();
None
}
XI_RUN_IDLE => {
let queue = self.handle.borrow().take_idle_queue();
let handler_as_any = self.handler.as_any();
for callback in queue {
callback.call(handler_as_any);
}
Some(0)
}
_ => None
}
}
}
impl WindowBuilder {
pub fn new() -> WindowBuilder {
WindowBuilder {
handler: None,
dwStyle: WS_OVERLAPPEDWINDOW,
title: String::new(),
cursor: Cursor::Arrow,
menu: None,
present_strategy: Default::default(),
}
}
pub fn set_handler(&mut self, handler: Box<WinHandler>) {
self.handler = Some(handler);
}
pub fn set_scroll(&mut self, hscroll: bool, vscroll: bool) {
self.dwStyle &= !(WS_HSCROLL | WS_VSCROLL);
if hscroll {
self.dwStyle |= WS_HSCROLL;
}
if vscroll {
self.dwStyle |= WS_VSCROLL;
}
}
pub fn set_title<S: Into<String>>(&mut self, title: S) {
self.title = title.into();
}
pub fn set_cursor(&mut self, cursor: Cursor) {
self.cursor = cursor;
}
pub fn set_menu(&mut self, menu: Menu) {
self.menu = Some(menu);
}
pub fn set_present_strategy(&mut self, present_strategy: PresentStrategy) {
self.present_strategy = present_strategy;
}
pub fn build(self)
-> Result<WindowHandle, Error>
{
unsafe {
let class_name = "Xi Editor".to_wide();
let icon = LoadIconW(0 as HINSTANCE, IDI_APPLICATION);
let cursor = LoadCursorW(0 as HINSTANCE, self.cursor.get_lpcwstr());
let brush = CreateSolidBrush(0xffffff);
let wnd = WNDCLASSW {
style: 0,
lpfnWndProc: Some(win_proc_dispatch),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: 0 as HINSTANCE,
hIcon: icon,
hCursor: cursor,
hbrBackground: brush,
lpszMenuName: 0 as LPCWSTR,
lpszClassName: class_name.as_ptr(),
};
let class_atom = RegisterClassW(&wnd);
if class_atom == 0 {
return Err(Error::Null);
}
let wndproc = MyWndProc {
handler: self.handler.unwrap(),
handle: Default::default(),
d2d_factory: direct2d::Factory::new().unwrap(),
state: RefCell::new(None),
};
let window = WindowState {
hwnd: Cell::new(0 as HWND),
dpi: Cell::new(0.0),
wndproc: Box::new(wndproc),
idle_queue: Default::default(),
};
let win = Rc::new(window);
let handle = WindowHandle(Rc::downgrade(&win));
let dpi = if let Some(func) = OPTIONAL_FUNCTIONS.GetDpiForSystem {
func() as f32
} else {
96.0
};
win.dpi.set(dpi);
let width = (500.0 * (dpi/96.0)) as i32;
let height = (400.0 * (dpi/96.0)) as i32;
let hmenu = match self.menu {
Some(menu) => menu.into_hmenu(),
None => 0 as HMENU,
};
let mut dwExStyle = 0;
if self.present_strategy == PresentStrategy::Flip {
dwExStyle |= WS_EX_NOREDIRECTIONBITMAP;
}
let hwnd = create_window(dwExStyle, class_name.as_ptr(),
self.title.to_wide().as_ptr(), self.dwStyle,
CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0 as HWND, hmenu, 0 as HINSTANCE,
win.clone());
if hwnd.is_null() {
return Err(Error::Null);
}
let dcomp_state = create_dcomp_state(self.present_strategy, hwnd)
.unwrap_or_else(|e| {
println!("Error creating swapchain, falling back to hwnd: {:?}", e);
None
});
win.hwnd.set(hwnd);
let state = WndState {
render_target: None,
dcomp_state,
dpi,
};
win.wndproc.connect(&handle, state);
mem::drop(win);
Ok(handle)
}
}
}
unsafe fn choose_adapter(factory: *mut IDXGIFactory2) -> *mut IDXGIAdapter {
let mut i = 0;
let mut best_adapter = null_mut();
let mut best_vram = 0;
loop {
let mut adapter: *mut IDXGIAdapter = null_mut();
if !SUCCEEDED((*factory).EnumAdapters(i, &mut adapter)) {
break;
}
let mut desc: DXGI_ADAPTER_DESC = mem::uninitialized();
(*adapter).GetDesc(&mut desc);
let vram = desc.DedicatedVideoMemory;
if i == 0 || vram > best_vram {
best_vram = vram;
best_adapter = adapter;
}
println!("{:?}: desc = {:?}, vram = {}",
adapter,
(&mut desc.Description[0] as LPWSTR).from_wide(),
desc.DedicatedVideoMemory);
i += 1;
}
best_adapter
}
unsafe fn create_dcomp_state(present_strategy: PresentStrategy, hwnd: HWND)
-> Result<Option<DCompState>, Error>
{
if present_strategy == PresentStrategy::Hwnd {
return Ok(None);
}
if let Some(create_dxgi_factory2) = OPTIONAL_FUNCTIONS.CreateDXGIFactory2 {
let mut factory: *mut IDXGIFactory2 = null_mut();
as_result(create_dxgi_factory2(0, &IID_IDXGIFactory2,
&mut factory as *mut *mut IDXGIFactory2 as *mut *mut c_void))?;
println!("dxgi factory pointer = {:?}", factory);
let adapter = choose_adapter(factory);
println!("adapter = {:?}", adapter);
let mut d3d11_device = D3D11Device::new_simple()?;
let mut d2d1_device = d3d11_device.create_d2d1_device()?;
let mut dcomp_device = d2d1_device.create_composition_device()?;
let mut dcomp_target = dcomp_device.create_target_for_hwnd(hwnd, true)?;
let (swap_effect, bufs) = match present_strategy {
PresentStrategy::Hwnd => unreachable!(),
PresentStrategy::Sequential => (DXGI_SWAP_EFFECT_SEQUENTIAL, 1),
PresentStrategy::Flip | PresentStrategy::FlipRedirect =>
(DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, 2),
};
let desc = DXGI_SWAP_CHAIN_DESC1 {
Width: 1024,
Height: 768,
Format: DXGI_FORMAT_B8G8R8A8_UNORM,
Stereo: FALSE,
SampleDesc: DXGI_SAMPLE_DESC { Count: 1, Quality: 0 },
BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: bufs,
Scaling: DXGI_SCALING_STRETCH,
SwapEffect: swap_effect,
AlphaMode: DXGI_ALPHA_MODE_IGNORE,
Flags: 0,
};
let mut swap_chain: *mut IDXGISwapChain1 = null_mut();
let res = (*factory).CreateSwapChainForComposition(d3d11_device.raw_ptr() as *mut IUnknown,
&desc, null_mut(), &mut swap_chain);
println!("swap chain res = 0x{:x}, pointer = {:?}", res, swap_chain);
let mut swapchain_visual = dcomp_device.create_visual()?;
swapchain_visual.set_content_raw(swap_chain as *mut IUnknown)?;
dcomp_target.set_root(&mut swapchain_visual)?;
Ok(Some(DCompState {
swap_chain, dcomp_device, dcomp_target, swapchain_visual,
sizing: false,
}))
} else {
Ok(None)
}
}
unsafe extern "system" fn win_proc_dispatch(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
-> LRESULT
{
if msg == WM_CREATE {
let create_struct = &*(lparam as *const CREATESTRUCTW);
let wndproc_ptr = create_struct.lpCreateParams;
SetWindowLongPtrW(hwnd, GWLP_USERDATA, wndproc_ptr as LONG_PTR);
}
let window_ptr = GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *const WindowState;
let result = {
if window_ptr.is_null() {
None
} else {
(*window_ptr).wndproc.window_proc(hwnd, msg, wparam, lparam)
}
};
if msg == WM_NCDESTROY {
if !window_ptr.is_null() {
SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
mem::drop(Rc::from_raw(window_ptr));
}
}
match result {
Some(lresult) => lresult,
None => DefWindowProcW(hwnd, msg, wparam, lparam),
}
}
unsafe fn create_window(
dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, x: c_int,
y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU,
hInstance: HINSTANCE, wndproc: Rc<WindowState>) -> HWND
{
CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, Rc::into_raw(wndproc) as LPVOID)
}
impl Cursor {
fn get_lpcwstr(&self) -> LPCWSTR {
match self {
Cursor::Arrow => IDC_ARROW,
Cursor::IBeam => IDC_IBEAM,
}
}
}
impl WindowHandle {
pub fn show(&self) {
if let Some(w) = self.0.upgrade() {
let hwnd = w.hwnd.get();
unsafe {
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
}
}
}
pub fn close(&self) {
if let Some(w) = self.0.upgrade() {
let hwnd = w.hwnd.get();
unsafe {
DestroyWindow(hwnd);
}
}
}
pub fn invalidate(&self) {
if let Some(w) = self.0.upgrade() {
let hwnd = w.hwnd.get();
unsafe {
InvalidateRect(hwnd, null(), FALSE);
}
}
}
pub fn get_hwnd(&self) -> Option<HWND> {
self.0.upgrade().map(|w| w.hwnd.get())
}
pub fn file_dialog(&self, ty: FileDialogType, options: FileDialogOptions)
-> Result<OsString, Error>
{
let hwnd = self.get_hwnd().ok_or(Error::Null)?;
unsafe { get_file_dialog_path(hwnd, ty, options) }
}
pub fn get_idle_handle(&self) -> Option<IdleHandle> {
self.0.upgrade().map(|w|
IdleHandle {
hwnd: w.hwnd.get(),
queue: w.idle_queue.clone(),
}
)
}
fn take_idle_queue(&self) -> Vec<Box<IdleCallback>> {
if let Some(w) = self.0.upgrade() {
mem::replace(&mut w.idle_queue.lock().unwrap(), Vec::new())
} else {
Vec::new()
}
}
pub fn get_dpi(&self) -> f32 {
if let Some(w) = self.0.upgrade() {
w.dpi.get()
} else {
96.0
}
}
pub fn px_to_pixels(&self, x: f32) -> i32 {
(x * self.get_dpi() * (1.0 / 96.0)).round() as i32
}
pub fn px_to_pixels_xy(&self, x: f32, y: f32) -> (i32, i32) {
let scale = self.get_dpi() * (1.0 / 96.0);
((x * scale).round() as i32, (y * scale).round() as i32)
}
pub fn pixels_to_px<T: Into<f64>>(&self, x: T) -> f32 {
(x.into() as f32) * 96.0 / self.get_dpi()
}
pub fn pixels_to_px_xy<T: Into<f64>>(&self, x: T, y: T) -> (f32, f32) {
let scale = 96.0 / self.get_dpi();
((x.into() as f32) * scale, (y.into() as f32) * scale)
}
}
unsafe impl Send for IdleHandle {}
impl IdleHandle {
pub fn add_idle<F>(&self, callback: F)
where F: FnOnce(&Any) + Send + 'static
{
let mut queue = self.queue.lock().unwrap();
if queue.is_empty() {
unsafe {
PostMessageW(self.hwnd, XI_RUN_IDLE, 0, 0);
}
}
queue.push(Box::new(callback));
}
fn invalidate(&self) {
unsafe {
InvalidateRect(self.hwnd, null(), FALSE);
}
}
}
unsafe fn cast_to_hwnd(rt: &GenericRenderTarget) -> Option<HwndRenderTarget> {
let raw_ptr = rt.clone().get_raw();
let mut hwnd = null_mut();
let err = (*raw_ptr).QueryInterface(&ID2D1HwndRenderTarget::uuidof(), &mut hwnd);
if SUCCEEDED(err) {
Some(HwndRenderTarget::from_raw(hwnd as *mut ID2D1HwndRenderTarget))
} else {
None
}
}