OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <memory> | 11 #include <memory> |
12 | 12 |
13 #include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h" | 13 #include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h" |
14 | 14 |
15 #include <X11/extensions/Xfixes.h> | 15 #include <X11/extensions/Xfixes.h> |
16 #include <X11/Xlib.h> | 16 #include <X11/Xlib.h> |
17 #include <X11/Xutil.h> | 17 #include <X11/Xutil.h> |
18 | 18 |
19 #include "webrtc/base/logging.h" | 19 #include "webrtc/base/logging.h" |
20 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 20 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
21 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 21 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
22 #include "webrtc/modules/desktop_capture/mouse_cursor.h" | 22 #include "webrtc/modules/desktop_capture/mouse_cursor.h" |
23 #include "webrtc/modules/desktop_capture/x11/x_error_trap.h" | 23 #include "webrtc/modules/desktop_capture/x11/x_error_trap.h" |
24 | 24 |
25 namespace webrtc { | |
26 | |
25 namespace { | 27 namespace { |
26 | 28 |
27 // WindowCapturer returns window IDs of X11 windows with WM_STATE attribute. | 29 // WindowCapturer returns window IDs of X11 windows with WM_STATE attribute. |
28 // These windows may not be immediate children of the root window, because | 30 // These windows may not be immediate children of the root window, because |
29 // window managers may re-parent them to add decorations. However, | 31 // window managers may re-parent them to add decorations. However, |
30 // XQueryPointer() expects to be passed children of the root. This function | 32 // XQueryPointer() expects to be passed children of the root. This function |
31 // searches up the list of the windows to find the root child that corresponds | 33 // searches up the list of the windows to find the root child that corresponds |
32 // to |window|. | 34 // to |window|. |
33 Window GetTopLevelWindow(Display* display, Window window) { | 35 Window GetTopLevelWindow(Display* display, Window window) { |
34 while (true) { | 36 while (true) { |
(...skipping 12 matching lines...) Expand all Loading... | |
47 | 49 |
48 if (parent == root) | 50 if (parent == root) |
49 break; | 51 break; |
50 | 52 |
51 window = parent; | 53 window = parent; |
52 } | 54 } |
53 | 55 |
54 return window; | 56 return window; |
55 } | 57 } |
56 | 58 |
59 DesktopSize GetWindowSize(Display* display, Window window) { | |
60 XWindowAttributes attributes; | |
61 { | |
62 XErrorTrap error_trap(display); | |
63 if (!XGetWindowAttributes(display, window, &attributes) || | |
64 error_trap.GetLastErrorAndDisable() != 0) { | |
65 return DesktopSize(0, 0); | |
Sergey Ulanov
2017/05/19 20:36:03
DesktopSize(); Don't need the zeros
braveyao1
2017/05/19 22:38:59
Done.
| |
66 } | |
67 } | |
68 | |
69 return DesktopSize(attributes.width, attributes.height); | |
70 } | |
71 | |
72 // As the comments to |GetTopLevelWindow()| above states, in window capture, | |
Sergey Ulanov
2017/05/19 20:36:03
nit: || around name of a function are not necessar
braveyao1
2017/05/19 22:38:59
Done.
| |
73 // the captured frame is in the coordinates of the input |window|, while the | |
74 // captured cursor position is in the coordinates of its |parent| window. | |
75 // And these two coordinates are not always same. The |parent| window may have | |
76 // decorations added, including the caption bar on top of the window and the | |
77 // shadow and border around them. The offset needs to be compensated later. | |
78 DesktopVector GetCursorPostionOffset(Display* display, | |
79 Window parent, | |
80 Window children) { | |
Sergey Ulanov
2017/05/19 20:36:03
s/children/child/
'children' is plural
braveyao1
2017/05/19 22:38:59
Done.
| |
81 DesktopSize parent_size = GetWindowSize(display, parent); | |
82 DesktopSize children_size = GetWindowSize(display, children); | |
83 | |
84 if (parent_size.is_empty() || children_size.is_empty()) { | |
85 return DesktopVector(0, 0); | |
86 } | |
87 // The |x_offset| is the thickness of the shadow and border added around. | |
88 // The |y_offset| doesn't include the shadow and border added at the bottom. | |
89 int x_offset = (parent_size.width() - children_size.width()) / 2; | |
Sergey Ulanov
2017/05/19 20:36:03
This assumes that the border has the same width on
braveyao1
2017/05/19 22:38:59
Done.
| |
90 int y_offset = parent_size.height() - children_size.height() - x_offset; | |
Sergey Ulanov
2017/05/19 20:36:03
This also assumes that border at the bottom is the
braveyao1
2017/05/19 22:38:59
Done.
| |
91 | |
92 return DesktopVector(x_offset, y_offset); | |
93 } | |
94 | |
57 } // namespace | 95 } // namespace |
58 | 96 |
59 namespace webrtc { | |
60 | |
61 class MouseCursorMonitorX11 : public MouseCursorMonitor, | 97 class MouseCursorMonitorX11 : public MouseCursorMonitor, |
62 public SharedXDisplay::XEventHandler { | 98 public SharedXDisplay::XEventHandler { |
63 public: | 99 public: |
64 MouseCursorMonitorX11(const DesktopCaptureOptions& options, Window window); | 100 MouseCursorMonitorX11(const DesktopCaptureOptions& options, |
101 Window window, | |
102 DesktopVector offset); | |
65 ~MouseCursorMonitorX11() override; | 103 ~MouseCursorMonitorX11() override; |
66 | 104 |
67 void Init(Callback* callback, Mode mode) override; | 105 void Init(Callback* callback, Mode mode) override; |
68 void Capture() override; | 106 void Capture() override; |
69 | 107 |
70 private: | 108 private: |
71 // SharedXDisplay::XEventHandler interface. | 109 // SharedXDisplay::XEventHandler interface. |
72 bool HandleXEvent(const XEvent& event) override; | 110 bool HandleXEvent(const XEvent& event) override; |
73 | 111 |
74 Display* display() { return x_display_->display(); } | 112 Display* display() { return x_display_->display(); } |
75 | 113 |
76 // Captures current cursor shape and stores it in |cursor_shape_|. | 114 // Captures current cursor shape and stores it in |cursor_shape_|. |
77 void CaptureCursor(); | 115 void CaptureCursor(); |
78 | 116 |
79 rtc::scoped_refptr<SharedXDisplay> x_display_; | 117 rtc::scoped_refptr<SharedXDisplay> x_display_; |
80 Callback* callback_; | 118 Callback* callback_; |
81 Mode mode_; | 119 Mode mode_; |
82 Window window_; | 120 Window window_; |
121 DesktopVector offset_; | |
83 | 122 |
84 bool have_xfixes_; | 123 bool have_xfixes_; |
85 int xfixes_event_base_; | 124 int xfixes_event_base_; |
86 int xfixes_error_base_; | 125 int xfixes_error_base_; |
87 | 126 |
88 std::unique_ptr<MouseCursor> cursor_shape_; | 127 std::unique_ptr<MouseCursor> cursor_shape_; |
89 }; | 128 }; |
90 | 129 |
91 MouseCursorMonitorX11::MouseCursorMonitorX11( | 130 MouseCursorMonitorX11::MouseCursorMonitorX11( |
92 const DesktopCaptureOptions& options, | 131 const DesktopCaptureOptions& options, |
93 Window window) | 132 Window window, |
133 DesktopVector offset) | |
94 : x_display_(options.x_display()), | 134 : x_display_(options.x_display()), |
95 callback_(NULL), | 135 callback_(NULL), |
96 mode_(SHAPE_AND_POSITION), | 136 mode_(SHAPE_AND_POSITION), |
97 window_(window), | 137 window_(window), |
138 offset_(offset), | |
98 have_xfixes_(false), | 139 have_xfixes_(false), |
99 xfixes_event_base_(-1), | 140 xfixes_event_base_(-1), |
100 xfixes_error_base_(-1) { | 141 xfixes_error_base_(-1) { |
101 // Set a default initial cursor shape in case XFixes is not present. | 142 // Set a default initial cursor shape in case XFixes is not present. |
102 const int kSize = 5; | 143 const int kSize = 5; |
103 std::unique_ptr<DesktopFrame> default_cursor( | 144 std::unique_ptr<DesktopFrame> default_cursor( |
104 new BasicDesktopFrame(DesktopSize(kSize, kSize))); | 145 new BasicDesktopFrame(DesktopSize(kSize, kSize))); |
105 const uint8_t pixels[kSize * kSize] = { | 146 const uint8_t pixels[kSize * kSize] = { |
106 0x00, 0x00, 0x00, 0x00, 0x00, | 147 0x00, 0x00, 0x00, 0x00, 0x00, |
107 0x00, 0xff, 0xff, 0xff, 0x00, | 148 0x00, 0xff, 0xff, 0xff, 0x00, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 if (!result || error_trap.GetLastErrorAndDisable() != 0) { | 219 if (!result || error_trap.GetLastErrorAndDisable() != 0) { |
179 state = OUTSIDE; | 220 state = OUTSIDE; |
180 } else { | 221 } else { |
181 // In screen mode (window_ == root_window) the mouse is always inside. | 222 // In screen mode (window_ == root_window) the mouse is always inside. |
182 // XQueryPointer() sets |child_window| to None if the cursor is outside | 223 // XQueryPointer() sets |child_window| to None if the cursor is outside |
183 // |window_|. | 224 // |window_|. |
184 state = | 225 state = |
185 (window_ == root_window || child_window != None) ? INSIDE : OUTSIDE; | 226 (window_ == root_window || child_window != None) ? INSIDE : OUTSIDE; |
186 } | 227 } |
187 | 228 |
188 callback_->OnMouseCursorPosition(state, | 229 callback_->OnMouseCursorPosition( |
189 webrtc::DesktopVector(win_x, win_y)); | 230 state, DesktopVector(win_x, win_y).subtract(offset_)); |
190 } | 231 } |
191 } | 232 } |
192 | 233 |
193 bool MouseCursorMonitorX11::HandleXEvent(const XEvent& event) { | 234 bool MouseCursorMonitorX11::HandleXEvent(const XEvent& event) { |
194 if (have_xfixes_ && event.type == xfixes_event_base_ + XFixesCursorNotify) { | 235 if (have_xfixes_ && event.type == xfixes_event_base_ + XFixesCursorNotify) { |
195 const XFixesCursorNotifyEvent* cursor_event = | 236 const XFixesCursorNotifyEvent* cursor_event = |
196 reinterpret_cast<const XFixesCursorNotifyEvent*>(&event); | 237 reinterpret_cast<const XFixesCursorNotifyEvent*>(&event); |
197 if (cursor_event->subtype == XFixesDisplayCursorNotify) { | 238 if (cursor_event->subtype == XFixesDisplayCursorNotify) { |
198 CaptureCursor(); | 239 CaptureCursor(); |
199 } | 240 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 XFree(img); | 272 XFree(img); |
232 | 273 |
233 cursor_shape_.reset(new MouseCursor(image.release(), hotspot)); | 274 cursor_shape_.reset(new MouseCursor(image.release(), hotspot)); |
234 } | 275 } |
235 | 276 |
236 // static | 277 // static |
237 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( | 278 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( |
238 const DesktopCaptureOptions& options, WindowId window) { | 279 const DesktopCaptureOptions& options, WindowId window) { |
239 if (!options.x_display()) | 280 if (!options.x_display()) |
240 return NULL; | 281 return NULL; |
241 window = GetTopLevelWindow(options.x_display()->display(), window); | 282 Window parent = GetTopLevelWindow(options.x_display()->display(), window); |
242 if (window == None) | 283 if (parent == None) |
243 return NULL; | 284 return NULL; |
244 return new MouseCursorMonitorX11(options, window); | 285 |
286 DesktopVector offset = | |
287 GetCursorPostionOffset(options.x_display()->display(), parent, window); | |
288 return new MouseCursorMonitorX11(options, parent, offset); | |
245 } | 289 } |
246 | 290 |
247 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( | 291 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( |
248 const DesktopCaptureOptions& options, | 292 const DesktopCaptureOptions& options, |
249 ScreenId screen) { | 293 ScreenId screen) { |
250 if (!options.x_display()) | 294 if (!options.x_display()) |
251 return NULL; | 295 return NULL; |
296 | |
252 return new MouseCursorMonitorX11( | 297 return new MouseCursorMonitorX11( |
253 options, DefaultRootWindow(options.x_display()->display())); | 298 options, DefaultRootWindow(options.x_display()->display()), |
299 DesktopVector(0, 0)); | |
254 } | 300 } |
255 | 301 |
256 } // namespace webrtc | 302 } // namespace webrtc |
OLD | NEW |