aboutsummaryrefslogtreecommitdiffstats
path: root/src/win32/monitor.rs
blob: d53577e495fe71b49e87c8df4fdab357fc60e354 (plain)
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
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<MonitorID> {
    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::<ffi::DISPLAY_DEVICEW>() 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::<ffi::DEVMODE>() 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<String> {
        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
    }
}