- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / desktop_resizer_win.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "remoting/host/desktop_resizer.h"
6
7 #include <map>
8
9 #include "base/logging.h"
10
11 namespace {
12 // TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
13 const int kDefaultDPI = 96;
14 }  // namespace
15
16 namespace remoting {
17
18 // Provide comparison operation for ScreenResolution so we can use it in
19 // std::map.
20 static inline bool operator <(const ScreenResolution& a,
21                               const ScreenResolution& b) {
22   if (a.dimensions().width() != b.dimensions().width())
23     return a.dimensions().width() < b.dimensions().width();
24   if (a.dimensions().height() != b.dimensions().height())
25     return a.dimensions().height() < b.dimensions().height();
26   if (a.dpi().x() != b.dpi().x())
27     return a.dpi().x() < b.dpi().x();
28   return a.dpi().y() < b.dpi().y();
29 }
30
31 class DesktopResizerWin : public DesktopResizer {
32  public:
33   DesktopResizerWin();
34   virtual ~DesktopResizerWin();
35
36   // DesktopResizer interface.
37   virtual ScreenResolution GetCurrentResolution() OVERRIDE;
38   virtual std::list<ScreenResolution> GetSupportedResolutions(
39       const ScreenResolution& preferred) OVERRIDE;
40   virtual void SetResolution(const ScreenResolution& resolution) OVERRIDE;
41   virtual void RestoreResolution(const ScreenResolution& original) OVERRIDE;
42
43  private:
44   static bool IsResizeSupported();
45
46   // Calls EnumDisplaySettingsEx() for the primary monitor.
47   // Returns false if |mode_number| does not exist.
48   static bool GetPrimaryDisplayMode(
49       DWORD mode_number, DWORD flags, DEVMODE* mode);
50
51   // Returns true if the mode has width, height, bits-per-pixel, frequency
52   // and orientation fields.
53   static bool IsModeValid(const DEVMODE& mode);
54
55   // Returns the width & height of |mode|, or 0x0 if they are missing.
56   static ScreenResolution GetModeResolution(const DEVMODE& mode);
57
58   std::map<ScreenResolution, DEVMODE> best_mode_for_resolution_;
59
60   DISALLOW_COPY_AND_ASSIGN(DesktopResizerWin);
61 };
62
63 DesktopResizerWin::DesktopResizerWin() {
64 }
65
66 DesktopResizerWin::~DesktopResizerWin() {
67 }
68
69 ScreenResolution DesktopResizerWin::GetCurrentResolution() {
70   DEVMODE current_mode;
71   if (GetPrimaryDisplayMode(ENUM_CURRENT_SETTINGS, 0, &current_mode) &&
72       IsModeValid(current_mode))
73     return GetModeResolution(current_mode);
74   return ScreenResolution();
75 }
76
77 std::list<ScreenResolution> DesktopResizerWin::GetSupportedResolutions(
78     const ScreenResolution& preferred) {
79   if (!IsResizeSupported())
80     return std::list<ScreenResolution>();
81
82   // Enumerate the resolutions to return, and where there are multiple modes of
83   // the same resolution, store the one most closely matching the current mode
84   // in |best_mode_for_resolution_|.
85   DEVMODE current_mode;
86   if (!GetPrimaryDisplayMode(ENUM_CURRENT_SETTINGS, 0, &current_mode) ||
87       !IsModeValid(current_mode))
88     return std::list<ScreenResolution>();
89
90   std::list<ScreenResolution> resolutions;
91   best_mode_for_resolution_.clear();
92   for (DWORD i = 0; ; ++i) {
93     DEVMODE candidate_mode;
94     if (!GetPrimaryDisplayMode(i, EDS_ROTATEDMODE, &candidate_mode))
95       break;
96
97     // Ignore modes missing the fields that we expect.
98     if (!IsModeValid(candidate_mode))
99       continue;
100
101     // Ignore modes with differing bits-per-pixel.
102     if (candidate_mode.dmBitsPerPel != current_mode.dmBitsPerPel)
103       continue;
104
105     // If there are multiple modes with the same dimensions:
106     // - Prefer the modes which match the current rotation.
107     // - Among those, prefer modes which match the current frequency.
108     // - Otherwise, prefer modes with a higher frequency.
109     ScreenResolution candidate_resolution = GetModeResolution(candidate_mode);
110     if (best_mode_for_resolution_.count(candidate_resolution) != 0) {
111       DEVMODE best_mode = best_mode_for_resolution_[candidate_resolution];
112
113       if ((candidate_mode.dmDisplayOrientation !=
114            current_mode.dmDisplayOrientation) &&
115           (best_mode.dmDisplayOrientation ==
116            current_mode.dmDisplayOrientation)) {
117         continue;
118       }
119
120       if ((candidate_mode.dmDisplayFrequency !=
121            current_mode.dmDisplayFrequency) &&
122           (best_mode.dmDisplayFrequency >=
123            candidate_mode.dmDisplayFrequency)) {
124         continue;
125       }
126     } else {
127       // If we haven't seen this resolution before, add it to those we return.
128       resolutions.push_back(candidate_resolution);
129     }
130
131     best_mode_for_resolution_[candidate_resolution] = candidate_mode;
132   }
133
134   return resolutions;
135 }
136
137 void DesktopResizerWin::SetResolution(const ScreenResolution& resolution) {
138   if (best_mode_for_resolution_.count(resolution) == 0)
139     return;
140
141   DEVMODE new_mode = best_mode_for_resolution_[resolution];
142   DWORD result = ChangeDisplaySettings(&new_mode, CDS_FULLSCREEN);
143   if (result != DISP_CHANGE_SUCCESSFUL)
144     LOG(ERROR) << "SetResolution failed: " << result;
145 }
146
147 void DesktopResizerWin::RestoreResolution(const ScreenResolution& original) {
148   // Restore the display mode based on the registry configuration.
149   DWORD result = ChangeDisplaySettings(NULL, 0);
150   if (result != DISP_CHANGE_SUCCESSFUL)
151     LOG(ERROR) << "RestoreResolution failed: " << result;
152 }
153
154 // static
155 bool DesktopResizerWin::IsResizeSupported() {
156   // Resize is supported only on single-monitor systems.
157   return GetSystemMetrics(SM_CMONITORS) == 1;
158 }
159
160 // static
161 bool DesktopResizerWin::GetPrimaryDisplayMode(
162     DWORD mode_number, DWORD flags, DEVMODE* mode) {
163  memset(mode, 0, sizeof(DEVMODE));
164  mode->dmSize = sizeof(DEVMODE);
165  if (!EnumDisplaySettingsEx(NULL, mode_number, mode, flags))
166    return false;
167  return true;
168 }
169
170 // static
171 bool DesktopResizerWin::IsModeValid(const DEVMODE& mode) {
172   const DWORD kRequiredFields =
173       DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
174       DM_DISPLAYFREQUENCY | DM_DISPLAYORIENTATION;
175   return (mode.dmFields & kRequiredFields) == kRequiredFields;
176 }
177
178 // static
179 ScreenResolution DesktopResizerWin::GetModeResolution(const DEVMODE& mode) {
180   DCHECK(IsModeValid(mode));
181   return ScreenResolution(
182       webrtc::DesktopSize(mode.dmPelsWidth, mode.dmPelsHeight),
183       webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
184 }
185
186 scoped_ptr<DesktopResizer> DesktopResizer::Create() {
187   return scoped_ptr<DesktopResizer>(new DesktopResizerWin);
188 }
189
190 }  // namespace remoting