Line data Source code
1 : /*
2 : * Copyright (c) 2014 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 :
11 : #include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
12 :
13 : namespace webrtc {
14 :
15 0 : WindowUtilX11::WindowUtilX11(rtc::scoped_refptr<SharedXDisplay> x_display) {
16 0 : x_display_ = x_display;
17 0 : wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
18 0 : window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
19 0 : normal_window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE_NORMAL", True);
20 0 : process_atom_ = XInternAtom(display(), "_NET_WM_PID", True);
21 0 : frame_extends_atom_ = XInternAtom(display(), "_NET_FRAME_EXTENTS", True);
22 0 : }
23 :
24 0 : WindowUtilX11::~WindowUtilX11() {
25 0 : }
26 :
27 0 : ::Window WindowUtilX11::GetApplicationWindow(::Window window) {
28 : // Get WM_STATE property of the window.
29 0 : XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
30 :
31 : // WM_STATE is considered to be set to WithdrawnState when it missing.
32 0 : int32_t state = window_state.is_valid() ? *window_state.data() : WithdrawnState;
33 :
34 0 : if (state == NormalState) {
35 : // Window has WM_STATE==NormalState. Return it.
36 0 : return window;
37 0 : } else if (state == IconicState) {
38 : // Window is in minimized. Skip it.
39 0 : return 0;
40 : }
41 :
42 : // If the window is in WithdrawnState then look at all of its children.
43 : ::Window root, parent;
44 : ::Window *children;
45 : unsigned int num_children;
46 0 : if (!XQueryTree(display(), window, &root, &parent, &children, &num_children)) {
47 0 : LOG(LS_ERROR) << "Failed to query for child windows although window"
48 0 : << "does not have a valid WM_STATE.";
49 0 : return 0;
50 : }
51 0 : ::Window app_window = 0;
52 0 : for (unsigned int i = 0; i < num_children; ++i) {
53 0 : app_window = GetApplicationWindow(children[i]);
54 0 : if (app_window) {
55 0 : break;
56 : }
57 : }
58 :
59 0 : if (children) {
60 0 : XFree(children);
61 : }
62 0 : return app_window;
63 : }
64 :
65 0 : bool WindowUtilX11::IsDesktopElement(::Window window) {
66 0 : if (window == 0) {
67 0 : return false;
68 : }
69 :
70 : // First look for _NET_WM_WINDOW_TYPE. The standard
71 : // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306)
72 : // says this hint *should* be present on all windows, and we use the existence
73 : // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not
74 : // a desktop element (that is, only "normal" windows should be shareable).
75 0 : XWindowProperty<uint32_t> window_type(display(), window, window_type_atom_);
76 0 : if (window_type.is_valid() && window_type.size() > 0) {
77 0 : uint32_t* end = window_type.data() + window_type.size();
78 0 : bool is_normal = (end != std::find(window_type.data(), end, normal_window_type_atom_));
79 0 : return !is_normal;
80 : }
81 :
82 : // Fall back on using the hint.
83 : XClassHint class_hint;
84 0 : Status status = XGetClassHint(display(), window, &class_hint);
85 0 : bool result = false;
86 0 : if (status == 0) {
87 : // No hints, assume this is a normal application window.
88 0 : return result;
89 : }
90 :
91 0 : if (strcmp("gnome-panel", class_hint.res_name) == 0 ||
92 0 : strcmp("desktop_window", class_hint.res_name) == 0) {
93 0 : result = true;
94 : }
95 0 : XFree(class_hint.res_name);
96 0 : XFree(class_hint.res_class);
97 0 : return result;
98 : }
99 :
100 0 : bool WindowUtilX11::GetWindowTitle(::Window window, std::string* title) {
101 : int status;
102 0 : bool result = false;
103 : XTextProperty window_name;
104 0 : window_name.value = NULL;
105 0 : if (window) {
106 0 : char * pWinName = NULL;
107 0 : if(XFetchName(display(), window, &pWinName)){
108 0 : *title = pWinName;
109 0 : XFree(pWinName);
110 0 : result = true;
111 : }
112 : else{
113 0 : status = XGetWMName(display(), window, &window_name);
114 0 : if (status && window_name.value && window_name.nitems) {
115 : int cnt;
116 0 : char **list = NULL;
117 0 : status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
118 0 : &cnt);
119 0 : if (status >= Success && cnt && *list) {
120 0 : if (cnt > 1) {
121 0 : LOG(LS_INFO) << "Window has " << cnt << " text properties, only using the first one.";
122 : }
123 0 : *title = *list;
124 0 : result = true;
125 : }
126 0 : if (list) {
127 0 : XFreeStringList(list);
128 : }
129 : }
130 0 : if (window_name.value) {
131 0 : XFree(window_name.value);
132 : }
133 : }
134 : }
135 0 : return result;
136 : }
137 :
138 0 : bool WindowUtilX11::BringWindowToFront(::Window window) {
139 0 : if (!window) {
140 0 : return false;
141 : }
142 :
143 : unsigned int num_children;
144 : ::Window* children;
145 : ::Window parent;
146 : ::Window root;
147 : // Find the root window to pass event to.
148 0 : int status = XQueryTree(display(), window, &root, &parent, &children, &num_children);
149 0 : if (status == 0) {
150 0 : LOG(LS_ERROR) << "Failed to query for the root window.";
151 0 : return false;
152 : }
153 :
154 0 : if (children) {
155 0 : XFree(children);
156 : }
157 :
158 0 : XRaiseWindow(display(), window);
159 :
160 : // Some window managers (e.g., metacity in GNOME) consider it illegal to
161 : // raise a window without also giving it input focus with
162 : // _NET_ACTIVE_WINDOW, so XRaiseWindow() on its own isn't enough.
163 0 : Atom atom = XInternAtom(display(), "_NET_ACTIVE_WINDOW", True);
164 0 : if (atom != None) {
165 : XEvent xev;
166 0 : xev.xclient.type = ClientMessage;
167 0 : xev.xclient.serial = 0;
168 0 : xev.xclient.send_event = True;
169 0 : xev.xclient.window = window;
170 0 : xev.xclient.message_type = atom;
171 :
172 : // The format member is set to 8, 16, or 32 and specifies whether the
173 : // data should be viewed as a list of bytes, shorts, or longs.
174 0 : xev.xclient.format = 32;
175 :
176 0 : memset(xev.xclient.data.l, 0, sizeof(xev.xclient.data.l));
177 :
178 0 : XSendEvent(display(),
179 : root,
180 : False,
181 : SubstructureRedirectMask | SubstructureNotifyMask,
182 0 : &xev);
183 : }
184 0 : XFlush(display());
185 0 : return true;
186 : }
187 :
188 0 : int WindowUtilX11::GetWindowProcessID(::Window window) {
189 : // Get _NET_WM_PID property of the window.
190 0 : XWindowProperty<uint32_t> process_id(display(), window, process_atom_);
191 :
192 0 : return process_id.is_valid() ? *process_id.data() : 0;
193 : }
194 :
195 0 : int32_t WindowUtilX11::GetWindowStatus(::Window window) {
196 : // Get WM_STATE property of the window.
197 0 : XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
198 :
199 : // WM_STATE is considered to be set to -1 when it missing.
200 0 : int32_t state = window_state.is_valid() ? *window_state.data() : -1;
201 0 : return state;
202 : }
203 :
204 0 : bool WindowUtilX11::GetWindowFrameExtents(::Window window,
205 : int32_t &left, int32_t &top,
206 : int32_t &right, int32_t &bottom) {
207 : //reset it first
208 0 : left = top = right = bottom =0;
209 :
210 : Atom actual_type;
211 : int actual_format;
212 : unsigned long nitems;
213 : unsigned long bytes_remaining;
214 : unsigned char *data;
215 : int status;
216 :
217 0 : status = XGetWindowProperty(display(),
218 : window,
219 : frame_extends_atom_,
220 : 0, // long_offset
221 : 4, // long_length - we expect 4 32-bit values for _NET_FRAME_EXTENTS
222 : False, // delete
223 : AnyPropertyType,
224 : &actual_type,
225 : &actual_format,
226 : &nitems,
227 : &bytes_remaining,
228 0 : &data);
229 :
230 0 : if (status == Success) {
231 0 : if ((nitems == 4) && (bytes_remaining == 0)) {
232 0 : long *data_as_long = (long *)((void *) data);
233 0 : left = (int) *(data_as_long++);
234 0 : right = (int) *(data_as_long++);
235 0 : top = (int) *(data_as_long++);
236 0 : bottom = (int) *(data_as_long++);
237 0 : return true;
238 : }
239 0 : XFree (data);
240 : }
241 0 : return false;
242 : }
243 :
244 0 : bool WindowUtilX11::GetWindowRect(::Window window, XRectangle & rcWindow, bool bWithFrame) {
245 : // reset
246 0 : rcWindow.x = rcWindow.y = rcWindow.width = rcWindow.height = 0;
247 :
248 : // get window info
249 : XWindowAttributes win_info;
250 0 : if (!XGetWindowAttributes(display(), window, &win_info)) {
251 0 : return false;
252 : }
253 :
254 : int absx,absy;
255 : ::Window temp_win;
256 0 : ::Window root_win = DefaultRootWindow(display());
257 0 : if (!XTranslateCoordinates(display(), window, root_win, 0, 0, &absx, &absy, &temp_win)) {
258 0 : return false;
259 : }
260 :
261 : // Adjust to limit in screen
262 0 : int nScreenCX = DisplayWidth(display(), DefaultScreen(display()));
263 0 : int nScreenCY = DisplayHeight(display(), DefaultScreen(display()));
264 :
265 0 : if (absx < 0) {
266 0 : win_info.width += absx;
267 0 : absx = 0;
268 0 : } else if ((absx + win_info.width) > nScreenCX) {
269 0 : win_info.width = nScreenCX - absx;
270 : }
271 0 : if (absy < 0) {
272 0 : win_info.height += absy;
273 0 : absy = 0;
274 0 : } else if ((absy + win_info.height) > nScreenCY) {
275 0 : win_info.height = nScreenCY - absy;
276 : }
277 :
278 : // data setting
279 0 : rcWindow.x = absx;
280 0 : rcWindow.y = absy;
281 0 : rcWindow.width = win_info.width;
282 0 : rcWindow.height = win_info.height;
283 :
284 0 : if (bWithFrame) {
285 : int left;
286 : int right;
287 : int top;
288 : int bottom;
289 0 : if (GetWindowFrameExtents(window, left, top, right, bottom)) {
290 0 : rcWindow.x -= left;
291 0 : rcWindow.y -= top;
292 0 : rcWindow.width += (left + right);
293 0 : rcWindow.height += (top + bottom);
294 : }
295 : }
296 0 : return true;
297 : }
298 :
299 : }//namespace webrtc
|