From d9d293667a7b5934ba923f578ffbfd2c12d121be Mon Sep 17 00:00:00 2001 From: Tomaka17 Date: Thu, 31 Jul 2014 10:52:05 +0200 Subject: Add monitor support for win32 --- src/lib.rs | 3 +- src/win32/ffi.rs | 47 ++++++++++++++++++++++++++++++- src/win32/mod.rs | 28 +++++++++++-------- src/win32/monitor.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/x11/mod.rs | 6 ++++ 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 src/win32/monitor.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index ab35774..953864a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,6 +258,7 @@ pub fn get_primary_monitor() -> MonitorID { impl MonitorID { /// Returns a human-readable name of the monitor. pub fn get_name(&self) -> Option { - Some("".to_string()) + let &MonitorID(ref id) = self; + id.get_name() } } diff --git a/src/win32/ffi.rs b/src/win32/ffi.rs index 268edbc..a217e20 100644 --- a/src/win32/ffi.rs +++ b/src/win32/ffi.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] #![allow(non_snake_case_functions)] #![allow(non_camel_case_types)] +#![allow(uppercase_variables)] use libc; @@ -135,6 +136,13 @@ pub static DISP_CHANGE_BADFLAGS: LONG = -4; pub static DISP_CHANGE_BADPARAM: LONG = -5; pub static DISP_CHANGE_BADDUALVIEW: LONG = -6; +// ? +pub static DISPLAY_DEVICE_ACTIVE: DWORD = 0x00000001; +pub static DISPLAY_DEVICE_MULTI_DRIVER: DWORD = 0x00000002; +pub static DISPLAY_DEVICE_PRIMARY_DEVICE: DWORD = 0x00000004; +pub static DISPLAY_DEVICE_MIRRORING_DRIVER: DWORD = 0x00000008; +pub static DISPLAY_DEVICE_VGA_COMPATIBLE: DWORD = 0x00000010; + // ? pub static DM_ORIENTATION: DWORD = 0x00000001; pub static DM_PAPERSIZE: DWORD = 0x00000002; @@ -167,6 +175,13 @@ pub static DM_PANNINGWIDTH: DWORD = 0x08000000; pub static DM_PANNINGHEIGHT: DWORD = 0x10000000; pub static DM_DISPLAYFIXEDOUTPUT: DWORD = 0x20000000; +// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx +pub static EDD_GET_DEVICE_INTERFACE_NAME: DWORD = 0x00000001; + +// ? +pub static ENUM_CURRENT_SETTINGS: DWORD = -1; +pub static ENUM_REGISTRY_SETTINGS: DWORD = -2; + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx pub static FORMAT_MESSAGE_ALLOCATE_BUFFER: DWORD = 0x00000100; pub static FORMAT_MESSAGE_ARGUMENT_ARRAY: DWORD = 0x00002000; @@ -520,6 +535,13 @@ pub struct PIXELFORMATDESCRIPTOR { pub dwDamageMask: DWORD, } +// http://msdn.microsoft.com/en-us/library/dd162807(v=vs.85).aspx +#[repr(C)] +pub struct POINTL { + pub x: LONG, + pub y: LONG, +} + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx #[repr(C)] pub struct DEVMODE { @@ -529,7 +551,7 @@ pub struct DEVMODE { pub dmSize: WORD, pub dmDriverExtra: WORD, pub dmFields: DWORD, - union1: [u8, ..16], + pub union1: [u8, ..16], pub dmColor: libc::c_short, pub dmDuplex: libc::c_short, pub dmYResolution: libc::c_short, @@ -563,6 +585,17 @@ pub struct WINDOWPLACEMENT { pub rcNormalPosition: RECT, } +// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183569(v=vs.85).aspx +#[repr(C)] +pub struct DISPLAY_DEVICEW { + pub cb: DWORD, + pub DeviceName: [WCHAR, ..32], + pub DeviceString: [WCHAR, ..128], + pub StateFlags: DWORD, + pub DeviceID: [WCHAR, ..128], + pub DeviceKey: [WCHAR, ..128], +} + pub type LPMSG = *mut MSG; #[link(name = "advapi32")] @@ -590,6 +623,10 @@ extern "system" { // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183411(v=vs.85).aspx pub fn ChangeDisplaySettingsW(lpDevMode: *mut DEVMODE, dwFlags: DWORD) -> LONG; + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413(v=vs.85).aspx + pub fn ChangeDisplaySettingsExW(lpszDeviceName: LPCWSTR, lpDevMode: *mut DEVMODE, hwnd: HWND, + dwFlags: DWORD, lParam: LPVOID) -> LONG; + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx pub fn CreateWindowExW(dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, x: libc::c_int, y: libc::c_int, nWidth: libc::c_int, nHeight: libc::c_int, @@ -611,6 +648,14 @@ extern "system" { // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162598(v=vs.85).aspx pub fn EndPaint(hWnd: HWND, lpPaint: *const PAINTSTRUCT) -> BOOL; + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx + pub fn EnumDisplayDevicesW(lpDevice: LPCWSTR, iDevNum: DWORD, + lpDisplayDevice: *mut DISPLAY_DEVICEW, dwFlags: DWORD) -> BOOL; + + // http://msdn.microsoft.com/en-us/library/dd162612(v=vs.85).aspx + pub fn EnumDisplaySettingsExW(lpszDeviceName: LPCWSTR, iModeNum: DWORD, + lpDevMode: *mut DEVMODE, dwFlags: DWORD) -> BOOL; + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162719(v=vs.85).aspx pub fn FillRect(hDC: HDC, lprc: *const RECT, hbr: HBRUSH) -> libc::c_int; diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 232f0e5..0cb8ac9 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -4,8 +4,11 @@ use std::sync::atomics::AtomicBool; use std::ptr; use {Event, Hints}; +pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; + mod event; mod ffi; +mod monitor; pub struct Window { window: ffi::HWND, @@ -17,16 +20,6 @@ pub struct Window { nosend: NoSend, } -pub struct MonitorID(uint); - -pub fn get_available_monitors() -> Vec { - unimplemented!() -} - -pub fn get_primary_monitor() -> MonitorID { - unimplemented!() -} - /// Stores the list of all the windows. /// Only available on callback thread. local_data_key!(pub WINDOWS_LIST: Mutex)>>) @@ -78,6 +71,18 @@ impl Window { // switching to fullscreen if monitor.is_some() { + let monitor = monitor.as_ref().unwrap(); + + // adjusting the rect + { + let pos = monitor.get_position(); + rect.left += pos.val0() as ffi::LONG; + rect.right += pos.val0() as ffi::LONG; + rect.top += pos.val1() as ffi::LONG; + rect.bottom += pos.val1() as ffi::LONG; + } + + // changing device settings let mut screen_settings: ffi::DEVMODE = unsafe { mem::zeroed() }; screen_settings.dmSize = mem::size_of::() as ffi::WORD; screen_settings.dmPelsWidth = 1024; @@ -85,7 +90,8 @@ impl Window { screen_settings.dmBitsPerPel = 32; screen_settings.dmFields = ffi::DM_BITSPERPEL | ffi::DM_PELSWIDTH | ffi::DM_PELSHEIGHT; - let result = unsafe { ffi::ChangeDisplaySettingsW(&mut screen_settings, ffi::CDS_FULLSCREEN) }; + let result = unsafe { ffi::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(), + &mut screen_settings, ptr::mut_null(), ffi::CDS_FULLSCREEN, ptr::mut_null()) }; if result != ffi::DISP_CHANGE_SUCCESSFUL { return Err(format!("ChangeDisplaySettings failed: {}", result)) } diff --git a/src/win32/monitor.rs b/src/win32/monitor.rs new file mode 100644 index 0000000..d53577e --- /dev/null +++ b/src/win32/monitor.rs @@ -0,0 +1,79 @@ +use super::ffi; + +pub struct MonitorID { + name: [ffi::WCHAR, ..32], + readable_name: String, + flags: ffi::DWORD, + position: (uint, uint), +} + +pub fn get_available_monitors() -> Vec { + use std::{iter, mem, ptr}; + + let mut result = Vec::new(); + + for id in iter::count(0u, 1) { + let mut output: ffi::DISPLAY_DEVICEW = unsafe { mem::zeroed() }; + output.cb = mem::size_of::() as ffi::DWORD; + + if unsafe { ffi::EnumDisplayDevicesW(ptr::null(), id as ffi::DWORD, &mut output, 0) } == 0 { + break + } + + if (output.StateFlags & ffi::DISPLAY_DEVICE_ACTIVE) == 0 || + (output.StateFlags & ffi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0 + { + continue + } + + let readable_name = String::from_utf16_lossy(output.DeviceString.as_slice()); + let readable_name = readable_name.as_slice().trim_right_chars(0 as char).to_string(); + + let position = unsafe { + let mut dev: ffi::DEVMODE = mem::zeroed(); + dev.dmSize = mem::size_of::() as ffi::WORD; + + if ffi::EnumDisplaySettingsExW(output.DeviceName.as_ptr(), ffi::ENUM_CURRENT_SETTINGS, + &mut dev, 0) == 0 + { + continue + } + + let point: &ffi::POINTL = mem::transmute(&dev.union1); + (point.x as uint, point.y as uint) + }; + + result.push(MonitorID { + name: output.DeviceName, + readable_name: readable_name, + flags: output.StateFlags, + position: position, + }); + } + + result +} + +pub fn get_primary_monitor() -> MonitorID { + for monitor in get_available_monitors().move_iter() { + if (monitor.flags & ffi::DISPLAY_DEVICE_PRIMARY_DEVICE) != 0 { + return monitor + } + } + + fail!("Failed to find the primary monitor") +} + +impl MonitorID { + pub fn get_name(&self) -> Option { + Some(self.readable_name.clone()) + } + + pub fn get_system_name(&self) -> &[ffi::WCHAR] { + self.name.as_slice() + } + + pub fn get_position(&self) -> (uint, uint) { + self.position + } +} diff --git a/src/x11/mod.rs b/src/x11/mod.rs index 9d08d4a..61488a1 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -24,6 +24,12 @@ pub fn get_primary_monitor() -> MonitorID { unimplemented!() } +impl MonitorID { + pub fn get_name(&self) -> Option { + Some("".to_string()) + } +} + impl Window { pub fn new(dimensions: Option<(uint, uint)>, title: &str, hints: &Hints, _: Option) -> Result -- cgit v1.2.3