]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/windows/display.cpp
Retrieve correct names for monitors on Windows
[libs/gui.git] / source / graphics / windows / display.cpp
1 #include "display.h"
2 #include "display_private.h"
3 #include <algorithm>
4 #include <windows.h>
5
6 using namespace std;
7
8 namespace Msp {
9 namespace Graphics {
10
11 Display::Display(const string &):
12         priv(new Private)
13 {
14         static ErrorDialog err_dlg(nullptr);
15
16         int primary_index = -1;
17         vector<unsigned> mode_monitor_indices;
18         vector<int> desktop_mode_indices;
19         for(unsigned i=0;; ++i)
20         {
21                 DISPLAY_DEVICE adapter_dev;
22                 adapter_dev.cb = sizeof(adapter_dev);
23                 if(!EnumDisplayDevices(nullptr, i, &adapter_dev, 0))
24                         break;
25
26                 if(adapter_dev.StateFlags&DISPLAY_DEVICE_MIRRORING_DRIVER)
27                         continue;
28
29                 monitors.push_back(Monitor());
30                 Monitor &monitor = monitors.back();
31                 monitor.index = monitors.size()-1;
32                 priv->monitors.push_back(adapter_dev.DeviceName);
33
34                 DISPLAY_DEVICE monitor_dev;
35                 monitor_dev.cb = sizeof(monitor_dev);
36                 if(EnumDisplayDevices(adapter_dev.DeviceName, 0, &monitor_dev, 0))
37                         monitor.name = monitor_dev.DeviceString;
38
39                 if(adapter_dev.StateFlags&DISPLAY_DEVICE_PRIMARY_DEVICE)
40                         primary_index = i;
41
42                 DEVMODE current;
43                 bool have_current = EnumDisplaySettings(adapter_dev.DeviceName, ENUM_CURRENT_SETTINGS, &current);
44
45                 unsigned first_mode = modes.size();
46                 int desktop_mode_index = -1;
47                 for(unsigned j=0;; ++j)
48                 {
49                         DEVMODE info;
50                         if(!EnumDisplaySettings(adapter_dev.DeviceName, j, &info))
51                                 break;
52
53                         if(any_of(modes.begin()+first_mode, modes.end(), [&info](const VideoMode &m){
54                                         return (m.width==info.dmPelsWidth && m.height==info.dmPelsHeight && m.rate==info.dmDisplayFrequency);
55                                 }))
56                                 continue;
57
58                         VideoMode mode(info.dmPelsWidth, info.dmPelsHeight);
59                         mode.index = modes.size();
60                         mode.rate = info.dmDisplayFrequency;
61
62                         modes.push_back(mode);
63                         mode_monitor_indices.push_back(monitor.index);
64
65                         if(have_current && info.dmPelsWidth==current.dmPelsWidth && info.dmPelsHeight==current.dmPelsHeight && info.dmDisplayFrequency==current.dmDisplayFrequency)
66                                 desktop_mode_index = mode.index;
67                 }
68                 desktop_mode_indices.push_back(desktop_mode_index);
69         }
70
71         for(unsigned i=0; i<monitors.size(); ++i)
72         {
73                 int j = desktop_mode_indices[i];
74                 if(j>=0)
75                         monitors[i].desktop_settings.mode = &modes[j];
76                 monitors[i].current_settings = monitors[i].desktop_settings;
77         }
78
79         for(unsigned i=0; i<modes.size(); ++i)
80         {
81                 Monitor &monitor = monitors[mode_monitor_indices[i]];
82                 modes[i].monitor = &monitor;
83                 monitor.video_modes.push_back(&modes[i]);
84         }
85
86         if(primary_index>=0)
87                 primary_monitor = &monitors[primary_index];
88 }
89
90 Display::~Display()
91 {
92         delete priv;
93 }
94
95 void Display::set_mode(const VideoMode &requested_mode, bool)
96 {
97         const VideoMode *mode = find_mode(requested_mode);
98         if(!mode)
99                 throw unsupported_video_mode(requested_mode);
100
101         DEVMODE info;
102         info.dmDeviceName[0] = 0;
103         info.dmSpecVersion = DM_SPECVERSION;
104         info.dmDriverVersion = 0;
105         info.dmSize = sizeof(DEVMODE);
106         info.dmDriverExtra = 0;
107         info.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT;
108         info.dmPelsWidth = mode->width;
109         info.dmPelsHeight = mode->height;
110         if(requested_mode.rate)
111         {
112                 info.dmFields |= DM_DISPLAYFREQUENCY;
113                 info.dmDisplayFrequency = mode->rate;
114         }
115
116         LONG ret = ChangeDisplaySettingsEx(priv->monitors[mode->monitor->index].c_str(), &info, NULL, CDS_FULLSCREEN, NULL);
117         if(ret!=DISP_CHANGE_SUCCESSFUL)
118                 throw unsupported_video_mode(requested_mode);
119
120         for(Monitor &m: monitors)
121                 if(&m==mode->monitor)
122                         m.current_settings.mode = mode;
123 }
124
125 bool Display::process_events()
126 {
127         MSG msg;
128         if(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
129         {
130                 TranslateMessage(&msg);
131                 DispatchMessage(&msg);
132                 return true;
133         }
134         else
135                 return false;
136 }
137
138 void Display::check_error()
139 {
140 }
141
142 } // namespace Msp
143 } // namespace Graphics