1#![allow(non_snake_case)]
18
19use std::any::Any;
20use std::cell::{Cell, RefCell};
21use std::ffi::OsString;
22use std::mem;
23use std::ptr::{null, null_mut};
24use std::rc::{Rc, Weak};
25use std::sync::{Arc, Mutex};
26
27use winapi::Interface;
28use winapi::ctypes::{c_int, c_void};
29use winapi::shared::basetsd::*;
30use winapi::shared::dxgi::*;
31use winapi::shared::dxgi1_2::*;
32use winapi::shared::dxgitype::*;
33use winapi::shared::dxgiformat::*;
34use winapi::shared::minwindef::*;
35use winapi::shared::windef::*;
36use winapi::shared::winerror::*;
37use winapi::um::d2d1::*;
38use winapi::um::unknwnbase::*;
39use winapi::um::wingdi::*;
40use winapi::um::winnt::*;
41use winapi::um::winuser::*;
42
43use direct2d;
44use direct2d::math::SizeU;
45use direct2d::render_target::{GenericRenderTarget, HwndRenderTarget, RenderTarget};
46
47use Error;
48use dialog::{FileDialogOptions, FileDialogType, get_file_dialog_path};
49use dcomp::{D3D11Device, DCompositionDevice, DCompositionTarget, DCompositionVisual};
50use menu::Menu;
51use paint::{self, PaintCtx};
52use util::{OPTIONAL_FUNCTIONS, as_result, FromWide, ToWide};
53
54extern "system" {
55 pub fn DwmFlush();
56}
57
58pub struct WindowBuilder {
60 handler: Option<Box<WinHandler>>,
61 dwStyle: DWORD,
62 title: String,
63 cursor: Cursor,
64 menu: Option<Menu>,
65 present_strategy: PresentStrategy,
66}
67
68#[derive(Clone, Copy, PartialEq, Eq, Debug)]
69pub enum PresentStrategy {
73 Hwnd,
76
77 Sequential,
82
83 Flip,
88
89 FlipRedirect,
93}
94
95#[derive(Clone, Default)]
96pub struct WindowHandle(Weak<WindowState>);
97
98#[derive(Clone)]
103pub struct IdleHandle {
104 pub(crate) hwnd: HWND,
105 queue: Arc<Mutex<Vec<Box<IdleCallback>>>>,
106}
107
108trait IdleCallback: Send {
109 fn call(self: Box<Self>, a: &Any);
110}
111
112impl<F: FnOnce(&Any) + Send> IdleCallback for F {
113 fn call(self: Box<F>, a: &Any) {
114 (*self)(a)
115 }
116}
117
118struct WindowState {
119 hwnd: Cell<HWND>,
120 dpi: Cell<f32>,
121 wndproc: Box<WndProc>,
122 idle_queue: Arc<Mutex<Vec<Box<IdleCallback>>>>,
123}
124
125pub trait WinHandler {
132 fn connect(&self, handle: &WindowHandle);
135
136 #[allow(unused_variables)]
139 fn size(&self, width: u32, height: u32) {}
140
141 fn paint(&self, ctx: &mut PaintCtx) -> bool;
145
146 fn rebuild_resources(&self) {}
148
149 #[allow(unused_variables)]
150 fn command(&self, id: u32) {}
152
153 #[allow(unused_variables)]
159 fn char(&self, ch: u32, mods: u32) {}
160
161 #[allow(unused_variables)]
169 fn keydown(&self, vkey_code: i32, mods: u32) -> bool { false }
170
171 #[allow(unused_variables)]
177 fn mouse_wheel(&self, delta: i32, mods: u32) {}
178
179 #[allow(unused_variables)]
185 fn mouse_hwheel(&self, delta: i32, mods: u32) {}
186
187 #[allow(unused_variables)]
192 fn mouse_move(&self, x: i32, y: i32, mods: u32) {}
193
194 #[allow(unused_variables)]
197 fn mouse(&self, event: &MouseEvent) {}
198
199 fn destroy(&self) {}
203
204 fn as_any(&self) -> &Any;
206}
207
208#[derive(Debug)]
210pub struct MouseEvent {
211 pub x: i32,
213 pub y: i32,
215 pub mods: u32,
217 pub which: MouseButton,
219 pub ty: MouseType,
221}
222
223#[derive(PartialEq, Eq, Clone, Copy, Debug)]
225pub enum MouseButton {
226 Left,
228 Middle,
230 Right,
232 X1,
234 X2,
236}
237
238#[derive(PartialEq, Eq, Clone, Copy, Debug)]
240pub enum MouseType {
241 Down,
243 DoubleClick,
246 Up,
248}
249
250pub enum Cursor {
252 Arrow,
253 IBeam,
254}
255
256trait WndProc {
258 fn connect(&self, handle: &WindowHandle, state: WndState);
259
260 fn window_proc(&self, hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
261 -> Option<LRESULT>;
262}
263
264pub const M_ALT: u32 = 1;
266
267pub const M_CTRL: u32 = 2;
269
270pub const M_SHIFT: u32 = 4;
272
273struct MyWndProc {
276 handler: Box<WinHandler>,
277 handle: RefCell<WindowHandle>,
278 d2d_factory: direct2d::Factory,
279 state: RefCell<Option<WndState>>,
280}
281
282struct WndState {
283 render_target: Option<GenericRenderTarget>,
284 dcomp_state: Option<DCompState>,
285 dpi: f32,
286}
287
288struct DCompState {
291 swap_chain: *mut IDXGISwapChain1,
292 dcomp_device: DCompositionDevice,
293 dcomp_target: DCompositionTarget,
294 swapchain_visual: DCompositionVisual,
295 sizing: bool,
297}
298
299const XI_RUN_IDLE: UINT = WM_USER;
301
302impl Default for PresentStrategy {
303 fn default() -> PresentStrategy {
304 PresentStrategy::FlipRedirect
307 }
308}
309
310fn get_mod_state(lparam: LPARAM) -> u32 {
311 unsafe {
312 let mut mod_state = 0;
313 if (lparam & (1 << 29)) != 0 { mod_state |= MOD_ALT as u32; }
314 if GetKeyState(VK_CONTROL) < 0 { mod_state |= MOD_CONTROL as u32; }
315 if GetKeyState(VK_SHIFT) < 0 { mod_state |= MOD_SHIFT as u32; }
316 mod_state
317 }
318}
319
320impl MyWndProc {
321 fn rebuild_render_target(&self) {
322 unsafe {
323 let mut state = self.state.borrow_mut();
324 let s = state.as_mut().unwrap();
325 let swap_chain = s.dcomp_state.as_ref().unwrap().swap_chain;
326 let rt = paint::create_render_target_dxgi(&self.d2d_factory, swap_chain, s.dpi)
327 .map(|rt| rt.as_generic());
328 s.render_target = rt.ok();
329 }
330 }
331
332 fn render(&self) {
334 let mut state = self.state.borrow_mut();
335 let s = state.as_mut().unwrap();
336 let rt = s.render_target.as_mut().unwrap();
337 rt.begin_draw();
338 let anim = self.handler.paint(&mut PaintCtx {
339 d2d_factory: &self.d2d_factory,
340 render_target: rt,
341 });
342 let res = rt.end_draw();
344 if let Err(e) = res {
345 println!("EndDraw error: {:?}", e);
346 }
347 if anim {
348 let handle = self.handle.borrow().get_idle_handle().unwrap();
349 let handle2 = handle.clone();
351 handle.add_idle(move |_| handle2.invalidate());
352 }
353 }
354}
355
356impl WndProc for MyWndProc {
357 fn connect(&self, handle: &WindowHandle, state: WndState) {
358 *self.handle.borrow_mut() = handle.clone();
359 self.handler.connect(handle);
360 *self.state.borrow_mut() = Some(state);
361 }
362
363 fn window_proc(&self, hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
364 -> Option<LRESULT>
365 {
366 match msg {
368 WM_ERASEBKGND => {
369 Some(0)
370 }
371 WM_PAINT => unsafe {
372 if self.state.borrow().as_ref().unwrap().render_target.is_none() {
373 let rt = paint::create_render_target(&self.d2d_factory, hwnd)
374 .map(|rt| rt.as_generic());
375 self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
376 }
377 self.render();
378 let mut state = self.state.borrow_mut();
379 let s = state.as_mut().unwrap();
380 if let Some(ref mut ds) = s.dcomp_state {
381 if !ds.sizing {
382 (*ds.swap_chain).Present(1, 0);
383 let _ = ds.dcomp_device.commit();
384 }
385 }
386 ValidateRect(hwnd, null_mut());
387 Some(0)
388 },
389 WM_ENTERSIZEMOVE => unsafe {
390 if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
391 let rt = paint::create_render_target(&self.d2d_factory, hwnd)
392 .map(|rt| rt.as_generic());
393 self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
394 self.handler.rebuild_resources();
395 self.render();
396
397 let mut state = self.state.borrow_mut();
398 let s = state.as_mut().unwrap();
399 if let Some(ref mut ds) = s.dcomp_state {
400 let _ = ds.dcomp_target.clear_root();
401 let _ = ds.dcomp_device.commit();
402 ds.sizing = true;
403 }
404 }
405 None
406 }
407 WM_EXITSIZEMOVE => unsafe {
408 if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
409 let mut rect: RECT = mem::uninitialized();
410 GetClientRect(hwnd, &mut rect);
411 let width = (rect.right - rect.left) as u32;
412 let height = (rect.bottom - rect.top) as u32;
413 let res = (*self.state.borrow_mut().as_mut().unwrap()
414 .dcomp_state.as_mut().unwrap().swap_chain)
415 .ResizeBuffers(2, width, height, DXGI_FORMAT_UNKNOWN, 0);
416 if SUCCEEDED(res) {
417 self.handler.rebuild_resources();
418 self.rebuild_render_target();
419 self.render();
420 let mut state = self.state.borrow_mut();
421 let mut s = state.as_mut().unwrap();
422 (*s.dcomp_state.as_ref().unwrap().swap_chain).Present(0, 0);
423 } else {
424 println!("ResizeBuffers failed: 0x{:x}", res);
425 }
426
427 DwmFlush();
430
431 let mut state = self.state.borrow_mut();
432 let mut s = state.as_mut().unwrap();
433 if let Some(ref mut ds) = s.dcomp_state {
434 let _ = ds.dcomp_target.set_root(&mut ds.swapchain_visual);
435 let _ = ds.dcomp_device.commit();
436 ds.sizing = false;
437 }
438 }
439 None
440 }
441 WM_SIZE => unsafe {
442 let width = LOWORD(lparam as u32) as u32;
443 let height = HIWORD(lparam as u32) as u32;
444 self.handler.size(width, height);
445 let use_hwnd = if let Some(ref dcomp_state) =
446 self.state.borrow().as_ref().unwrap().dcomp_state
447 {
448 dcomp_state.sizing
449 } else {
450 true
451 };
452 if use_hwnd {
453 let mut state = self.state.borrow_mut();
454 let mut s = state.as_mut().unwrap();
455 if let Some(ref mut rt) = s.render_target {
456 if let Some(hrt) = cast_to_hwnd(rt) {
457 let width = LOWORD(lparam as u32) as u32;
458 let height = HIWORD(lparam as u32) as u32;
459 let size = SizeU(D2D1_SIZE_U { width, height });
460 let _ = hrt.resize(size);
461 }
462 }
463 InvalidateRect(hwnd, null_mut(), FALSE);
464 } else {
465 let res;
466 {
467 let mut state = self.state.borrow_mut();
468 let mut s = state.as_mut().unwrap();
469 s.render_target = None;
470 res = (*s.dcomp_state.as_mut().unwrap().swap_chain)
471 .ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0);
472 }
473 if SUCCEEDED(res) {
474 self.rebuild_render_target();
475 self.render();
476 let mut state = self.state.borrow_mut();
477 let mut s = state.as_mut().unwrap();
478 if let Some(ref mut dcomp_state) = s.dcomp_state {
479 (*dcomp_state.swap_chain).Present(0, 0);
480 let _ = dcomp_state.dcomp_device.commit();
481 }
482 ValidateRect(hwnd, null_mut());
483 } else {
484 println!("ResizeBuffers failed: 0x{:x}", res);
485 }
486 }
487 Some(0)
488 },
489 WM_COMMAND => {
490 self.handler.command(LOWORD(wparam as u32) as u32);
491 Some(0)
492 }
493 WM_CHAR => {
494 let mods = get_mod_state(lparam);
495 self.handler.char(wparam as u32, mods);
496 Some(0)
497 }
498 WM_KEYDOWN | WM_SYSKEYDOWN => {
499 let mods = get_mod_state(lparam);
500 let handled = self.handler.keydown(wparam as i32, mods);
501 if handled {
502 Some(0)
503 } else {
504 None
505 }
506 }
507 WM_MOUSEWHEEL => {
508 let delta = HIWORD(wparam as u32) as i16 as i32;
509 let mods = LOWORD(wparam as u32) as u32;
510 self.handler.mouse_wheel(delta, mods);
511 Some(0)
512 }
513 WM_MOUSEHWHEEL => {
514 let delta = HIWORD(wparam as u32) as i16 as i32;
515 let mods = LOWORD(wparam as u32) as u32;
516 self.handler.mouse_hwheel(delta, mods);
517 Some(0)
518 }
519 WM_MOUSEMOVE => {
520 let x = LOWORD(lparam as u32) as i16 as i32;
521 let y = HIWORD(lparam as u32) as i16 as i32;
522 let mods = LOWORD(wparam as u32) as u32;
523 self.handler.mouse_move(x, y, mods);
524 Some(0)
525 }
526 WM_LBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP |
529 WM_MBUTTONDBLCLK | WM_MBUTTONDOWN | WM_MBUTTONUP |
530 WM_RBUTTONDBLCLK | WM_RBUTTONDOWN | WM_RBUTTONUP |
531 WM_XBUTTONDBLCLK | WM_XBUTTONDOWN | WM_XBUTTONUP =>
532 {
533 let which = match msg {
534 WM_LBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP => MouseButton::Left,
535 WM_MBUTTONDBLCLK | WM_MBUTTONDOWN | WM_MBUTTONUP => MouseButton::Middle,
536 WM_RBUTTONDBLCLK | WM_RBUTTONDOWN | WM_RBUTTONUP => MouseButton::Right,
537 WM_XBUTTONDBLCLK | WM_XBUTTONDOWN | WM_XBUTTONUP =>
538 match HIWORD(wparam as u32) {
539 1 => MouseButton::X1,
540 2 => MouseButton::X2,
541 _ => {
542 println!("unexpected X button event");
543 return None;
544 }
545 },
546 _ => unreachable!()
547 };
548 let ty = match msg {
549 WM_LBUTTONDOWN | WM_MBUTTONDOWN | WM_RBUTTONDOWN | WM_XBUTTONDOWN =>
550 MouseType::Down,
551 WM_LBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_RBUTTONDBLCLK | WM_XBUTTONDBLCLK =>
552 MouseType::DoubleClick,
553 WM_LBUTTONUP | WM_MBUTTONUP | WM_RBUTTONUP | WM_XBUTTONUP =>
554 MouseType::Up,
555 _ => unreachable!(),
556 };
557 let x = LOWORD(lparam as u32) as i16 as i32;
558 let y = HIWORD(lparam as u32) as i16 as i32;
559 let mods = LOWORD(wparam as u32) as u32;
560 let event = MouseEvent { x, y, mods, which, ty };
561 self.handler.mouse(&event);
562 Some(0)
563 }
564 WM_DESTROY => {
565 self.handler.destroy();
566 None
567 }
568 XI_RUN_IDLE => {
569 let queue = self.handle.borrow().take_idle_queue();
570 let handler_as_any = self.handler.as_any();
571 for callback in queue {
572 callback.call(handler_as_any);
573 }
574 Some(0)
575 }
576 _ => None
577 }
578 }
579}
580
581impl WindowBuilder {
582 pub fn new() -> WindowBuilder {
583 WindowBuilder {
584 handler: None,
585 dwStyle: WS_OVERLAPPEDWINDOW,
586 title: String::new(),
587 cursor: Cursor::Arrow,
588 menu: None,
589 present_strategy: Default::default(),
590 }
591 }
592
593 pub fn set_handler(&mut self, handler: Box<WinHandler>) {
595 self.handler = Some(handler);
596 }
597
598 pub fn set_scroll(&mut self, hscroll: bool, vscroll: bool) {
599 self.dwStyle &= !(WS_HSCROLL | WS_VSCROLL);
600 if hscroll {
601 self.dwStyle |= WS_HSCROLL;
602 }
603 if vscroll {
604 self.dwStyle |= WS_VSCROLL;
605 }
606 }
607
608 pub fn set_title<S: Into<String>>(&mut self, title: S) {
609 self.title = title.into();
610 }
611
612 pub fn set_cursor(&mut self, cursor: Cursor) {
614 self.cursor = cursor;
615 }
616
617 pub fn set_menu(&mut self, menu: Menu) {
618 self.menu = Some(menu);
619 }
620
621 pub fn set_present_strategy(&mut self, present_strategy: PresentStrategy) {
622 self.present_strategy = present_strategy;
623 }
624
625 pub fn build(self)
626 -> Result<WindowHandle, Error>
627 {
628 unsafe {
629 let class_name = "Xi Editor".to_wide();
634 let icon = LoadIconW(0 as HINSTANCE, IDI_APPLICATION);
635 let cursor = LoadCursorW(0 as HINSTANCE, self.cursor.get_lpcwstr());
636 let brush = CreateSolidBrush(0xffffff);
637 let wnd = WNDCLASSW {
638 style: 0,
639 lpfnWndProc: Some(win_proc_dispatch),
640 cbClsExtra: 0,
641 cbWndExtra: 0,
642 hInstance: 0 as HINSTANCE,
643 hIcon: icon,
644 hCursor: cursor,
645 hbrBackground: brush,
646 lpszMenuName: 0 as LPCWSTR,
647 lpszClassName: class_name.as_ptr(),
648 };
649 let class_atom = RegisterClassW(&wnd);
650 if class_atom == 0 {
651 return Err(Error::Null);
652 }
653
654 let wndproc = MyWndProc {
655 handler: self.handler.unwrap(),
656 handle: Default::default(),
657 d2d_factory: direct2d::Factory::new().unwrap(),
658 state: RefCell::new(None),
659 };
660
661 let window = WindowState {
662 hwnd: Cell::new(0 as HWND),
663 dpi: Cell::new(0.0),
664 wndproc: Box::new(wndproc),
665 idle_queue: Default::default(),
666 };
667 let win = Rc::new(window);
668 let handle = WindowHandle(Rc::downgrade(&win));
669
670 let dpi = if let Some(func) = OPTIONAL_FUNCTIONS.GetDpiForSystem {
672 func() as f32
674 } else {
675 96.0
678 };
679 win.dpi.set(dpi);
680 let width = (500.0 * (dpi/96.0)) as i32;
681 let height = (400.0 * (dpi/96.0)) as i32;
682
683 let hmenu = match self.menu {
684 Some(menu) => menu.into_hmenu(),
685 None => 0 as HMENU,
686 };
687 let mut dwExStyle = 0;
688 if self.present_strategy == PresentStrategy::Flip {
689 dwExStyle |= WS_EX_NOREDIRECTIONBITMAP;
690 }
691 let hwnd = create_window(dwExStyle, class_name.as_ptr(),
692 self.title.to_wide().as_ptr(), self.dwStyle,
693 CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0 as HWND, hmenu, 0 as HINSTANCE,
694 win.clone());
695 if hwnd.is_null() {
696 return Err(Error::Null);
697 }
698
699 let dcomp_state = create_dcomp_state(self.present_strategy, hwnd)
700 .unwrap_or_else(|e| {
701 println!("Error creating swapchain, falling back to hwnd: {:?}", e);
702 None
703 });
704
705 win.hwnd.set(hwnd);
706 let state = WndState {
707 render_target: None,
708 dcomp_state,
709 dpi,
710 };
711 win.wndproc.connect(&handle, state);
712 mem::drop(win);
713 Ok(handle)
714 }
715 }
716}
717
718unsafe fn choose_adapter(factory: *mut IDXGIFactory2) -> *mut IDXGIAdapter {
723 let mut i = 0;
724 let mut best_adapter = null_mut();
725 let mut best_vram = 0;
726 loop {
727 let mut adapter: *mut IDXGIAdapter = null_mut();
728 if !SUCCEEDED((*factory).EnumAdapters(i, &mut adapter)) {
729 break;
730 }
731 let mut desc: DXGI_ADAPTER_DESC = mem::uninitialized();
732 (*adapter).GetDesc(&mut desc);
733 let vram = desc.DedicatedVideoMemory;
734 if i == 0 || vram > best_vram {
735 best_vram = vram;
736 best_adapter = adapter;
737 }
738 println!("{:?}: desc = {:?}, vram = {}",
739 adapter,
740 (&mut desc.Description[0] as LPWSTR).from_wide(),
741 desc.DedicatedVideoMemory);
742 i += 1;
743 }
744 best_adapter
745}
746
747unsafe fn create_dcomp_state(present_strategy: PresentStrategy, hwnd: HWND)
748 -> Result<Option<DCompState>, Error>
749{
750 if present_strategy == PresentStrategy::Hwnd {
751 return Ok(None);
752 }
753 if let Some(create_dxgi_factory2) = OPTIONAL_FUNCTIONS.CreateDXGIFactory2 {
754
755 let mut factory: *mut IDXGIFactory2 = null_mut();
756 as_result(create_dxgi_factory2(0, &IID_IDXGIFactory2,
757 &mut factory as *mut *mut IDXGIFactory2 as *mut *mut c_void))?;
758 println!("dxgi factory pointer = {:?}", factory);
759 let adapter = choose_adapter(factory);
760 println!("adapter = {:?}", adapter);
761
762 let mut d3d11_device = D3D11Device::new_simple()?;
763 let mut d2d1_device = d3d11_device.create_d2d1_device()?;
764 let mut dcomp_device = d2d1_device.create_composition_device()?;
765 let mut dcomp_target = dcomp_device.create_target_for_hwnd(hwnd, true)?;
766
767 let (swap_effect, bufs) = match present_strategy {
768 PresentStrategy::Hwnd => unreachable!(),
769 PresentStrategy::Sequential => (DXGI_SWAP_EFFECT_SEQUENTIAL, 1),
770 PresentStrategy::Flip | PresentStrategy::FlipRedirect =>
771 (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, 2),
772 };
773 let desc = DXGI_SWAP_CHAIN_DESC1 {
774 Width: 1024,
775 Height: 768,
776 Format: DXGI_FORMAT_B8G8R8A8_UNORM,
777 Stereo: FALSE,
778 SampleDesc: DXGI_SAMPLE_DESC { Count: 1, Quality: 0 },
779 BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
780 BufferCount: bufs,
781 Scaling: DXGI_SCALING_STRETCH,
782 SwapEffect: swap_effect,
783 AlphaMode: DXGI_ALPHA_MODE_IGNORE,
784 Flags: 0,
785 };
786 let mut swap_chain: *mut IDXGISwapChain1 = null_mut();
787 let res = (*factory).CreateSwapChainForComposition(d3d11_device.raw_ptr() as *mut IUnknown,
788 &desc, null_mut(), &mut swap_chain);
789 println!("swap chain res = 0x{:x}, pointer = {:?}", res, swap_chain);
790
791 let mut swapchain_visual = dcomp_device.create_visual()?;
792 swapchain_visual.set_content_raw(swap_chain as *mut IUnknown)?;
793 dcomp_target.set_root(&mut swapchain_visual)?;
794 Ok(Some(DCompState {
795 swap_chain, dcomp_device, dcomp_target, swapchain_visual,
796 sizing: false,
797 }))
798 } else {
799 Ok(None)
800 }
801}
802
803unsafe extern "system" fn win_proc_dispatch(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM)
804 -> LRESULT
805{
806 if msg == WM_CREATE {
807 let create_struct = &*(lparam as *const CREATESTRUCTW);
808 let wndproc_ptr = create_struct.lpCreateParams;
809 SetWindowLongPtrW(hwnd, GWLP_USERDATA, wndproc_ptr as LONG_PTR);
810 }
811 let window_ptr = GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *const WindowState;
812 let result = {
813 if window_ptr.is_null() {
814 None
815 } else {
816 (*window_ptr).wndproc.window_proc(hwnd, msg, wparam, lparam)
817 }
818 };
819 if msg == WM_NCDESTROY {
820 if !window_ptr.is_null() {
821 SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
822 mem::drop(Rc::from_raw(window_ptr));
823 }
824 }
825 match result {
826 Some(lresult) => lresult,
827 None => DefWindowProcW(hwnd, msg, wparam, lparam),
828 }
829}
830
831unsafe fn create_window(
833 dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, x: c_int,
834 y: c_int, nWidth: c_int, nHeight: c_int, hWndParent: HWND, hMenu: HMENU,
835 hInstance: HINSTANCE, wndproc: Rc<WindowState>) -> HWND
836{
837 CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y,
838 nWidth, nHeight, hWndParent, hMenu, hInstance, Rc::into_raw(wndproc) as LPVOID)
839}
840
841impl Cursor {
842 fn get_lpcwstr(&self) -> LPCWSTR {
843 match self {
844 Cursor::Arrow => IDC_ARROW,
845 Cursor::IBeam => IDC_IBEAM,
846 }
847 }
848}
849
850impl WindowHandle {
851 pub fn show(&self) {
852 if let Some(w) = self.0.upgrade() {
853 let hwnd = w.hwnd.get();
854 unsafe {
855 ShowWindow(hwnd, SW_SHOWNORMAL);
856 UpdateWindow(hwnd);
857 }
858 }
859 }
860
861 pub fn close(&self) {
862 if let Some(w) = self.0.upgrade() {
863 let hwnd = w.hwnd.get();
864 unsafe {
865 DestroyWindow(hwnd);
866 }
867 }
868 }
869
870 pub fn invalidate(&self) {
871 if let Some(w) = self.0.upgrade() {
872 let hwnd = w.hwnd.get();
873 unsafe {
874 InvalidateRect(hwnd, null(), FALSE);
875 }
876 }
877 }
878
879 pub fn get_hwnd(&self) -> Option<HWND> {
882 self.0.upgrade().map(|w| w.hwnd.get())
883 }
884
885 pub fn file_dialog(&self, ty: FileDialogType, options: FileDialogOptions)
886 -> Result<OsString, Error>
887 {
888 let hwnd = self.get_hwnd().ok_or(Error::Null)?;
889 unsafe { get_file_dialog_path(hwnd, ty, options) }
890 }
891
892 pub fn get_idle_handle(&self) -> Option<IdleHandle> {
894 self.0.upgrade().map(|w|
895 IdleHandle {
896 hwnd: w.hwnd.get(),
897 queue: w.idle_queue.clone(),
898 }
899 )
900 }
901
902 fn take_idle_queue(&self) -> Vec<Box<IdleCallback>> {
903 if let Some(w) = self.0.upgrade() {
904 mem::replace(&mut w.idle_queue.lock().unwrap(), Vec::new())
905 } else {
906 Vec::new()
907 }
908 }
909
910 pub fn get_dpi(&self) -> f32 {
912 if let Some(w) = self.0.upgrade() {
913 w.dpi.get()
914 } else {
915 96.0
916 }
917 }
918
919 pub fn px_to_pixels(&self, x: f32) -> i32 {
921 (x * self.get_dpi() * (1.0 / 96.0)).round() as i32
922 }
923
924 pub fn px_to_pixels_xy(&self, x: f32, y: f32) -> (i32, i32) {
926 let scale = self.get_dpi() * (1.0 / 96.0);
927 ((x * scale).round() as i32, (y * scale).round() as i32)
928 }
929
930 pub fn pixels_to_px<T: Into<f64>>(&self, x: T) -> f32 {
932 (x.into() as f32) * 96.0 / self.get_dpi()
933 }
934
935 pub fn pixels_to_px_xy<T: Into<f64>>(&self, x: T, y: T) -> (f32, f32) {
937 let scale = 96.0 / self.get_dpi();
938 ((x.into() as f32) * scale, (y.into() as f32) * scale)
939 }
940}
941
942unsafe impl Send for IdleHandle {}
944
945impl IdleHandle {
946 pub fn add_idle<F>(&self, callback: F)
950 where F: FnOnce(&Any) + Send + 'static
951 {
952 let mut queue = self.queue.lock().unwrap();
953 if queue.is_empty() {
954 unsafe {
955 PostMessageW(self.hwnd, XI_RUN_IDLE, 0, 0);
956 }
957 }
958 queue.push(Box::new(callback));
959 }
960
961 fn invalidate(&self) {
962 unsafe {
963 InvalidateRect(self.hwnd, null(), FALSE);
964 }
965 }
966}
967
968unsafe fn cast_to_hwnd(rt: &GenericRenderTarget) -> Option<HwndRenderTarget> {
972 let raw_ptr = rt.clone().get_raw();
973 let mut hwnd = null_mut();
974 let err = (*raw_ptr).QueryInterface(&ID2D1HwndRenderTarget::uuidof(), &mut hwnd);
975 if SUCCEEDED(err) {
976 Some(HwndRenderTarget::from_raw(hwnd as *mut ID2D1HwndRenderTarget))
977 } else {
978 None
979 }
980}