OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file defines utility functions for X11 (Linux only). This code has been | 5 // This file defines utility functions for X11 (Linux only). This code has been |
6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support | 6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support |
7 // remains woefully incomplete. | 7 // remains woefully incomplete. |
8 | 8 |
9 #include "ui/base/x/x11_util.h" | 9 #include "ui/base/x/x11_util.h" |
10 | 10 |
11 #include <gdk/gdk.h> | 11 #include <gdk/gdk.h> |
12 #include <gdk/gdkx.h> | 12 #include <gdk/gdkx.h> |
13 #include <gtk/gtk.h> | 13 #include <gtk/gtk.h> |
14 | 14 |
15 #include <sys/ipc.h> | 15 #include <sys/ipc.h> |
16 #include <sys/shm.h> | 16 #include <sys/shm.h> |
17 | 17 |
18 #include <list> | 18 #include <list> |
19 #include <set> | 19 #include <vector> |
20 | 20 |
21 #include "base/command_line.h" | 21 #include "base/command_line.h" |
22 #include "base/logging.h" | 22 #include "base/logging.h" |
23 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
24 #include "base/string_number_conversions.h" | 24 #include "base/string_number_conversions.h" |
25 #include "base/threading/thread.h" | 25 #include "base/threading/thread.h" |
26 #include "gfx/rect.h" | 26 #include "gfx/rect.h" |
27 #include "gfx/size.h" | 27 #include "gfx/size.h" |
28 #include "ui/base/x/x11_util_internal.h" | 28 #include "ui/base/x/x11_util_internal.h" |
29 | 29 |
(...skipping 29 matching lines...) Expand all Loading... |
59 LOG(ERROR) << GetErrorEventDescription(d, e); | 59 LOG(ERROR) << GetErrorEventDescription(d, e); |
60 return 0; | 60 return 0; |
61 } | 61 } |
62 | 62 |
63 int DefaultX11IOErrorHandler(Display* d) { | 63 int DefaultX11IOErrorHandler(Display* d) { |
64 // If there's an IO error it likely means the X server has gone away | 64 // If there's an IO error it likely means the X server has gone away |
65 LOG(ERROR) << "X IO Error detected"; | 65 LOG(ERROR) << "X IO Error detected"; |
66 _exit(1); | 66 _exit(1); |
67 } | 67 } |
68 | 68 |
| 69 // Note: The caller should free the resulting value data. |
| 70 bool GetProperty(XID window, const std::string& property_name, long max_length, |
| 71 Atom* type, int* format, unsigned long* num_items, |
| 72 unsigned char** property) { |
| 73 Atom property_atom = gdk_x11_get_xatom_by_name_for_display( |
| 74 gdk_display_get_default(), property_name.c_str()); |
| 75 |
| 76 unsigned long remaining_bytes = 0; |
| 77 return XGetWindowProperty(GetXDisplay(), |
| 78 window, |
| 79 property_atom, |
| 80 0, // offset into property data to read |
| 81 max_length, // max length to get |
| 82 False, // deleted |
| 83 AnyPropertyType, |
| 84 type, |
| 85 format, |
| 86 num_items, |
| 87 &remaining_bytes, |
| 88 property); |
| 89 } |
| 90 |
69 } // namespace | 91 } // namespace |
70 | 92 |
71 bool XDisplayExists() { | 93 bool XDisplayExists() { |
72 return (gdk_display_get_default() != NULL); | 94 return (gdk_display_get_default() != NULL); |
73 } | 95 } |
74 | 96 |
75 Display* GetXDisplay() { | 97 Display* GetXDisplay() { |
76 static Display* display = NULL; | 98 static Display* display = NULL; |
77 | 99 |
78 if (!display) | 100 if (!display) |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 return false; | 236 return false; |
215 | 237 |
216 if (!XTranslateCoordinates(GetSecondaryDisplay(), window, root, | 238 if (!XTranslateCoordinates(GetSecondaryDisplay(), window, root, |
217 0, 0, &x, &y, &child)) | 239 0, 0, &x, &y, &child)) |
218 return false; | 240 return false; |
219 | 241 |
220 *rect = gfx::Rect(x, y, width, height); | 242 *rect = gfx::Rect(x, y, width, height); |
221 return true; | 243 return true; |
222 } | 244 } |
223 | 245 |
224 bool GetIntProperty(XID window, const std::string& property_name, int* value) { | 246 bool PropertyExists(XID window, const std::string& property_name) { |
225 Atom property_atom = gdk_x11_get_xatom_by_name_for_display( | |
226 gdk_display_get_default(), property_name.c_str()); | |
227 | |
228 Atom type = None; | 247 Atom type = None; |
229 int format = 0; // size in bits of each item in 'property' | 248 int format = 0; // size in bits of each item in 'property' |
230 long unsigned int num_items = 0, remaining_bytes = 0; | 249 long unsigned int num_items = 0; |
231 unsigned char* property = NULL; | 250 unsigned char* property = NULL; |
232 | 251 |
233 int result = XGetWindowProperty(GetXDisplay(), | 252 int result = GetProperty(window, property_name, 1, |
234 window, | 253 &type, &format, &num_items, &property); |
235 property_atom, | |
236 0, // offset into property data to read | |
237 1, // max length to get | |
238 False, // deleted | |
239 AnyPropertyType, | |
240 &type, | |
241 &format, | |
242 &num_items, | |
243 &remaining_bytes, | |
244 &property); | |
245 if (result != Success) | 254 if (result != Success) |
246 return false; | 255 return false; |
247 | 256 |
| 257 XFree(property); |
| 258 return num_items > 0; |
| 259 } |
| 260 |
| 261 bool GetIntProperty(XID window, const std::string& property_name, int* value) { |
| 262 Atom type = None; |
| 263 int format = 0; // size in bits of each item in 'property' |
| 264 long unsigned int num_items = 0; |
| 265 unsigned char* property = NULL; |
| 266 |
| 267 int result = GetProperty(window, property_name, 1, |
| 268 &type, &format, &num_items, &property); |
| 269 if (result != Success) |
| 270 return false; |
| 271 |
248 if (format != 32 || num_items != 1) { | 272 if (format != 32 || num_items != 1) { |
249 XFree(property); | 273 XFree(property); |
250 return false; | 274 return false; |
251 } | 275 } |
252 | 276 |
253 *value = *(reinterpret_cast<int*>(property)); | 277 *value = *(reinterpret_cast<int*>(property)); |
254 XFree(property); | 278 XFree(property); |
255 return true; | 279 return true; |
256 } | 280 } |
257 | 281 |
258 bool GetIntArrayProperty(XID window, | 282 bool GetIntArrayProperty(XID window, |
259 const std::string& property_name, | 283 const std::string& property_name, |
260 std::vector<int>* value) { | 284 std::vector<int>* value) { |
261 Atom property_atom = gdk_x11_get_xatom_by_name_for_display( | |
262 gdk_display_get_default(), property_name.c_str()); | |
263 | |
264 Atom type = None; | 285 Atom type = None; |
265 int format = 0; // size in bits of each item in 'property' | 286 int format = 0; // size in bits of each item in 'property' |
266 long unsigned int num_items = 0, remaining_bytes = 0; | 287 long unsigned int num_items = 0; |
267 unsigned char* properties = NULL; | 288 unsigned char* properties = NULL; |
268 | 289 |
269 int result = XGetWindowProperty(GetXDisplay(), | 290 int result = GetProperty(window, property_name, |
270 window, | 291 (~0L), // (all of them) |
271 property_atom, | 292 &type, &format, &num_items, &properties); |
272 0, // offset into property data to read | |
273 (~0L), // max length to get (all of them) | |
274 False, // deleted | |
275 AnyPropertyType, | |
276 &type, | |
277 &format, | |
278 &num_items, | |
279 &remaining_bytes, | |
280 &properties); | |
281 if (result != Success) | 293 if (result != Success) |
282 return false; | 294 return false; |
283 | 295 |
284 if (format != 32) { | 296 if (format != 32) { |
285 XFree(properties); | 297 XFree(properties); |
286 return false; | 298 return false; |
287 } | 299 } |
288 | 300 |
289 int* int_properties = reinterpret_cast<int*>(properties); | 301 int* int_properties = reinterpret_cast<int*>(properties); |
290 value->clear(); | 302 value->clear(); |
291 value->insert(value->begin(), int_properties, int_properties + num_items); | 303 value->insert(value->begin(), int_properties, int_properties + num_items); |
292 XFree(properties); | 304 XFree(properties); |
293 return true; | 305 return true; |
294 } | 306 } |
295 | 307 |
| 308 bool GetAtomArrayProperty(XID window, |
| 309 const std::string& property_name, |
| 310 std::vector<Atom>* value) { |
| 311 Atom type = None; |
| 312 int format = 0; // size in bits of each item in 'property' |
| 313 long unsigned int num_items = 0; |
| 314 unsigned char* properties = NULL; |
| 315 |
| 316 int result = GetProperty(window, property_name, |
| 317 (~0L), // (all of them) |
| 318 &type, &format, &num_items, &properties); |
| 319 if (result != Success) |
| 320 return false; |
| 321 |
| 322 if (type != XA_ATOM) { |
| 323 XFree(properties); |
| 324 return false; |
| 325 } |
| 326 |
| 327 Atom* atom_properties = reinterpret_cast<Atom*>(properties); |
| 328 value->clear(); |
| 329 value->insert(value->begin(), atom_properties, atom_properties + num_items); |
| 330 XFree(properties); |
| 331 return true; |
| 332 } |
| 333 |
296 bool GetStringProperty( | 334 bool GetStringProperty( |
297 XID window, const std::string& property_name, std::string* value) { | 335 XID window, const std::string& property_name, std::string* value) { |
298 Atom property_atom = gdk_x11_get_xatom_by_name_for_display( | |
299 gdk_display_get_default(), property_name.c_str()); | |
300 | |
301 Atom type = None; | 336 Atom type = None; |
302 int format = 0; // size in bits of each item in 'property' | 337 int format = 0; // size in bits of each item in 'property' |
303 long unsigned int num_items = 0, remaining_bytes = 0; | 338 long unsigned int num_items = 0; |
304 unsigned char* property = NULL; | 339 unsigned char* property = NULL; |
305 | 340 |
306 int result = XGetWindowProperty(GetXDisplay(), | 341 int result = GetProperty(window, property_name, 1024, |
307 window, | 342 &type, &format, &num_items, &property); |
308 property_atom, | |
309 0, // offset into property data to read | |
310 1024, // max length to get | |
311 False, // deleted | |
312 AnyPropertyType, | |
313 &type, | |
314 &format, | |
315 &num_items, | |
316 &remaining_bytes, | |
317 &property); | |
318 if (result != Success) | 343 if (result != Success) |
319 return false; | 344 return false; |
320 | 345 |
321 if (format != 8) { | 346 if (format != 8) { |
322 XFree(property); | 347 XFree(property); |
323 return false; | 348 return false; |
324 } | 349 } |
325 | 350 |
326 value->assign(reinterpret_cast<char*>(property), num_items); | 351 value->assign(reinterpret_cast<char*>(property), num_items); |
327 XFree(property); | 352 XFree(property); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 if (depth > max_depth) | 394 if (depth > max_depth) |
370 return false; | 395 return false; |
371 | 396 |
372 XID root, parent, *children; | 397 XID root, parent, *children; |
373 unsigned int num_children; | 398 unsigned int num_children; |
374 int status = XQueryTree(GetXDisplay(), window, &root, &parent, &children, | 399 int status = XQueryTree(GetXDisplay(), window, &root, &parent, &children, |
375 &num_children); | 400 &num_children); |
376 if (status == 0) | 401 if (status == 0) |
377 return false; | 402 return false; |
378 | 403 |
379 std::set<XID> windows; | 404 std::vector<XID> windows; |
380 for (unsigned int i = 0; i < num_children; i++) | 405 for (int i = static_cast<int>(num_children) - 1; i >= 0; i--) |
381 windows.insert(children[i]); | 406 windows.push_back(children[i]); |
382 | 407 |
383 XFree(children); | 408 XFree(children); |
384 | 409 |
385 // XQueryTree returns the children of |window| in bottom-to-top order, so | 410 // XQueryTree returns the children of |window| in bottom-to-top order, so |
386 // reverse-iterate the list to check the windows from top-to-bottom. | 411 // reverse-iterate the list to check the windows from top-to-bottom. |
387 std::set<XID>::reverse_iterator iter; | 412 std::vector<XID>::iterator iter; |
388 for (iter = windows.rbegin(); iter != windows.rend(); iter++) { | 413 for (iter = windows.begin(); iter != windows.end(); iter++) { |
389 if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter)) | 414 if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter)) |
390 return true; | 415 return true; |
391 } | 416 } |
392 | 417 |
393 // If we're at this point, we didn't find the window we're looking for at the | 418 // If we're at this point, we didn't find the window we're looking for at the |
394 // current level, so we need to recurse to the next level. We use a second | 419 // current level, so we need to recurse to the next level. We use a second |
395 // loop because the recursion and call to XQueryTree are expensive and is only | 420 // loop because the recursion and call to XQueryTree are expensive and is only |
396 // needed for a small number of cases. | 421 // needed for a small number of cases. |
397 if (++depth <= max_depth) { | 422 if (++depth <= max_depth) { |
398 for (iter = windows.rbegin(); iter != windows.rend(); iter++) { | 423 for (iter = windows.begin(); iter != windows.end(); iter++) { |
399 if (EnumerateChildren(delegate, *iter, max_depth, depth)) | 424 if (EnumerateChildren(delegate, *iter, max_depth, depth)) |
400 return true; | 425 return true; |
401 } | 426 } |
402 } | 427 } |
403 | 428 |
404 return false; | 429 return false; |
405 } | 430 } |
406 | 431 |
407 bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) { | 432 bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) { |
408 XID root = GetX11RootWindow(); | 433 XID root = GetX11RootWindow(); |
409 return EnumerateChildren(delegate, root, max_depth, 0); | 434 return EnumerateChildren(delegate, root, max_depth, 0); |
410 } | 435 } |
411 | 436 |
412 bool GetXWindowStack(std::vector<XID>* windows) { | 437 bool GetXWindowStack(Window window, std::vector<XID>* windows) { |
413 windows->clear(); | 438 windows->clear(); |
414 | 439 |
415 static Atom atom = XInternAtom(GetXDisplay(), | |
416 "_NET_CLIENT_LIST_STACKING", False); | |
417 | |
418 Atom type; | 440 Atom type; |
419 int format; | 441 int format; |
420 unsigned long count; | 442 unsigned long count; |
421 unsigned long bytes_after; | |
422 unsigned char *data = NULL; | 443 unsigned char *data = NULL; |
423 if (XGetWindowProperty(GetXDisplay(), | 444 if (!GetProperty(window, |
424 GetX11RootWindow(), | 445 "_NET_CLIENT_LIST_STACKING", |
425 atom, | 446 ~0L, |
426 0, // offset | 447 &type, |
427 ~0L, // length | 448 &format, |
428 False, // delete | 449 &count, |
429 AnyPropertyType, // requested type | 450 &data)) { |
430 &type, | |
431 &format, | |
432 &count, | |
433 &bytes_after, | |
434 &data) != Success) { | |
435 return false; | 451 return false; |
436 } | 452 } |
437 | 453 |
438 bool result = false; | 454 bool result = false; |
439 if (type == XA_WINDOW && format == 32 && data && count > 0) { | 455 if (type == XA_WINDOW && format == 32 && data && count > 0) { |
440 result = true; | 456 result = true; |
441 XID* stack = reinterpret_cast<XID*>(data); | 457 XID* stack = reinterpret_cast<XID*>(data); |
442 for (unsigned long i = 0; i < count; i++) | 458 for (long i = static_cast<long>(count) - 1; i >= 0; i--) |
443 windows->insert(windows->begin(), stack[i]); | 459 windows->push_back(stack[i]); |
444 } | 460 } |
445 | 461 |
446 if (data) | 462 if (data) |
447 XFree(data); | 463 XFree(data); |
448 | 464 |
449 return result; | 465 return result; |
450 } | 466 } |
451 | 467 |
452 void RestackWindow(XID window, XID sibling, bool above) { | 468 void RestackWindow(XID window, XID sibling, bool above) { |
453 XWindowChanges changes; | 469 XWindowChanges changes; |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 | 761 |
746 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, | 762 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, |
747 SubstructureNotifyMask, &event); | 763 SubstructureNotifyMask, &event); |
748 return result == Success; | 764 return result == Success; |
749 } | 765 } |
750 | 766 |
751 void SetDefaultX11ErrorHandlers() { | 767 void SetDefaultX11ErrorHandlers() { |
752 SetX11ErrorHandlers(NULL, NULL); | 768 SetX11ErrorHandlers(NULL, NULL); |
753 } | 769 } |
754 | 770 |
| 771 bool IsX11WindowFullScreen(XID window) { |
| 772 // First check if _NET_WM_STATE property contains _NET_WM_STATE_FULLSCREEN. |
| 773 static Atom atom = gdk_x11_get_xatom_by_name_for_display( |
| 774 gdk_display_get_default(), "_NET_WM_STATE_FULLSCREEN"); |
| 775 |
| 776 std::vector<Atom> atom_properties; |
| 777 if (GetAtomArrayProperty(window, |
| 778 "_NET_WM_STATE", |
| 779 &atom_properties) && |
| 780 std::find(atom_properties.begin(), atom_properties.end(), atom) |
| 781 != atom_properties.end()) |
| 782 return true; |
| 783 |
| 784 // As the last resort, check if the window size is as large as the main |
| 785 // screen. |
| 786 GdkRectangle monitor_rect; |
| 787 gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect); |
| 788 |
| 789 gfx::Rect window_rect; |
| 790 if (!ui::GetWindowRect(window, &window_rect)) |
| 791 return false; |
| 792 |
| 793 return monitor_rect.x == window_rect.x() && |
| 794 monitor_rect.y == window_rect.y() && |
| 795 monitor_rect.width == window_rect.width() && |
| 796 monitor_rect.height == window_rect.height(); |
| 797 } |
| 798 |
755 // ---------------------------------------------------------------------------- | 799 // ---------------------------------------------------------------------------- |
756 // These functions are declared in x11_util_internal.h because they require | 800 // These functions are declared in x11_util_internal.h because they require |
757 // XLib.h to be included, and it conflicts with many other headers. | 801 // XLib.h to be included, and it conflicts with many other headers. |
758 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { | 802 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { |
759 static XRenderPictFormat* pictformat = NULL; | 803 static XRenderPictFormat* pictformat = NULL; |
760 if (pictformat) | 804 if (pictformat) |
761 return pictformat; | 805 return pictformat; |
762 | 806 |
763 // First look for a 32-bit format which ignores the alpha value | 807 // First look for a 32-bit format which ignores the alpha value |
764 XRenderPictFormat templ; | 808 XRenderPictFormat templ; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
871 "X Error detected: serial %lu, error_code %u (%s), " | 915 "X Error detected: serial %lu, error_code %u (%s), " |
872 "request_code %u minor_code %u (%s)", | 916 "request_code %u minor_code %u (%s)", |
873 error_event->serial, error_event->error_code, error_str, | 917 error_event->serial, error_event->error_code, error_str, |
874 error_event->request_code, error_event->minor_code, request_str); | 918 error_event->request_code, error_event->minor_code, request_str); |
875 } | 919 } |
876 // ---------------------------------------------------------------------------- | 920 // ---------------------------------------------------------------------------- |
877 // End of x11_util_internal.h | 921 // End of x11_util_internal.h |
878 | 922 |
879 | 923 |
880 } // namespace ui | 924 } // namespace ui |
OLD | NEW |