3e801c25cef7e82fe882054f98d2b4bf2d7f67ce
[vuplus_xbmc] / xbmc / windowing / windows / WinSystemWin32.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "WinSystemWin32.h"
22 #include "WinEventsWin32.h"
23 #include "resource.h"
24 #include "guilib/gui3d.h"
25 #include "settings/AdvancedSettings.h"
26 #include "settings/DisplaySettings.h"
27 #include "settings/Settings.h"
28 #include "utils/log.h"
29
30 #ifdef TARGET_WINDOWS
31 #include <tpcshrd.h>
32
33 CWinSystemWin32::CWinSystemWin32()
34 : CWinSystemBase()
35 {
36   m_eWindowSystem = WINDOW_SYSTEM_WIN32;
37   m_hWnd = NULL;
38   m_hInstance = NULL;
39   m_hIcon = NULL;
40   m_hDC = NULL;
41   m_nPrimary = 0;
42   PtrCloseGestureInfoHandle = NULL;
43   PtrSetGestureConfig = NULL;
44   PtrGetGestureInfo = NULL;
45   m_ValidWindowedPosition = false;
46   m_IsAlteringWindow = false;
47 }
48
49 CWinSystemWin32::~CWinSystemWin32()
50 {
51   if (m_hIcon)
52   {
53     DestroyIcon(m_hIcon);
54     m_hIcon = NULL;
55   }
56 };
57
58 bool CWinSystemWin32::InitWindowSystem()
59 {
60   if(!CWinSystemBase::InitWindowSystem())
61     return false;
62
63   if(m_MonitorsInfo.size() < 1)
64   {
65     CLog::Log(LOGERROR, "%s - no suitable monitor found, aborting...", __FUNCTION__);
66     return false;
67   }
68
69   return true;
70 }
71
72 bool CWinSystemWin32::DestroyWindowSystem()
73 {
74   RestoreDesktopResolution(m_nScreen);
75   return true;
76 }
77
78 bool CWinSystemWin32::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
79 {
80   m_hInstance = ( HINSTANCE )GetModuleHandle( NULL );
81
82   m_nWidth  = res.iWidth;
83   m_nHeight = res.iHeight;
84   m_bFullScreen = fullScreen;
85   m_nScreen = res.iScreen;
86
87   m_hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));
88
89   // Register the windows class
90   WNDCLASS wndClass;
91   wndClass.style = CS_OWNDC; // For OpenGL
92   wndClass.lpfnWndProc = CWinEvents::WndProc;
93   wndClass.cbClsExtra = 0;
94   wndClass.cbWndExtra = 0;
95   wndClass.hInstance = m_hInstance;
96   wndClass.hIcon = m_hIcon;
97   wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
98   wndClass.hbrBackground = ( HBRUSH )GetStockObject( BLACK_BRUSH );
99   wndClass.lpszMenuName = NULL;
100   wndClass.lpszClassName = name.c_str();
101
102   if( !RegisterClass( &wndClass ) )
103   {
104     return false;
105   }
106
107   HWND hWnd = CreateWindow( name.c_str(), name.c_str(), fullScreen ? WS_POPUP : WS_OVERLAPPEDWINDOW,
108     0, 0, m_nWidth, m_nHeight, 0,
109     NULL, m_hInstance, userFunction );
110   if( hWnd == NULL )
111   {
112     return false;
113   }
114
115   const DWORD dwHwndTabletProperty =
116       TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down (circle)
117       TABLET_DISABLE_FLICKS; // disables pen flicks (back, forward, drag down, drag up)
118
119   SetProp(hWnd, MICROSOFT_TABLETPENSERVICE_PROPERTY, reinterpret_cast<HANDLE>(dwHwndTabletProperty));
120
121   // setup our touch pointers
122   HMODULE hUser32 = GetModuleHandleA( "user32" );
123   if (hUser32)
124   {
125     PtrGetGestureInfo = (pGetGestureInfo) GetProcAddress( hUser32, "GetGestureInfo" );
126     PtrSetGestureConfig = (pSetGestureConfig) GetProcAddress( hUser32, "SetGestureConfig" );
127     PtrCloseGestureInfoHandle = (pCloseGestureInfoHandle) GetProcAddress( hUser32, "CloseGestureInfoHandle" );
128   }
129
130   m_hWnd = hWnd;
131   m_hDC = GetDC(m_hWnd);
132
133   m_bWindowCreated = true;
134
135   CreateBlankWindows();
136
137   ResizeInternal(true);
138
139   // Show the window
140   ShowWindow( m_hWnd, SW_SHOWDEFAULT );
141   UpdateWindow( m_hWnd );
142
143   return true;
144 }
145
146 bool CWinSystemWin32::CreateBlankWindows()
147 {
148   WNDCLASSEX wcex;
149
150   wcex.cbSize = sizeof(WNDCLASSEX);
151   wcex.style= CS_HREDRAW | CS_VREDRAW;
152   wcex.lpfnWndProc= DefWindowProc;
153   wcex.cbClsExtra= 0;
154   wcex.cbWndExtra= 0;
155   wcex.hInstance= NULL;
156   wcex.hIcon= 0;
157   wcex.hCursor= NULL;
158   wcex.hbrBackground= (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
159   wcex.lpszMenuName= 0;
160   wcex.lpszClassName= "BlankWindowClass";
161   wcex.hIconSm= 0;
162
163   // Now we can go ahead and register our new window class
164   int reg = RegisterClassEx(&wcex);
165
166   // We need as many blank windows as there are screens (minus 1)
167   int BlankWindowsCount = m_MonitorsInfo.size() -1;
168
169   for (int i=0; i < BlankWindowsCount; i++)
170   {
171     HWND hBlankWindow = CreateWindowEx(WS_EX_TOPMOST, "BlankWindowClass", "", WS_POPUP | WS_DISABLED,
172     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
173
174     if(hBlankWindow ==  NULL)
175       return false;
176
177     m_hBlankWindows.push_back(hBlankWindow);
178   }
179
180   return true;
181 }
182
183 bool CWinSystemWin32::BlankNonActiveMonitors(bool bBlank)
184 {
185   if(m_hBlankWindows.size() == 0)
186     return false;
187
188   if(bBlank == false)
189   {
190     for (unsigned int i=0; i < m_hBlankWindows.size(); i++)
191       ShowWindow(m_hBlankWindows[i], SW_HIDE);
192     return true;
193   }
194
195   // Move a blank window in front of every screen, except the current XBMC screen.
196   int screen = 0;
197   if (screen == m_nScreen)
198     screen++;
199
200   for (unsigned int i=0; i < m_hBlankWindows.size(); i++)
201   {
202     RECT rBounds = ScreenRect(screen);
203     // move and resize the window
204     SetWindowPos(m_hBlankWindows[i], NULL, rBounds.left, rBounds.top,
205       rBounds.right - rBounds.left, rBounds.bottom - rBounds.top,
206       SWP_NOACTIVATE);
207
208     ShowWindow(m_hBlankWindows[i], SW_SHOW | SW_SHOWNOACTIVATE);
209
210     screen++;
211     if (screen == m_nScreen)
212       screen++;
213   }
214
215   if(m_hWnd)
216     SetForegroundWindow(m_hWnd);
217
218   return true;
219 }
220
221 bool CWinSystemWin32::CenterWindow()
222 {
223   RESOLUTION_INFO DesktopRes = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP);
224
225   m_nLeft = (DesktopRes.iWidth / 2) - (m_nWidth / 2);
226   m_nTop = (DesktopRes.iHeight / 2) - (m_nHeight / 2);
227
228   RECT rc;
229   rc.left = m_nLeft;
230   rc.top = m_nTop;
231   rc.right = rc.left + m_nWidth;
232   rc.bottom = rc.top + m_nHeight;
233   AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, false );
234
235   SetWindowPos(m_hWnd, 0, rc.left, rc.top, 0, 0, SWP_NOSIZE);
236
237   return true;
238 }
239
240 bool CWinSystemWin32::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
241 {
242   m_nWidth = newWidth;
243   m_nHeight = newHeight;
244
245   if(newLeft > 0)
246     m_nLeft = newLeft;
247
248   if(newTop > 0)
249     m_nTop = newTop;
250
251   ResizeInternal();
252
253   return true;
254 }
255
256 void CWinSystemWin32::NotifyAppFocusChange(bool bGaining)
257 {
258   if (m_bFullScreen && bGaining) //bump ourselves to top
259     SetWindowPos(m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
260 }
261
262 bool CWinSystemWin32::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
263 {
264   m_IsAlteringWindow = true;
265
266   CLog::Log(LOGDEBUG, "%s (%s) on screen %d with size %dx%d, refresh %f%s", __FUNCTION__, !fullScreen ? "windowed" : (CSettings::Get().GetBool("videoscreen.fakefullscreen") ? "windowed fullscreen" : "true fullscreen"), res.iScreen, res.iWidth, res.iHeight, res.fRefreshRate, (res.dwFlags & D3DPRESENTFLAG_INTERLACED) ? "i" : "");
267
268   bool forceResize = false;
269
270   if (m_nScreen != res.iScreen)
271   {
272     forceResize = true;
273     RestoreDesktopResolution(m_nScreen);
274   }
275
276   if(m_hWnd && !m_bFullScreen && fullScreen)
277   {
278     // save position of windowed mode
279     WINDOWINFO wi;
280     wi.cbSize = sizeof(WINDOWINFO);
281     GetWindowInfo(m_hWnd, &wi);
282     m_nLeft = wi.rcClient.left;
283     m_nTop = wi.rcClient.top;
284     m_ValidWindowedPosition = true;
285   }
286
287   m_bFullScreen = fullScreen;
288   m_nScreen = res.iScreen;
289   m_nWidth  = res.iWidth;
290   m_nHeight = res.iHeight;
291   m_bBlankOtherDisplay = blankOtherDisplays;
292
293   if (fullScreen && CSettings::Get().GetBool("videoscreen.fakefullscreen"))
294     ChangeResolution(res);
295
296   ResizeInternal(forceResize);
297
298   BlankNonActiveMonitors(m_bBlankOtherDisplay);
299
300   m_IsAlteringWindow = false;
301
302   return true;
303 }
304
305 void CWinSystemWin32::RestoreDesktopResolution(int screen)
306 {
307   int resIdx = RES_DESKTOP;
308   for (int idx = RES_DESKTOP; idx < RES_DESKTOP + GetNumScreens(); idx++)
309   {
310     if (CDisplaySettings::Get().GetResolutionInfo(idx).iScreen == screen)
311     {
312       resIdx = idx;
313       break;
314     }
315   }
316   ChangeResolution(CDisplaySettings::Get().GetResolutionInfo(resIdx));
317 }
318
319 const MONITOR_DETAILS &CWinSystemWin32::GetMonitor(int screen) const
320 {
321   for (unsigned int monitor = 0; monitor < m_MonitorsInfo.size(); monitor++)
322     if (m_MonitorsInfo[monitor].ScreenNumber == screen)
323       return m_MonitorsInfo[monitor];
324
325   // What to do if monitor is not found? Not sure... use the primary screen as a default value.
326   return m_MonitorsInfo[m_nPrimary];
327 }
328
329 int CWinSystemWin32::GetCurrentScreen()
330 {
331   HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY);
332   for (unsigned int monitor = 0; monitor < m_MonitorsInfo.size(); monitor++)
333     if (m_MonitorsInfo[monitor].hMonitor == hMonitor)
334       return m_MonitorsInfo[monitor].ScreenNumber;
335   // primary as fallback - v. strange if this ever happens
336   return 0;
337 }
338
339 RECT CWinSystemWin32::ScreenRect(int screen)
340 {
341   const MONITOR_DETAILS &details = GetMonitor(screen);
342
343   DEVMODE sDevMode;
344   ZeroMemory(&sDevMode, sizeof(DEVMODE));
345   sDevMode.dmSize = sizeof(DEVMODE);
346   EnumDisplaySettings(details.DeviceName, ENUM_CURRENT_SETTINGS, &sDevMode);
347
348   RECT rc;
349   rc.left = sDevMode.dmPosition.x;
350   rc.right = sDevMode.dmPosition.x + sDevMode.dmPelsWidth;
351   rc.top = sDevMode.dmPosition.y;
352   rc.bottom = sDevMode.dmPosition.y + sDevMode.dmPelsHeight;
353
354   return rc;
355 }
356
357 bool CWinSystemWin32::ResizeInternal(bool forceRefresh)
358 {
359   if (m_hWnd == NULL)
360     return false;
361   DWORD dwStyle = WS_CLIPCHILDREN;
362   HWND windowAfter;
363   RECT rc;
364
365   if(m_bFullScreen)
366   {
367     dwStyle |= WS_POPUP;
368     windowAfter = HWND_TOP;
369     rc = ScreenRect(m_nScreen);
370   }
371   else
372   {
373     dwStyle |= WS_OVERLAPPEDWINDOW;
374     windowAfter = g_advancedSettings.m_alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST;
375
376     rc.left = m_nLeft;
377     rc.right = m_nLeft + m_nWidth;
378     rc.top = m_nTop;
379     rc.bottom = m_nTop + m_nHeight;
380
381     HMONITOR hMon = MonitorFromRect(&rc, MONITOR_DEFAULTTONULL);
382     HMONITOR hMon2 = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY);
383
384     // hasn't been windowed yet, or windowed position would not fullscreen to the same screen we were fullscreen on?
385     // -> center on the screen that we were fullscreen on
386     if(!m_ValidWindowedPosition || hMon == NULL || hMon != hMon2)
387     {
388       RECT newScreenRect = ScreenRect(GetCurrentScreen());
389       rc.left = m_nLeft = newScreenRect.left + ((newScreenRect.right - newScreenRect.left) / 2) - (m_nWidth / 2);
390       rc.top  = m_nTop  =  newScreenRect.top + ((newScreenRect.bottom - newScreenRect.top) / 2) - (m_nHeight / 2);
391       rc.right = m_nLeft + m_nWidth;
392       rc.bottom = m_nTop + m_nHeight;
393     }
394
395     AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, false );
396   }
397
398   WINDOWINFO wi;
399   wi.cbSize = sizeof (WINDOWINFO);
400   GetWindowInfo(m_hWnd, &wi);
401   RECT wr = wi.rcWindow;
402
403   if (forceRefresh || wr.bottom  - wr.top != rc.bottom - rc.top || wr.right - wr.left != rc.right - rc.left ||
404                      (wi.dwStyle & WS_CAPTION) != (dwStyle & WS_CAPTION))
405   {
406     CLog::Log(LOGDEBUG, "%s - resizing due to size change (%d,%d,%d,%d%s)->(%d,%d,%d,%d%s)",__FUNCTION__,wr.left, wr.top, wr.right, wr.bottom, (wi.dwStyle & WS_CAPTION) ? "" : " fullscreen",
407                                                                                                          rc.left, rc.top, rc.right, rc.bottom, (dwStyle & WS_CAPTION) ? "" : " fullscreen");
408     SetWindowRgn(m_hWnd, 0, false);
409     SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
410
411     // The SWP_DRAWFRAME is here because, perversely, without it win7 draws a
412     // white frame plus titlebar around the xbmc splash
413     SetWindowPos(m_hWnd, windowAfter, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW|SWP_DRAWFRAME);
414
415     // TODO: Probably only need this if switching screens
416     ValidateRect(NULL, NULL);
417   }
418   return true;
419 }
420
421 bool CWinSystemWin32::ChangeResolution(RESOLUTION_INFO res)
422 {
423   const MONITOR_DETAILS &details = GetMonitor(res.iScreen);
424
425   DEVMODE sDevMode;
426   ZeroMemory(&sDevMode, sizeof(DEVMODE));
427   sDevMode.dmSize = sizeof(DEVMODE);
428
429   // If we can't read the current resolution or any detail of the resolution is different than res
430   if (!EnumDisplaySettings(details.DeviceName, ENUM_CURRENT_SETTINGS, &sDevMode) ||
431       sDevMode.dmPelsWidth != res.iWidth || sDevMode.dmPelsHeight != res.iHeight ||
432       sDevMode.dmDisplayFrequency != (int)res.fRefreshRate ||
433       ((sDevMode.dmDisplayFlags & DM_INTERLACED) && !(res.dwFlags & D3DPRESENTFLAG_INTERLACED)) ||
434       (!(sDevMode.dmDisplayFlags & DM_INTERLACED) && (res.dwFlags & D3DPRESENTFLAG_INTERLACED)) )
435   {
436     ZeroMemory(&sDevMode, sizeof(DEVMODE));
437     sDevMode.dmSize = sizeof(DEVMODE);
438     sDevMode.dmDriverExtra = 0;
439     sDevMode.dmPelsWidth = res.iWidth;
440     sDevMode.dmPelsHeight = res.iHeight;
441     sDevMode.dmDisplayFrequency = (int)res.fRefreshRate;
442     sDevMode.dmDisplayFlags = (res.dwFlags & D3DPRESENTFLAG_INTERLACED) ? DM_INTERLACED : 0;
443     sDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
444
445     // CDS_FULLSCREEN is for temporary fullscreen mode and prevents icons and windows from moving
446     // to fit within the new dimensions of the desktop
447     LONG rc = ChangeDisplaySettingsEx(details.DeviceName, &sDevMode, NULL, CDS_FULLSCREEN, NULL);
448     if (rc != DISP_CHANGE_SUCCESSFUL)
449     {
450       CLog::Log(LOGERROR, "%s: error, code %d", __FUNCTION__, rc);
451       return false;
452     }
453     else
454     {
455       return true;
456     }
457   }
458   // nothing to do, return success
459   return true;
460 }
461
462
463 void CWinSystemWin32::UpdateResolutions()
464 {
465
466   CWinSystemBase::UpdateResolutions();
467
468   UpdateResolutionsInternal();
469
470   if(m_MonitorsInfo.size() < 1)
471     return;
472
473   float refreshRate = 0;
474   int w = 0;
475   int h = 0;
476   uint32_t dwFlags;
477
478   // Primary
479   m_MonitorsInfo[m_nPrimary].ScreenNumber = 0;
480   w = m_MonitorsInfo[m_nPrimary].ScreenWidth;
481   h = m_MonitorsInfo[m_nPrimary].ScreenHeight;
482   if( (m_MonitorsInfo[m_nPrimary].RefreshRate == 59) || (m_MonitorsInfo[m_nPrimary].RefreshRate == 29) || (m_MonitorsInfo[m_nPrimary].RefreshRate == 23) )
483     refreshRate = (float)(m_MonitorsInfo[m_nPrimary].RefreshRate + 1) / 1.001f;
484   else
485     refreshRate = (float)m_MonitorsInfo[m_nPrimary].RefreshRate;
486   dwFlags = m_MonitorsInfo[m_nPrimary].Interlaced ? D3DPRESENTFLAG_INTERLACED : 0;
487
488   UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, refreshRate, dwFlags);
489   CLog::Log(LOGNOTICE, "Primary mode: %s", CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strMode.c_str());
490
491   // Desktop resolution of the other screens
492   if(m_MonitorsInfo.size() >= 2)
493   {
494     int xbmcmonitor = 1;  // The screen number+1 showed in the GUI display settings
495
496     for (unsigned int monitor = 0; monitor < m_MonitorsInfo.size(); monitor++)
497     {
498       if (monitor != m_nPrimary)
499       {
500         m_MonitorsInfo[monitor].ScreenNumber = xbmcmonitor;
501         w = m_MonitorsInfo[monitor].ScreenWidth;
502         h = m_MonitorsInfo[monitor].ScreenHeight;
503         if( (m_MonitorsInfo[monitor].RefreshRate == 59) || (m_MonitorsInfo[monitor].RefreshRate == 29) || (m_MonitorsInfo[monitor].RefreshRate == 23) )
504           refreshRate = (float)(m_MonitorsInfo[monitor].RefreshRate + 1) / 1.001f;
505         else
506           refreshRate = (float)m_MonitorsInfo[monitor].RefreshRate;
507         dwFlags = m_MonitorsInfo[monitor].Interlaced ? D3DPRESENTFLAG_INTERLACED : 0;
508
509         RESOLUTION_INFO res;
510         UpdateDesktopResolution(res, xbmcmonitor++, w, h, refreshRate, dwFlags);
511         CDisplaySettings::Get().AddResolutionInfo(res);
512         CLog::Log(LOGNOTICE, "Secondary mode: %s", res.strMode.c_str());
513       }
514     }
515   }
516
517   // The rest of the resolutions. The order is not important.
518   for (unsigned int monitor = 0; monitor < m_MonitorsInfo.size(); monitor++)
519   {
520     for(int mode = 0;; mode++)
521     {
522       DEVMODE devmode;
523       ZeroMemory(&devmode, sizeof(devmode));
524       devmode.dmSize = sizeof(devmode);
525       if(EnumDisplaySettings(m_MonitorsInfo[monitor].DeviceName, mode, &devmode) == 0)
526         break;
527       if(devmode.dmBitsPerPel != 32)
528         continue;
529
530       float refreshRate;
531       if(devmode.dmDisplayFrequency == 59 || devmode.dmDisplayFrequency == 29 || devmode.dmDisplayFrequency == 23)
532         refreshRate = (float)(devmode.dmDisplayFrequency + 1) / 1.001f;
533       else
534         refreshRate = (float)(devmode.dmDisplayFrequency);
535       dwFlags = (devmode.dmDisplayFlags & DM_INTERLACED) ? D3DPRESENTFLAG_INTERLACED : 0;
536
537       RESOLUTION_INFO res;
538       UpdateDesktopResolution(res, m_MonitorsInfo[monitor].ScreenNumber, devmode.dmPelsWidth, devmode.dmPelsHeight, refreshRate, dwFlags);
539       AddResolution(res);
540       CLog::Log(LOGNOTICE, "Additional mode: %s", res.strMode.c_str());
541     }
542   }
543 }
544
545 void CWinSystemWin32::AddResolution(const RESOLUTION_INFO &res)
546 {
547   for (unsigned int i = 0; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
548   {
549     if (CDisplaySettings::Get().GetResolutionInfo(i).iScreen      == res.iScreen &&
550         CDisplaySettings::Get().GetResolutionInfo(i).iWidth       == res.iWidth &&
551         CDisplaySettings::Get().GetResolutionInfo(i).iHeight      == res.iHeight &&
552         CDisplaySettings::Get().GetResolutionInfo(i).iScreenWidth == res.iScreenWidth &&
553         CDisplaySettings::Get().GetResolutionInfo(i).iScreenHeight== res.iScreenHeight &&
554         CDisplaySettings::Get().GetResolutionInfo(i).fRefreshRate == res.fRefreshRate &&
555         CDisplaySettings::Get().GetResolutionInfo(i).dwFlags      == res.dwFlags)
556       return; // already have this resolution
557   }
558
559   CDisplaySettings::Get().AddResolutionInfo(res);
560 }
561
562 bool CWinSystemWin32::UpdateResolutionsInternal()
563 {
564
565   DISPLAY_DEVICE ddAdapter;
566   ZeroMemory(&ddAdapter, sizeof(ddAdapter));
567   ddAdapter.cb = sizeof(ddAdapter);
568   DWORD adapter = 0;
569
570   while (EnumDisplayDevices(NULL, adapter, &ddAdapter, 0))
571   {
572     // Exclude displays that are not part of the windows desktop. Using them is too different: no windows,
573     // direct access with GDI CreateDC() or DirectDraw for example. So it may be possible to play video, but GUI?
574     if (!(ddAdapter.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) && (ddAdapter.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
575     {
576       DISPLAY_DEVICE ddMon;
577       ZeroMemory(&ddMon, sizeof(ddMon));
578       ddMon.cb = sizeof(ddMon);
579       bool foundScreen = false;
580       DWORD screen = 0;
581
582       // Just look for the first active output, we're actually only interested in the information at the adapter level.
583       while (EnumDisplayDevices(ddAdapter.DeviceName, screen, &ddMon, 0))
584       {
585         if (ddMon.StateFlags & (DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED))
586         {
587           foundScreen = true;
588           break;
589         }
590         ZeroMemory(&ddMon, sizeof(ddMon));
591         ddMon.cb = sizeof(ddMon);
592         screen++;
593       }
594       // Remoting returns no screens. Handle with a dummy screen.
595       if (!foundScreen && screen == 0)
596       {
597         lstrcpy(ddMon.DeviceString, _T("Dummy Monitor")); // safe: large static array
598         foundScreen = true;
599       }
600
601       if (foundScreen)
602       {
603         CLog::Log(LOGNOTICE, "Found screen: %s on %s, adapter %d.", ddMon.DeviceString, ddAdapter.DeviceString, adapter);
604
605         // get information about the display's current position and display mode
606         // TODO: for Windows 7/Server 2008 and up, Microsoft recommends QueryDisplayConfig() instead, the API used by the control panel.
607         DEVMODE dm;
608         ZeroMemory(&dm, sizeof(dm));
609         dm.dmSize = sizeof(dm);
610         if (EnumDisplaySettingsEx(ddAdapter.DeviceName, ENUM_CURRENT_SETTINGS, &dm, 0) == FALSE)
611           EnumDisplaySettingsEx(ddAdapter.DeviceName, ENUM_REGISTRY_SETTINGS, &dm, 0);
612
613         // get the monitor handle and workspace
614         HMONITOR hm = 0;
615         POINT pt = { dm.dmPosition.x, dm.dmPosition.y };
616         hm = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
617
618         MONITOR_DETAILS md;
619         memset(&md, 0, sizeof(MONITOR_DETAILS));
620
621         strcpy(md.MonitorName, ddMon.DeviceString);
622         strcpy(md.CardName, ddAdapter.DeviceString);
623         strcpy(md.DeviceName, ddAdapter.DeviceName);
624
625         // width x height @ x,y - bpp - refresh rate
626         // note that refresh rate information is not available on Win9x
627         md.ScreenWidth = dm.dmPelsWidth;
628         md.ScreenHeight = dm.dmPelsHeight;
629         md.hMonitor = hm;
630         md.RefreshRate = dm.dmDisplayFrequency;
631         md.Bpp = dm.dmBitsPerPel;
632         md.Interlaced = (dm.dmDisplayFlags & DM_INTERLACED) ? true : false;
633
634         m_MonitorsInfo.push_back(md);
635
636         // Careful, some adapters don't end up in the vector (mirroring, no active output, etc.)
637         if (ddAdapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
638           m_nPrimary = m_MonitorsInfo.size() -1;
639
640       }
641     }
642     ZeroMemory(&ddAdapter, sizeof(ddAdapter));
643     ddAdapter.cb = sizeof(ddAdapter);
644     adapter++;
645   }
646   return 0;
647 }
648
649 void CWinSystemWin32::ShowOSMouse(bool show)
650 {
651   static int counter = 0;
652   if ((counter < 0 && show) || (counter >= 0 && !show))
653     counter = ShowCursor(show);
654 }
655
656 bool CWinSystemWin32::Minimize()
657 {
658   ShowWindow(m_hWnd, SW_MINIMIZE);
659   return true;
660 }
661 bool CWinSystemWin32::Restore()
662 {
663   ShowWindow(m_hWnd, SW_RESTORE);
664   return true;
665 }
666 bool CWinSystemWin32::Hide()
667 {
668   ShowWindow(m_hWnd, SW_HIDE);
669   return true;
670 }
671 bool CWinSystemWin32::Show(bool raise)
672 {
673   HWND windowAfter = HWND_BOTTOM;
674   if (raise)
675   {
676     if (m_bFullScreen)
677       windowAfter = HWND_TOP;
678     else
679       windowAfter = g_advancedSettings.m_alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST;
680   }
681
682   SetWindowPos(m_hWnd, windowAfter, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
683   UpdateWindow(m_hWnd);
684   if (raise)
685   {
686     SetForegroundWindow(m_hWnd);
687     SetFocus(m_hWnd);
688   }
689   return true;
690 }
691
692 #endif