1/*
2 *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10#include "webrtc/base/win32windowpicker.h"
11
12#include <string>
13#include <vector>
14
15#include "webrtc/base/arraysize.h"
16#include "webrtc/base/common.h"
17#include "webrtc/base/logging.h"
18
19namespace rtc {
20
21namespace {
22
23// Window class names that we want to filter out.
24const char kProgramManagerClass[] = "Progman";
25const char kButtonClass[] = "Button";
26
27}  // namespace
28
29BOOL CALLBACK Win32WindowPicker::EnumProc(HWND hwnd, LPARAM l_param) {
30  WindowDescriptionList* descriptions =
31      reinterpret_cast<WindowDescriptionList*>(l_param);
32
33  // Skip windows that are invisible, minimized, have no title, or are owned,
34  // unless they have the app window style set. Except for minimized windows,
35  // this is what Alt-Tab does.
36  // TODO: Figure out how to grab a thumbnail of a minimized window and
37  // include them in the list.
38  int len = GetWindowTextLength(hwnd);
39  HWND owner = GetWindow(hwnd, GW_OWNER);
40  LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
41  if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
42      (owner && !(exstyle & WS_EX_APPWINDOW))) {
43    // TODO: Investigate if windows without title still could be
44    // interesting to share. We could use the name of the process as title:
45    //
46    // GetWindowThreadProcessId()
47    // OpenProcess()
48    // QueryFullProcessImageName()
49    return TRUE;
50  }
51
52  // Skip the Program Manager window and the Start button.
53  TCHAR class_name_w[500];
54  ::GetClassName(hwnd, class_name_w, 500);
55  std::string class_name = ToUtf8(class_name_w);
56  if (class_name == kProgramManagerClass || class_name == kButtonClass) {
57    // We don't want the Program Manager window nor the Start button.
58    return TRUE;
59  }
60
61  TCHAR window_title[500];
62  GetWindowText(hwnd, window_title, arraysize(window_title));
63  std::string title = ToUtf8(window_title);
64
65  WindowId id(hwnd);
66  WindowDescription desc(id, title);
67  descriptions->push_back(desc);
68  return TRUE;
69}
70
71BOOL CALLBACK Win32WindowPicker::MonitorEnumProc(HMONITOR h_monitor,
72                                                 HDC hdc_monitor,
73                                                 LPRECT lprc_monitor,
74                                                 LPARAM l_param) {
75  DesktopDescriptionList* desktop_desc =
76      reinterpret_cast<DesktopDescriptionList*>(l_param);
77
78  DesktopId id(h_monitor, static_cast<int>(desktop_desc->size()));
79  // TODO: Figure out an appropriate desktop title.
80  DesktopDescription desc(id, "");
81
82  // Determine whether it's the primary monitor.
83  MONITORINFO monitor_info = {0};
84  monitor_info.cbSize = sizeof(monitor_info);
85  bool primary = (GetMonitorInfo(h_monitor, &monitor_info) &&
86      (monitor_info.dwFlags & MONITORINFOF_PRIMARY) != 0);
87  desc.set_primary(primary);
88
89  desktop_desc->push_back(desc);
90  return TRUE;
91}
92
93Win32WindowPicker::Win32WindowPicker() {
94}
95
96bool Win32WindowPicker::Init() {
97  return true;
98}
99// TODO: Consider changing enumeration to clear() descriptions
100// before append().
101bool Win32WindowPicker::GetWindowList(WindowDescriptionList* descriptions) {
102  LPARAM desc = reinterpret_cast<LPARAM>(descriptions);
103  return EnumWindows(Win32WindowPicker::EnumProc, desc) != FALSE;
104}
105
106bool Win32WindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) {
107  // Create a fresh WindowDescriptionList so that we can use desktop_desc.size()
108  // in MonitorEnumProc to compute the desktop index.
109  DesktopDescriptionList desktop_desc;
110  HDC hdc = GetDC(NULL);
111  bool success = false;
112  if (EnumDisplayMonitors(hdc, NULL, Win32WindowPicker::MonitorEnumProc,
113      reinterpret_cast<LPARAM>(&desktop_desc)) != FALSE) {
114    // Append the desktop descriptions to the end of the returned descriptions.
115    descriptions->insert(descriptions->end(), desktop_desc.begin(),
116                         desktop_desc.end());
117    success = true;
118  }
119  ReleaseDC(NULL, hdc);
120  return success;
121}
122
123bool Win32WindowPicker::GetDesktopDimensions(const DesktopId& id,
124                                             int* width,
125                                             int* height) {
126  MONITORINFOEX monitor_info;
127  monitor_info.cbSize = sizeof(MONITORINFOEX);
128  if (!GetMonitorInfo(id.id(), &monitor_info)) {
129    return false;
130  }
131  *width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left;
132  *height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
133  return true;
134}
135
136bool Win32WindowPicker::IsVisible(const WindowId& id) {
137  return (::IsWindow(id.id()) != FALSE && ::IsWindowVisible(id.id()) != FALSE);
138}
139
140bool Win32WindowPicker::MoveToFront(const WindowId& id) {
141  return SetForegroundWindow(id.id()) != FALSE;
142}
143
144}  // namespace rtc
145