1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#![allow(clippy::needless_doctest_main)]

//! A window library in Rust for Windows.
//!
//! `wita` is a library that create a window and run an event loop.
//! It is only for Windows.
//!
//! # Example
//!
//! ```no_run
//! struct Application;
//!
//! impl Application {
//!     fn new() -> Result<Self, wita::ApiError> {
//!         wita::WindowBuilder::new()
//!             .title("hello, world!")
//!             .build()?;
//!         Ok(Self)
//!     }
//! }
//!
//! impl wita::EventHandler for Application {
//!     fn closed(&mut self, _: &wita::Window) {
//!         println!("closed");
//!     }
//! }
//!
//! fn main() {
//!     wita::run(wita::RunType::Wait, Application::new).unwrap();
//! }
//! ```
//!
//! # Event handling
//!
//! You must implement [`EventHandler`] for the your defined object, and can handle events in the `impl EventHandler`.
//!
//! ```ignore
//! struct Foo {}
//!
//! impl Foo {
//!     fn new() -> Result<Self, wita::ApiError> {
//!         wita::WindowBuilder::new().build()?;
//!         Ok(Self {})
//!     }
//! }
//!
//! impl wita::EventHandler for Foo {
//!     // You define handlers.
//!     // For example, handle the event that closed the window.
//!     fn closed(&mut self, _: &wita::Window) {
//!         // write handling codes
//!     }
//! }
//! ```
//! Next, pass the your defined object to [`run`].
//!
//! ```ignore
//! wita::run(wita::RunType::Wait, Foo::new).unwrap();
//! ```
//!
//! # Drawing on the window
//! There are directly no any methods for drawing on a [`Window`] in `wita`.
//! However, a [`Window`] provides the [`raw_handle`] that return a pointer which is `HWND`.
//! You can create a drawing context by using the [`raw_handle`] such as DirectX, Vulkan, etc.
//!
//! [`raw_handle`]: struct.Window.html#method.raw_handle
//!

mod bindings {
    ::windows::include_bindings!();
}

mod api;
mod context;
mod device;
mod event;
mod geometry;
pub mod ime;
mod monitor;
mod procedure;
#[cfg(any(feature = "raw_input", doc))]
pub mod raw_input;
mod resource;
mod window;
#[macro_use]
pub mod error;

pub use context::RunType;
pub use device::*;
#[doc(inline)]
pub use error::ApiError;
pub use event::*;
pub use geometry::*;
pub use monitor::*;
pub use resource::*;
pub use window::*;

use bindings::Windows::Win32::{Foundation::*, UI::WindowsAndMessaging::*};
use context::*;

/// The value is an unit in logical coordinates.
pub const DEFAULT_DPI: i32 = 96;

/// Run the event loop.
pub fn run<F, T, E>(run_type: RunType, f: F) -> Result<(), E>
where
    F: FnOnce() -> Result<T, E>,
    T: EventHandler + 'static,
{
    api::enable_dpi_awareness();
    api::enable_gui_thread();
    window::register_class::<T>();
    context::create_context();
    let handler = f();
    match handler {
        Ok(handler) => set_event_handler(handler),
        Err(e) => return Err(e),
    }
    let mut msg = MSG::default();
    match run_type {
        RunType::Idle => unsafe {
            while msg.message != WM_QUIT {
                call_handler(|eh: &mut T, _| eh.pre_processing());
                if PeekMessageW(&mut msg, HWND::NULL, 0, 0, PM_REMOVE) != BOOL(0) {
                    TranslateMessage(&msg);
                    DispatchMessageW(&msg);
                } else {
                    call_handler(|eh: &mut T, _| eh.idle());
                }
                maybe_resume_unwind();
                call_handler(|eh: &mut T, _| eh.post_processing());
            }
        },
        RunType::Wait => unsafe {
            loop {
                let ret = GetMessageW(&mut msg, HWND::NULL, 0, 0);
                if ret == BOOL(0) || ret == BOOL(-1) {
                    break;
                }
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
                maybe_resume_unwind();
            }
        },
    }
    destroy_context();
    Ok(())
}