Modify window handling.
This commit is contained in:
parent
cde7b3560f
commit
9a36e1c4f8
@ -10,6 +10,9 @@ crossbeam = "0.8.4"
|
||||
|
||||
vulkano = "0.34.1"
|
||||
glam = "0.29.2"
|
||||
egui = "0.29.1"
|
||||
|
||||
cpal = "0.15.3"
|
||||
|
||||
pool = { git = "https://git.tsukiyo.org/Utility/pool" }
|
||||
|
||||
@ -19,7 +22,10 @@ windows = { version = "0.58.0", features = [
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_UI_Input",
|
||||
"Win32_System_Registry",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Devices_DeviceAndDriverInstallation",
|
||||
"Win32_Devices_Display",
|
||||
] }
|
||||
widestring = "1.1.0"
|
||||
|
||||
|
30
doc/design/network/api_control.md
Normal file
30
doc/design/network/api_control.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Control API
|
||||
|
||||
## Packet
|
||||
|
||||
```
|
||||
<Id:4B> <Secret:12B> <Data:496B>
|
||||
```
|
||||
|
||||
### Encryption
|
||||
|
||||
## Commnad
|
||||
|
||||
Each packet may provide up to 62 commands.
|
||||
|
||||
```
|
||||
<OpCode:2b> <Code:14b> <Channel:16b> <Value:32b>
|
||||
```
|
||||
|
||||
### OpCode
|
||||
|
||||
- (0) Info
|
||||
- (1) Get
|
||||
- (2) Set
|
||||
- (3) Add
|
||||
|
||||
### Code
|
||||
|
||||
### Channel
|
||||
|
||||
### Value
|
4
doc/design/network/srv.md
Normal file
4
doc/design/network/srv.md
Normal file
@ -0,0 +1,4 @@
|
||||
# SRV Records
|
||||
|
||||
- _donten._tcp.example.com
|
||||
- _donten._udp.example.com
|
@ -18,12 +18,12 @@ fn main()
|
||||
sys_win.create(donten::WindowConfig {
|
||||
x: CW_USEDEFAULT, y: CW_USEDEFAULT,
|
||||
width: 640, height: 480,
|
||||
visible: true,
|
||||
resize: false, caption: true, sysmenu: false,
|
||||
resize: false,
|
||||
private: false,
|
||||
title: "Hello".to_string(),
|
||||
context: None,
|
||||
}).ok();
|
||||
|
||||
std::thread::park();
|
||||
|
||||
// Handle command queries.
|
||||
}
|
||||
|
@ -14,3 +14,9 @@ impl Subsystem for APIManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for APIManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
74
src/system/api_control/mod.rs
Normal file
74
src/system/api_control/mod.rs
Normal file
@ -0,0 +1,74 @@
|
||||
#[derive(Clone, Copy)]
|
||||
enum OpCode {
|
||||
None,
|
||||
Set,
|
||||
Add,
|
||||
Get,
|
||||
}
|
||||
|
||||
struct Command {
|
||||
op:OpCode,
|
||||
code:u16,
|
||||
channel:u16,
|
||||
value:i32,
|
||||
}
|
||||
|
||||
struct Endpoint {
|
||||
key:[u8;4],
|
||||
secret:[u8;12],
|
||||
mask:[u8;508],
|
||||
}
|
||||
impl Endpoint {
|
||||
fn parse(&self, data:&[u8]) -> Result<Vec<Command>,()>
|
||||
{
|
||||
if data.len() == 512 {
|
||||
let mut commands = Vec::new();
|
||||
|
||||
let key :[u8;4] = data[0..4].try_into().unwrap_or_default();
|
||||
let secret :[u8;12] = data[4..16].try_into().unwrap_or_default();
|
||||
|
||||
if key == self.key && secret == self.secret {
|
||||
let mut has_next = true;
|
||||
let mut index = 16;
|
||||
while index < 512 && has_next {
|
||||
let data :[u8;8] = data[index..index+8].try_into().unwrap_or_default();
|
||||
|
||||
let op = match data[0] & 0x7 {
|
||||
1 => OpCode::Get,
|
||||
2 => OpCode::Set,
|
||||
3 => OpCode::Add,
|
||||
_ => OpCode::None,
|
||||
};
|
||||
|
||||
match op {
|
||||
OpCode::None => { has_next = false; }
|
||||
_ => {
|
||||
let code = (((data[1] as u16) << 8) + (data[0] as u16)) >> 3;
|
||||
let channel = ((data[3] as u16) << 8) + (data[2] as u16);
|
||||
|
||||
let value = (data[7] as i32) << 24
|
||||
+ (data[6] as i32) << 16
|
||||
+ (data[5] as i32) << 8
|
||||
+ (data[4] as i32);
|
||||
|
||||
commands.push(Command {
|
||||
op,
|
||||
code,
|
||||
channel,
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
index += 8;
|
||||
}
|
||||
|
||||
Ok(commands)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
0
src/system/api_device/mod.rs
Normal file
0
src/system/api_device/mod.rs
Normal file
11
src/system/app/context/launcher.rs
Normal file
11
src/system/app/context/launcher.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use super::*;
|
||||
|
||||
pub struct Launcher {
|
||||
|
||||
}
|
||||
impl Launcher {
|
||||
|
||||
}
|
||||
impl Context for Launcher {
|
||||
|
||||
}
|
5
src/system/app/context/mod.rs
Normal file
5
src/system/app/context/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub trait Context {
|
||||
fn draw() { }
|
||||
}
|
||||
|
||||
mod launcher; use launcher::Launcher;
|
23
src/system/app/mod.rs
Normal file
23
src/system/app/mod.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use super::*;
|
||||
|
||||
mod context; pub use context::*;
|
||||
pub struct AppManager {
|
||||
channel:Sender<Query>,
|
||||
}
|
||||
|
||||
impl AppManager {
|
||||
|
||||
}
|
||||
|
||||
impl Subsystem for AppManager {
|
||||
fn start(_supervisor:Option<Sender<Query>>) -> Result<Sender<Query>, Error>
|
||||
{
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for AppManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
@ -14,3 +14,9 @@ impl Subsystem for AudioManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for AudioManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -14,3 +14,9 @@ impl Subsystem for ControlManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for ControlManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -29,3 +29,9 @@ impl Subsystem for InputManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for InputManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ pub(crate) mod scene; pub(crate) use scene::*;
|
||||
pub(crate) mod network; pub(crate) use network::*;
|
||||
pub(crate) mod storage; pub(crate) use storage::*;
|
||||
pub(crate) mod api; pub(crate) use api::*;
|
||||
pub(crate) mod api_control; pub(crate) use api_control::*;
|
||||
pub(crate) mod api_device; pub(crate) use api_device::*;
|
||||
pub(crate) mod app; pub(crate) use app::*;
|
||||
|
||||
pub(crate) trait Subsystem {
|
||||
pub(crate) trait Subsystem : From<Sender<Query>> {
|
||||
fn start(supervisor:Option<Sender<Query>>) -> Result<Sender<Query>, Error>;
|
||||
fn shutdown() -> Result<(), Error> { Ok(()) }
|
||||
}
|
||||
@ -23,7 +26,7 @@ pub(crate) trait Subsystem {
|
||||
pub enum System {
|
||||
Supervisor = 0,
|
||||
Window,
|
||||
Render,
|
||||
Video,
|
||||
Audio,
|
||||
Input,
|
||||
Control,
|
||||
@ -31,5 +34,8 @@ pub enum System {
|
||||
Network,
|
||||
Storage,
|
||||
API,
|
||||
APIDevice,
|
||||
APIControl,
|
||||
App,
|
||||
_MAX,
|
||||
}
|
||||
|
@ -14,3 +14,9 @@ impl Subsystem for NetworkManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for NetworkManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ impl Query {
|
||||
}
|
||||
|
||||
pub enum QueryData {
|
||||
Notify,
|
||||
|
||||
Supervisor(SupervisorQuery),
|
||||
API,
|
||||
Audio,
|
||||
|
9
src/system/scene/entity/camera.rs
Normal file
9
src/system/scene/entity/camera.rs
Normal file
@ -0,0 +1,9 @@
|
||||
pub struct Camera {
|
||||
position:glam::DVec3,
|
||||
orientation:glam::Quat,
|
||||
|
||||
fov:f64,
|
||||
|
||||
transform:glam::DMat3,
|
||||
itransform:glam::DMat3,
|
||||
}
|
1
src/system/scene/entity/mod.rs
Normal file
1
src/system/scene/entity/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod camera; pub use camera::Camera;
|
@ -1,6 +1,8 @@
|
||||
use super::*;
|
||||
|
||||
mod entity; pub use entity::*;
|
||||
mod world;
|
||||
|
||||
pub struct SceneManager {
|
||||
channel:Sender<Query>,
|
||||
}
|
||||
@ -15,3 +17,9 @@ impl Subsystem for SceneManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for SceneManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -14,3 +14,9 @@ impl Subsystem for StorageManager {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for StorageManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -24,3 +24,9 @@ impl Subsystem for Supervisor {
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for Supervisor {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
4
src/system/video/device/mod.rs
Normal file
4
src/system/video/device/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub struct Device {
|
||||
pub id:usize,
|
||||
pub name:String,
|
||||
}
|
@ -1,14 +1,26 @@
|
||||
use pool::Pool;
|
||||
|
||||
use crate::system::*;
|
||||
use super::vulkan::*;
|
||||
|
||||
pub struct Internal {
|
||||
supervisor:Sender<Query>,
|
||||
|
||||
devices:Pool<()>,
|
||||
surfaces:Pool<()>,
|
||||
swapchains:Pool<()>,
|
||||
viewports:Pool<()>,
|
||||
}
|
||||
impl Internal {
|
||||
pub fn thread(supervisor:Sender<Query>, _tx:Sender<Query>, rx:Receiver<Query>)
|
||||
{
|
||||
let _sv = Internal {
|
||||
supervisor,
|
||||
|
||||
devices:Pool::new(),
|
||||
surfaces:Pool::new(),
|
||||
swapchains:Pool::new(),
|
||||
viewports:Pool::new(),
|
||||
};
|
||||
|
||||
// Initialize rendering system.
|
@ -1,8 +1,9 @@
|
||||
use super::*;
|
||||
|
||||
mod query; pub use query::*;
|
||||
mod device; pub use device::Device;
|
||||
mod vulkan; use vulkan::Vulkan as Renderer;
|
||||
mod internal; use internal::Internal;
|
||||
mod query; pub use query::VideoQuery;
|
||||
|
||||
pub struct VideoManager {
|
||||
channel:Sender<Query>,
|
||||
@ -30,3 +31,16 @@ impl Subsystem for VideoManager {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sender<Query>> for VideoManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
|
||||
Context (physical device, window)
|
||||
|
||||
Viewport
|
||||
|
||||
***/
|
||||
|
@ -1,4 +1,29 @@
|
||||
use super::*;
|
||||
|
||||
pub enum VideoQuery {
|
||||
None,
|
||||
|
||||
GetDevices,
|
||||
Devices {
|
||||
devices:Vec<Device>,
|
||||
},
|
||||
|
||||
CreateContext {
|
||||
handle:WindowHandle,
|
||||
},
|
||||
ContextCreated {
|
||||
id:usize,
|
||||
},
|
||||
|
||||
RefreshContext {
|
||||
id:usize,
|
||||
},
|
||||
|
||||
DestroyContext {
|
||||
id:usize,
|
||||
},
|
||||
|
||||
Render {
|
||||
contexts:Vec<usize>,
|
||||
},
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
pub struct WindowConfig {
|
||||
pub x:i32, pub y:i32,
|
||||
pub width:i32, pub height:i32,
|
||||
pub visible:bool,
|
||||
pub resize:bool,
|
||||
pub caption:bool,
|
||||
pub sysmenu:bool,
|
||||
|
||||
pub resize:bool,
|
||||
pub private:bool,
|
||||
|
||||
pub title:String,
|
||||
pub context:Option<usize>,
|
||||
}
|
||||
|
198
src/system/window/display.rs
Normal file
198
src/system/window/display.rs
Normal file
@ -0,0 +1,198 @@
|
||||
use windows::core::PCWSTR;
|
||||
use windows::Win32::{
|
||||
Foundation::{
|
||||
BOOL, RECT, LPARAM,
|
||||
GetLastError,
|
||||
},
|
||||
Graphics::Gdi::{
|
||||
EnumDisplayMonitors,
|
||||
GetMonitorInfoW,
|
||||
EnumDisplayDevicesW,
|
||||
DISPLAY_DEVICEW,
|
||||
MONITORINFO, MONITORINFOEXW,
|
||||
HMONITOR, HDC,
|
||||
},
|
||||
UI::WindowsAndMessaging::MONITORINFOF_PRIMARY,
|
||||
Devices::DeviceAndDriverInstallation::{
|
||||
SetupDiEnumDeviceInfo,
|
||||
SetupDiGetClassDevsW,
|
||||
SetupDiGetDeviceRegistryPropertyW,
|
||||
SetupDiDestroyDeviceInfoList,
|
||||
SetupDiOpenDevRegKey,
|
||||
SPDRP_HARDWAREID,
|
||||
DIGCF_PRESENT,
|
||||
SP_DEVINFO_DATA,
|
||||
GUID_DEVCLASS_MONITOR,
|
||||
DICS_FLAG_GLOBAL,
|
||||
DIREG_DEV,
|
||||
DIGCF_DEVICEINTERFACE,
|
||||
DIGCF_ALLCLASSES,
|
||||
},
|
||||
Devices::Display::GUID_DEVINTERFACE_MONITOR,
|
||||
System::Registry::{
|
||||
REG_SZ,
|
||||
HKEY_LOCAL_MACHINE,
|
||||
KEY_READ,
|
||||
RegQueryValueExW,
|
||||
},
|
||||
};
|
||||
|
||||
use pool::Pool;
|
||||
|
||||
pub struct Display {
|
||||
handle:HMONITOR,
|
||||
name:String,
|
||||
primary:bool,
|
||||
|
||||
x:i32, y:i32,
|
||||
width:i32, height:i32,
|
||||
|
||||
wx:i32, wy:i32,
|
||||
wwidth:i32, wheight:i32,
|
||||
}
|
||||
|
||||
pub struct DisplayManager {
|
||||
displays:Vec<Display>,
|
||||
}
|
||||
impl DisplayManager {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
displays:Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enumerate(&mut self)
|
||||
{
|
||||
self.displays.clear();
|
||||
unsafe {
|
||||
EnumDisplayMonitors(None, None, Some(Self::enumerate_callback), LPARAM(&mut self.displays as *mut Vec<Display> as _)).ok().ok();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn enumerate_callback(hmonitor:HMONITOR, _hdc:HDC, _rect:*mut RECT, lparam:LPARAM) -> BOOL
|
||||
{
|
||||
let displays = lparam.0 as *mut Vec<Display>;
|
||||
|
||||
let mut mi = MONITORINFOEXW {
|
||||
monitorInfo:MONITORINFO {
|
||||
cbSize: std::mem::size_of::<MONITORINFOEXW>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut dv = DISPLAY_DEVICEW {
|
||||
cb: std::mem::size_of::<DISPLAY_DEVICEW>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut name = String::new();
|
||||
|
||||
if GetMonitorInfoW(hmonitor, &mut mi as *mut MONITORINFOEXW as _).as_bool() {
|
||||
if EnumDisplayDevicesW(PCWSTR::from_raw(mi.szDevice.as_ptr()), 0, &mut dv as _, 1).as_bool() {
|
||||
let raw_device_id = PCWSTR::from_raw(dv.DeviceID.as_ptr()).to_string().unwrap();
|
||||
let cleaned_device_id = raw_device_id
|
||||
.trim_start_matches(r"\\?\")
|
||||
.split("#{")
|
||||
.collect::<Vec<_>>()[0]
|
||||
.replace('#', "\\")
|
||||
.to_string();
|
||||
|
||||
match SetupDiGetClassDevsW(
|
||||
None,
|
||||
PCWSTR::from_raw(widestring::U16CString::from_str(cleaned_device_id).unwrap().as_ptr()),
|
||||
None,
|
||||
DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,
|
||||
) {
|
||||
Ok(hdevinfo) => {
|
||||
if !hdevinfo.is_invalid() {
|
||||
let mut devinfo_data = SP_DEVINFO_DATA {
|
||||
cbSize:std::mem::size_of::<SP_DEVINFO_DATA>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut device_index = 0;
|
||||
while SetupDiEnumDeviceInfo(hdevinfo, device_index, &mut devinfo_data).is_ok() {
|
||||
const BUFFER_SIZE :usize = 256;
|
||||
let mut buffer_size = BUFFER_SIZE as u32;
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
let mut property_type = 0u32;
|
||||
|
||||
match SetupDiGetDeviceRegistryPropertyW(
|
||||
hdevinfo,
|
||||
&devinfo_data,
|
||||
SPDRP_HARDWAREID,
|
||||
Some(&mut property_type),
|
||||
Some(&mut buffer),
|
||||
Some(&mut buffer_size as _)
|
||||
) {
|
||||
Ok(_) => {
|
||||
match SetupDiOpenDevRegKey(
|
||||
hdevinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL.0,
|
||||
0,
|
||||
DIREG_DEV,
|
||||
KEY_READ.0,
|
||||
) {
|
||||
Ok(hkey) => {
|
||||
const KEY_BUFFER_SIZE :usize = 1024;
|
||||
let mut key_buffer = [0u8; KEY_BUFFER_SIZE];
|
||||
let mut key_buffer_size = KEY_BUFFER_SIZE as u32;
|
||||
|
||||
let result = RegQueryValueExW(
|
||||
hkey,
|
||||
PCWSTR::from_raw(widestring::U16CString::from_str("EDID\0").unwrap().as_ptr() as _),
|
||||
None,
|
||||
None,
|
||||
Some(&mut key_buffer as _),
|
||||
Some(&mut key_buffer_size),
|
||||
);
|
||||
|
||||
if result.is_ok() {
|
||||
const DESCRIPTOR_START :usize = 54;
|
||||
for block in key_buffer[DESCRIPTOR_START..].chunks_exact(18) {
|
||||
if block[3] == 0xFC {
|
||||
name = String::from_utf8(block[5..18].to_vec()).unwrap_or_default().trim_end_matches(['\0', ' ', '\n', '\r']).to_string();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("RegQueryValueExW: {}", result.0);
|
||||
}
|
||||
}
|
||||
Err(e) => { println!("regkey: {}", e.message()); }
|
||||
}
|
||||
}
|
||||
Err(e) => { println!("SetupDiOpenDevRegKey: {}", e.message()); }
|
||||
}
|
||||
|
||||
device_index += 1;
|
||||
}
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(hdevinfo).ok();
|
||||
}
|
||||
Err(e) => { println!("SetupDiGetClassDevsW: {} ; {}", e.message(), GetLastError().0); }
|
||||
}
|
||||
}
|
||||
|
||||
(*displays).push(Display {
|
||||
handle:hmonitor,
|
||||
name,
|
||||
primary:(mi.monitorInfo.dwFlags & MONITORINFOF_PRIMARY) != 0,
|
||||
|
||||
x:mi.monitorInfo.rcMonitor.left,
|
||||
y:mi.monitorInfo.rcMonitor.top,
|
||||
width:mi.monitorInfo.rcMonitor.right - mi.monitorInfo.rcMonitor.left,
|
||||
height:mi.monitorInfo.rcMonitor.bottom - mi.monitorInfo.rcMonitor.top,
|
||||
|
||||
wx:mi.monitorInfo.rcWork.left,
|
||||
wy:mi.monitorInfo.rcWork.top,
|
||||
wwidth:mi.monitorInfo.rcWork.right - mi.monitorInfo.rcWork.left,
|
||||
wheight:mi.monitorInfo.rcWork.bottom - mi.monitorInfo.rcWork.top,
|
||||
});
|
||||
}
|
||||
|
||||
BOOL(1)
|
||||
}
|
||||
}
|
@ -45,10 +45,8 @@ use windows::{
|
||||
WDA_MONITOR,
|
||||
CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT,
|
||||
SW_SHOW,
|
||||
WM_MOVE, WM_SIZE,
|
||||
WM_INPUT, WM_DEVICECHANGE, WM_DISPLAYCHANGE,
|
||||
WM_NULL,
|
||||
WS_OVERLAPPED, WS_POPUPWINDOW,
|
||||
WS_POPUP, WS_OVERLAPPED, WS_POPUPWINDOW,
|
||||
WS_BORDER, WS_SIZEBOX, WS_CAPTION,
|
||||
WS_SYSMENU, WS_MINIMIZEBOX, WS_MAXIMIZEBOX,
|
||||
WS_VISIBLE,
|
||||
@ -59,38 +57,49 @@ use windows::{
|
||||
}
|
||||
};
|
||||
use std::sync::RwLock;
|
||||
use pool::Pool;
|
||||
|
||||
mod display; use display::DisplayManager;
|
||||
|
||||
static mut WINPROC_SENDER :RwLock<Option<crossbeam::channel::Sender<Query>>> = RwLock::new(None);
|
||||
|
||||
enum InternalQuery {
|
||||
None,
|
||||
Thread(u32),
|
||||
}
|
||||
use super::{
|
||||
display::DisplayManager,
|
||||
winproc::{window_proc, WINPROC_SENDER},
|
||||
};
|
||||
|
||||
pub struct Internal {
|
||||
supervisor:Sender<Query>,
|
||||
input:Option<Sender<Query>>,
|
||||
video:Option<Sender<Query>>,
|
||||
app:Option<Sender<Query>>,
|
||||
|
||||
display:DisplayManager,
|
||||
windows:Pool<HWND>,
|
||||
}
|
||||
impl Internal {
|
||||
pub fn thread(supervisor:Sender<Query>, tx:Sender<Query>, rx:Receiver<Query>)
|
||||
{
|
||||
let _sv = Internal {
|
||||
let mut sv = Internal {
|
||||
supervisor,
|
||||
input:None,
|
||||
video:None,
|
||||
app:None,
|
||||
|
||||
display:DisplayManager::new(),
|
||||
windows:Pool::new(),
|
||||
};
|
||||
|
||||
let (system_sender, system_receiver) = crossbeam::channel::bounded::<InternalQuery>(16);
|
||||
let (thread_sender, thread_receiver) = crossbeam::channel::bounded::<Query>(16);
|
||||
|
||||
if let Ok(channel) = unsafe {WINPROC_SENDER.get_mut()} {
|
||||
*channel = Some(tx.clone());
|
||||
*channel = Some((tx.clone(), system_sender.clone()));
|
||||
} else {
|
||||
println!("error: failed to set window system sender.");
|
||||
}
|
||||
|
||||
let (system_sender, system_receiver) = crossbeam::channel::bounded::<InternalQuery>(16);
|
||||
let (thread_sender, thread_receiver) = crossbeam::channel::bounded::<Query>(16);
|
||||
// Enumerate monitors.
|
||||
sv.display.enumerate();
|
||||
|
||||
// Prepare window handler thread.
|
||||
std::thread::spawn(move || {
|
||||
let system_sender = system_sender;
|
||||
|
||||
// Initialize window settings.
|
||||
let class_name = widestring::U16CString::from_str("donten-window-class").unwrap();
|
||||
@ -131,7 +140,7 @@ impl Internal {
|
||||
}
|
||||
}
|
||||
if unsafe {RegisterRawInputDevices(&rawinput_devices, std::mem::size_of::<RAWINPUTDEVICE>() as u32)}.is_err() {
|
||||
println!("Failed to register input devices: {}", unsafe {GetLastError()}.to_hresult().message());
|
||||
println!("error: failed to register input devices: {}", unsafe {GetLastError()}.to_hresult().message());
|
||||
}
|
||||
|
||||
// Send thread id to system.
|
||||
@ -140,7 +149,7 @@ impl Internal {
|
||||
// Process window events.
|
||||
let mut msg = MSG::default();
|
||||
unsafe {
|
||||
while GetMessageW(&mut msg, None, 0, 0).into() {
|
||||
while GetMessageW(&mut msg, None, 0, 0).as_bool() {
|
||||
TranslateMessage(&msg).ok().ok();
|
||||
DispatchMessageW(&msg);
|
||||
|
||||
@ -163,26 +172,25 @@ impl Internal {
|
||||
WindowQuery::Create {
|
||||
config,
|
||||
} => {
|
||||
|
||||
let dwexstyle = WS_EX_APPWINDOW;
|
||||
let mut dwstyle = if config.caption { WS_OVERLAPPED } else { WS_POPUPWINDOW };
|
||||
let mut dwstyle = WS_POPUP | WS_BORDER | WS_VISIBLE; //if config.caption { WS_OVERLAPPED } else { WS_POPUPWINDOW };
|
||||
|
||||
if config.sysmenu {
|
||||
/*if config.sysmenu {
|
||||
dwstyle |= WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
}
|
||||
}*/
|
||||
|
||||
if config.resize {
|
||||
dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX;
|
||||
dwstyle |= WS_SIZEBOX; // | WS_MAXIMIZEBOX
|
||||
}
|
||||
|
||||
if config.visible {
|
||||
/*if config.visible {
|
||||
dwstyle |= WS_VISIBLE;
|
||||
}
|
||||
}*/
|
||||
|
||||
match CreateWindowExW(
|
||||
dwexstyle,
|
||||
class_name,
|
||||
PCWSTR(widestring::U16CString::from_str(config.title).unwrap().as_ptr()),
|
||||
PCWSTR::null(),
|
||||
dwstyle,
|
||||
config.x,
|
||||
config.y,
|
||||
@ -199,7 +207,11 @@ impl Internal {
|
||||
}
|
||||
|
||||
// Return window information to manager.
|
||||
if system_sender.send(InternalQuery::Create {
|
||||
handle:hwnd.into(),
|
||||
}).is_ok() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
@ -226,12 +238,99 @@ impl Internal {
|
||||
|
||||
// Handle messages.
|
||||
while let Ok(msg) = rx.recv() {
|
||||
match &msg.data {
|
||||
match msg.data {
|
||||
QueryData::Notify => {
|
||||
while let Ok(msg) = system_receiver.try_recv() {
|
||||
match msg {
|
||||
|
||||
InternalQuery::Create {
|
||||
handle,
|
||||
} => {
|
||||
sv.windows.add(handle.handle);
|
||||
|
||||
if let Some(sc) = &sv.video {
|
||||
sc.send(Query::new(Some(tx.clone()), QueryData::Video(VideoQuery::CreateContext {
|
||||
handle:handle.clone(),
|
||||
}))).ok();
|
||||
}
|
||||
}
|
||||
|
||||
InternalQuery::Close {
|
||||
handle,
|
||||
} => {
|
||||
for id in sv.windows.list() {
|
||||
if let Some(wnd) = sv.windows.get(id).cloned() {
|
||||
if wnd == handle.handle {
|
||||
sv.windows.remove(id).ok();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InternalQuery::Input {
|
||||
handle:_,
|
||||
} => {
|
||||
// Forward input data to system.
|
||||
}
|
||||
|
||||
InternalQuery::InputDeviceChange {
|
||||
state:_,
|
||||
handle:_,
|
||||
} => {
|
||||
println!("RECV DEVICECHANGE");
|
||||
|
||||
// Get new device information.
|
||||
}
|
||||
|
||||
InternalQuery::DeviceChange => {
|
||||
println!("RECV DISPLAYCHANGE");
|
||||
|
||||
// Get new display information.
|
||||
sv.display.enumerate();
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QueryData::Supervisor(query) => match query {
|
||||
SupervisorQuery::Status {
|
||||
system,
|
||||
channel
|
||||
} => match system {
|
||||
System::Input => {
|
||||
sv.input = channel;
|
||||
}
|
||||
|
||||
System::Video => {
|
||||
sv.video = channel;
|
||||
|
||||
// Prepare graphics context for each
|
||||
}
|
||||
|
||||
System::App => {
|
||||
sv.app = channel;
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
SupervisorQuery::Stop {
|
||||
system:_,
|
||||
} => {
|
||||
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
QueryData::Window(query) => match query {
|
||||
|
||||
// Forward thread-required queries.
|
||||
WindowQuery::Create { .. } => {
|
||||
if thread_sender.send(msg).is_ok() {
|
||||
if thread_sender.send(Query::new(None, QueryData::Window(query))).is_ok() {
|
||||
// Dispatch window message to allow receiving of query.
|
||||
unsafe {PostThreadMessageW(thread_id, WM_NULL, WPARAM(0), LPARAM(0))}.ok();
|
||||
} else {
|
||||
@ -249,88 +348,3 @@ impl Internal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn window_proc(
|
||||
hwnd:HWND,
|
||||
msg:u32,
|
||||
wparam:WPARAM,
|
||||
lparam:LPARAM,
|
||||
) -> LRESULT {
|
||||
if let Ok(sender) = WINPROC_SENDER.read() {
|
||||
if let Some(_sender) = sender.as_ref() {
|
||||
match msg {
|
||||
WM_MOVE => {
|
||||
|
||||
}
|
||||
|
||||
WM_SIZE => {
|
||||
|
||||
}
|
||||
|
||||
WM_INPUT => {
|
||||
//println!("INPUT");
|
||||
|
||||
let mut _rawinput_header = RAWINPUTHEADER::default();
|
||||
let header_size = std::mem::size_of::<RAWINPUTHEADER>() as u32;
|
||||
|
||||
let mut size = 0;
|
||||
let result = unsafe {GetRawInputData(
|
||||
HRAWINPUT(lparam.0 as _),
|
||||
RID_INPUT,
|
||||
None,
|
||||
&mut size,
|
||||
header_size,
|
||||
)};
|
||||
|
||||
if result == 0 && size > 0 {
|
||||
let mut buffer = vec![0u8; size as usize];
|
||||
|
||||
if unsafe {GetRawInputData(
|
||||
HRAWINPUT(lparam.0 as _),
|
||||
RID_INPUT,
|
||||
Some(buffer.as_mut_ptr() as *mut _),
|
||||
&mut size,
|
||||
header_size,
|
||||
)} > 0 {
|
||||
let raw_input :&RAWINPUT = &*(buffer.as_ptr() as *const RAWINPUT);
|
||||
|
||||
const TYPE_MOUSE :u32 = RIM_TYPEMOUSE.0;
|
||||
const TYPE_KEYBOARD :u32 = RIM_TYPEKEYBOARD.0;
|
||||
const TYPE_HID :u32 = RIM_TYPEHID.0;
|
||||
match raw_input.header.dwType {
|
||||
TYPE_MOUSE => {
|
||||
let _data = unsafe {raw_input.data.mouse};
|
||||
//sender.send(0).ok();
|
||||
}
|
||||
|
||||
TYPE_KEYBOARD => {
|
||||
let _data = unsafe {raw_input.data.keyboard};
|
||||
}
|
||||
|
||||
TYPE_HID => {
|
||||
let _data = unsafe {raw_input.data.hid};
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return LRESULT(0);
|
||||
}
|
||||
|
||||
WM_DEVICECHANGE => {
|
||||
println!("DEVICECHANGE");
|
||||
}
|
||||
|
||||
WM_DISPLAYCHANGE => {
|
||||
println!("DISPLAYCHANGE");
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
use windows::Win32::Graphics::Gdi::{
|
||||
EnumDisplayDevicesW,
|
||||
DISPLAY_DEVICEW,
|
||||
};
|
||||
|
||||
use pool::Pool;
|
||||
|
||||
pub struct Display {
|
||||
x:i32, y:i32,
|
||||
width:i32, height:i32,
|
||||
}
|
||||
|
||||
pub struct DisplayManager {
|
||||
displays:Pool<Display>,
|
||||
}
|
||||
impl DisplayManager {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
let mut this = Self {
|
||||
displays:Pool::new(),
|
||||
};
|
||||
|
||||
this.enumerate();
|
||||
this
|
||||
}
|
||||
|
||||
pub fn enumerate(&mut self)
|
||||
{
|
||||
let mut index = 0;
|
||||
let mut device = DISPLAY_DEVICEW::default();
|
||||
while unsafe {EnumDisplayDevicesW(None, index, &mut device, 1)}.into() {
|
||||
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,3 @@
|
||||
//use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
|
||||
|
||||
pub struct MonitorInfo {
|
||||
pub x:i32,
|
||||
pub y:i32,
|
||||
pub width:u32,
|
||||
pub height:u32,
|
||||
}
|
||||
|
||||
pub struct WindowLayout {
|
||||
pub x:i32,
|
||||
pub y:i32,
|
||||
@ -16,10 +7,10 @@ pub struct WindowLayout {
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
|
||||
name:String,
|
||||
windows:Vec<WindowLayout>,
|
||||
}
|
||||
|
||||
pub struct LayoutSystem {
|
||||
pub layouts:Vec<Layout>,
|
||||
pub monitors:Vec<MonitorInfo>,
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
use super::*;
|
||||
|
||||
mod query; pub use query::WindowQuery;
|
||||
mod windowhandle; pub use windowhandle::*;
|
||||
|
||||
mod query; pub use query::*;
|
||||
mod config; pub use config::WindowConfig;
|
||||
mod layout; pub use layout::*;
|
||||
mod winproc;
|
||||
mod display;
|
||||
mod internal; use internal::Internal;
|
||||
|
||||
pub struct WindowManager {
|
||||
channel:Sender<Query>,
|
||||
}
|
||||
|
||||
|
||||
impl WindowManager {
|
||||
pub fn create(&self, config:WindowConfig) -> Result<(),()>
|
||||
{
|
||||
|
@ -1,4 +1,36 @@
|
||||
use super::WindowConfig;
|
||||
use super::{WindowConfig, Layout, WindowHandle};
|
||||
|
||||
pub(crate) enum InternalQuery {
|
||||
None,
|
||||
Thread(u32),
|
||||
|
||||
Create {
|
||||
handle:WindowHandle,
|
||||
},
|
||||
Close {
|
||||
handle:WindowHandle,
|
||||
},
|
||||
|
||||
Move {
|
||||
handle:WindowHandle,
|
||||
},
|
||||
Resize {
|
||||
handle:WindowHandle,
|
||||
width:i32,
|
||||
height:i32,
|
||||
},
|
||||
|
||||
|
||||
Input {
|
||||
handle:WindowHandle,
|
||||
},
|
||||
|
||||
DeviceChange,
|
||||
InputDeviceChange {
|
||||
state:bool,
|
||||
handle:usize,
|
||||
},
|
||||
}
|
||||
|
||||
pub enum WindowQuery {
|
||||
None,
|
||||
@ -41,6 +73,10 @@ pub enum WindowQuery {
|
||||
Configure {
|
||||
id:usize,
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub enum LayoutQuery {
|
||||
Build {
|
||||
id:usize,
|
||||
},
|
||||
}
|
||||
|
13
src/system/window/windowhandle.rs
Normal file
13
src/system/window/windowhandle.rs
Normal file
@ -0,0 +1,13 @@
|
||||
pub type RawWindowHandle = windows::Win32::Foundation::HWND;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WindowHandle {
|
||||
pub handle:RawWindowHandle,
|
||||
}
|
||||
unsafe impl Send for WindowHandle { }
|
||||
impl From<RawWindowHandle> for WindowHandle {
|
||||
fn from(value: RawWindowHandle) -> Self
|
||||
{
|
||||
Self { handle:value }
|
||||
}
|
||||
}
|
166
src/system/window/winproc.rs
Normal file
166
src/system/window/winproc.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use crate::system::*;
|
||||
|
||||
use std::sync::RwLock;
|
||||
use windows::Win32::{
|
||||
Foundation::{
|
||||
HWND,
|
||||
LPARAM,
|
||||
LRESULT,
|
||||
WPARAM,
|
||||
},
|
||||
UI::{
|
||||
Input::{
|
||||
GetRawInputData,
|
||||
HRAWINPUT,
|
||||
RAWINPUT,
|
||||
RAWINPUTDEVICE,
|
||||
RAWINPUTHEADER,
|
||||
RID_INPUT,
|
||||
RIDEV_DEVNOTIFY,
|
||||
RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
|
||||
},
|
||||
WindowsAndMessaging::{
|
||||
DefWindowProcW,
|
||||
MSG,
|
||||
WM_MOVE, WM_SIZE, WM_CLOSE,
|
||||
WM_CAPTURECHANGED,
|
||||
|
||||
WM_INPUT, WM_INPUT_DEVICE_CHANGE,
|
||||
WM_DEVICECHANGE, WM_DISPLAYCHANGE,
|
||||
WM_NULL,
|
||||
},
|
||||
},
|
||||
System::Threading::GetCurrentThreadId,
|
||||
};
|
||||
|
||||
use super::InternalQuery;
|
||||
|
||||
pub static mut WINPROC_SENDER :RwLock<Option<(
|
||||
crossbeam::channel::Sender<Query>,
|
||||
crossbeam::channel::Sender<InternalQuery>
|
||||
)>> = RwLock::new(None);
|
||||
|
||||
pub unsafe extern "system" fn window_proc(
|
||||
hwnd:HWND,
|
||||
msg:u32,
|
||||
wparam:WPARAM,
|
||||
lparam:LPARAM,
|
||||
) -> LRESULT {
|
||||
if let Ok(sender) = WINPROC_SENDER.read() {
|
||||
if let Some((notify, sender)) = sender.as_ref() {
|
||||
match msg {
|
||||
WM_MOVE => {
|
||||
if sender.send(InternalQuery::Move {
|
||||
handle:hwnd.into(),
|
||||
}).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
WM_SIZE => {
|
||||
let width = lparam.0 as i32;
|
||||
let height = (lparam.0 >> 32) as i32;
|
||||
|
||||
if sender.send(InternalQuery::Resize {
|
||||
handle:hwnd.into(), width, height,
|
||||
}).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
WM_CLOSE => {
|
||||
if sender.send(InternalQuery::Close {
|
||||
handle:hwnd.into(),
|
||||
}).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WM_CAPTURECHANGED => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
WM_INPUT => {
|
||||
let mut _rawinput_header = RAWINPUTHEADER::default();
|
||||
let header_size = std::mem::size_of::<RAWINPUTHEADER>() as u32;
|
||||
|
||||
let mut size = 0;
|
||||
let result = unsafe {GetRawInputData(
|
||||
HRAWINPUT(lparam.0 as _),
|
||||
RID_INPUT,
|
||||
None,
|
||||
&mut size,
|
||||
header_size,
|
||||
)};
|
||||
|
||||
if result == 0 && size > 0 {
|
||||
let mut buffer = vec![0u8; size as usize];
|
||||
|
||||
if unsafe {GetRawInputData(
|
||||
HRAWINPUT(lparam.0 as _),
|
||||
RID_INPUT,
|
||||
Some(buffer.as_mut_ptr() as *mut _),
|
||||
&mut size,
|
||||
header_size,
|
||||
)} > 0 {
|
||||
let raw_input :&RAWINPUT = &*(buffer.as_ptr() as *const RAWINPUT);
|
||||
|
||||
let resp = InternalQuery::Input {
|
||||
handle:hwnd.into(),
|
||||
};
|
||||
|
||||
const TYPE_MOUSE :u32 = RIM_TYPEMOUSE.0;
|
||||
const TYPE_KEYBOARD :u32 = RIM_TYPEKEYBOARD.0;
|
||||
const TYPE_HID :u32 = RIM_TYPEHID.0;
|
||||
match raw_input.header.dwType {
|
||||
TYPE_MOUSE => {
|
||||
let _data = unsafe {raw_input.data.mouse};
|
||||
//sender.send(0).ok();
|
||||
}
|
||||
|
||||
TYPE_KEYBOARD => {
|
||||
let _data = unsafe {raw_input.data.keyboard};
|
||||
}
|
||||
|
||||
TYPE_HID => {
|
||||
let _data = unsafe {raw_input.data.hid};
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
if sender.send(resp).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LRESULT(0);
|
||||
}
|
||||
|
||||
WM_INPUT_DEVICE_CHANGE => {
|
||||
let state = wparam.0 == 1;
|
||||
let handle = lparam.0 as usize;
|
||||
|
||||
if sender.send(InternalQuery::InputDeviceChange {
|
||||
state,
|
||||
handle,
|
||||
}).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
WM_DEVICECHANGE | WM_DISPLAYCHANGE => {
|
||||
if sender.send(InternalQuery::DeviceChange).is_ok() {
|
||||
notify.send(Query::new(None, QueryData::Notify)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
}
|
Reference in New Issue
Block a user