From cdf7bfaf78b052f1e05c8cb48937db58dcd3c9e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Aug 2018 23:17:36 -0700 Subject: [PATCH] Initial code push --- .gitignore | 2 + Cargo.lock | 30 ++++++++++ Cargo.toml | 7 +++ src/main.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..bc8dc87 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,30 @@ +[[package]] +name = "display_off" +version = "0.1.0" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ab8ea40 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "display_off" +version = "0.1.0" +authors = ["Manvir "] + +[dependencies] +winapi = { version = "0.3", features = ["lowlevelmonitorconfigurationapi", "winuser", "libloaderapi"] } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..be1ed2b --- /dev/null +++ b/src/main.rs @@ -0,0 +1,157 @@ +#![windows_subsystem = "windows"] // Hides console window +extern crate winapi; + +use std::mem; +use std::ptr::null_mut; + +use winapi::ctypes::c_void; +use winapi::um::libloaderapi::GetModuleHandleW; +use winapi::shared::windef::{HMONITOR, HDC, LPRECT, HWND}; +use winapi::um::lowlevelmonitorconfigurationapi::SetVCPFeature; +use winapi::um::winuser::{GetMessageW, + RegisterClassW, DefWindowProcW, CreateWindowExW, + TranslateMessage, DispatchMessageW, EnumDisplayMonitors, + CS_VREDRAW, CS_HREDRAW, MSG, CS_OWNDC, WNDCLASSW, WM_QUERYENDSESSION}; +use winapi::um::physicalmonitorenumerationapi::{GetPhysicalMonitorsFromHMONITOR, PHYSICAL_MONITOR}; + +// Power states +enum Power { + On = 0x01, + Standby = 0x02, + Suspend = 0x03, + Off = 0x04, + HardOff = 0x05 +} + +static mut DISPLAY_LIST: Option> = None; + +fn win32_string(str : &str) -> Vec { + let mut vec: Vec = str.encode_utf16().collect(); + vec.push(0); + vec +} + +/* +* Sets the power state of `display_handle` to `state` +*/ +fn set_power_state(display_handle: *mut c_void, state: Power) -> bool { + if unsafe { SetVCPFeature(display_handle, 0xD6, state as u32)} == 0 { return false; } + true +} + +/* +* Returns a `Vec<*mut c_void>` containing display handles pointing to +* there respective displays. +*/ +fn get_display_handles() -> Vec<*mut c_void> { + let mut display_list: Vec<*mut c_void> = Vec::<*mut c_void>::new(); + let display_list_ptr: isize = &mut display_list as *mut _ as isize; + + unsafe { + EnumDisplayMonitors(null_mut(), null_mut(), Some(monitor_enum_proc), display_list_ptr); + } + + display_list.shrink_to_fit(); + display_list +} + +/* +* Calls `set_power_state` for every display handle in `display_list` +* setting the power state to `Power::HardOff`. +*/ +fn poweroff_displays(display_list: Vec<*mut c_void>) { + for display in display_list { + set_power_state(display, Power::HardOff); + }; +} + +/* +* Main window loop +*/ +fn run_loop(window: HWND) { + unsafe { + let mut message: MSG = mem::uninitialized(); + while GetMessageW(&mut message as *mut MSG, window, 0, 0) == 1 { + TranslateMessage(&message as *const MSG); + DispatchMessageW(&message as *const MSG); + } + } +} + +/* +* A message only widnow used to receive a shutdown event +*/ +fn create_window() -> HWND { + let name = win32_string("dummy_class"); + let title = win32_string("ddc"); + let instance = unsafe { GetModuleHandleW(null_mut()) }; + + unsafe { + let wnd_class = WNDCLASSW { + style : CS_OWNDC | CS_HREDRAW | CS_VREDRAW, + lpfnWndProc : Some(win_proc), + hInstance : instance, + lpszClassName : name.as_ptr(), + cbClsExtra : 0, + cbWndExtra : 0, + hIcon: null_mut(), + hCursor: null_mut(), + hbrBackground: null_mut(), + lpszMenuName: null_mut(), + }; + + RegisterClassW(&wnd_class); + + CreateWindowExW(0, name.as_ptr(), title.as_ptr(), 0, 0, 0, 0, 0, null_mut(), null_mut(), instance, null_mut()) + } +} + +/* +* Called by the windows api for every display +*/ +unsafe extern "system" fn monitor_enum_proc(h_monitor: HMONITOR, _: HDC, _: LPRECT, data: isize) -> i32 { + let display_list: &mut Vec<*mut c_void> = &mut *(data as *mut Vec<*mut c_void>); + + let mut temp_mon: Vec = Vec::with_capacity(1); + temp_mon.push(PHYSICAL_MONITOR{ + hPhysicalMonitor: null_mut(), + szPhysicalMonitorDescription: [0_u16; 128] + }); + + GetPhysicalMonitorsFromHMONITOR(h_monitor, 1, temp_mon.as_mut_ptr()); + + for monitor in temp_mon { + display_list.push(monitor.hPhysicalMonitor); + } + + /* + * Will `display_list` be droped if `mem::forget` is'nt called? + * `display_list` lives outside this function in `main()`, passed + * as a pointer to this function. + */ + mem::forget(display_list); + + 1 +} + +/* +* Recives window messages. We only care about `WM_QUERYENDSESSION` as its the widnows shutdown event +*/ +unsafe extern "system" fn win_proc(hwnd: HWND, msg: u32, w_param: usize, l_param: isize) -> isize { + match msg { + WM_QUERYENDSESSION => { + let display_list: Vec<*mut c_void> = DISPLAY_LIST.clone().unwrap(); + poweroff_displays(display_list); + }, + _ => (), + }; + DefWindowProcW(hwnd, msg, w_param, l_param) +} + +fn main() { + let display_handles: Vec<*mut c_void> = get_display_handles(); + unsafe { DISPLAY_LIST = Some(display_handles) }; + + let window = create_window(); + run_loop(window); +}