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.
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
7 // remains woefully incomplete.
9 #include "ui/base/x/x11_util.h"
20 #include <X11/extensions/shape.h>
21 #include <X11/extensions/XInput2.h>
23 #include "base/bind.h"
24 #include "base/command_line.h"
25 #include "base/debug/trace_event.h"
26 #include "base/logging.h"
27 #include "base/memory/scoped_ptr.h"
28 #include "base/memory/singleton.h"
29 #include "base/message_loop/message_loop.h"
30 #include "base/metrics/histogram.h"
31 #include "base/strings/string_number_conversions.h"
32 #include "base/strings/string_util.h"
33 #include "base/strings/stringprintf.h"
34 #include "base/sys_byteorder.h"
35 #include "base/threading/thread.h"
36 #include "base/x11/x11_error_tracker.h"
37 #include "third_party/skia/include/core/SkBitmap.h"
38 #include "third_party/skia/include/core/SkPostConfig.h"
39 #include "ui/base/x/x11_util_internal.h"
40 #include "ui/events/event_utils.h"
41 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
42 #include "ui/events/x/device_data_manager.h"
43 #include "ui/events/x/touch_factory_x11.h"
44 #include "ui/gfx/canvas.h"
45 #include "ui/gfx/image/image_skia.h"
46 #include "ui/gfx/image/image_skia_rep.h"
47 #include "ui/gfx/point.h"
48 #include "ui/gfx/point_conversions.h"
49 #include "ui/gfx/rect.h"
50 #include "ui/gfx/size.h"
52 #if defined(OS_FREEBSD)
53 #include <sys/sysctl.h>
54 #include <sys/types.h>
58 #include <X11/Xcursor/Xcursor.h>
59 #include "skia/ext/image_operations.h"
60 #include "ui/gfx/skia_util.h"
63 #if defined(TOOLKIT_GTK)
66 #include "ui/gfx/gdk_compat.h"
67 #include "ui/gfx/gtk_compat.h"
74 // Used to cache the XRenderPictFormat for a visual/display pair.
75 struct CachedPictFormat {
76 bool equals(XDisplay* display, Visual* visual) const {
77 return display == this->display && visual == this->visual;
82 XRenderPictFormat* format;
85 typedef std::list<CachedPictFormat> CachedPictFormats;
87 // Returns the cache of pict formats.
88 CachedPictFormats* get_cached_pict_formats() {
89 static CachedPictFormats* formats = NULL;
91 formats = new CachedPictFormats();
95 // Maximum number of CachedPictFormats we keep around.
96 const size_t kMaxCacheSize = 5;
98 int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
99 if (base::MessageLoop::current()) {
100 base::MessageLoop::current()->PostTask(
101 FROM_HERE, base::Bind(&LogErrorEventDescription, d, *e));
104 << "X error received: "
105 << "serial " << e->serial << ", "
106 << "error_code " << static_cast<int>(e->error_code) << ", "
107 << "request_code " << static_cast<int>(e->request_code) << ", "
108 << "minor_code " << static_cast<int>(e->minor_code);
113 int DefaultX11IOErrorHandler(XDisplay* d) {
114 // If there's an IO error it likely means the X server has gone away
115 LOG(ERROR) << "X IO error received (X server probably went away)";
119 // Note: The caller should free the resulting value data.
120 bool GetProperty(XID window, const std::string& property_name, long max_length,
121 Atom* type, int* format, unsigned long* num_items,
122 unsigned char** property) {
123 Atom property_atom = GetAtom(property_name.c_str());
124 unsigned long remaining_bytes = 0;
125 return XGetWindowProperty(gfx::GetXDisplay(),
128 0, // offset into property data to read
129 max_length, // max length to get
139 // A process wide singleton that manages the usage of X cursors.
147 ::Cursor GetCursor(int cursor_shape) {
148 // Lookup cursor by attempting to insert a null value, which avoids
149 // a second pass through the map after a cache miss.
150 std::pair<std::map<int, ::Cursor>::iterator, bool> it = cache_.insert(
151 std::make_pair(cursor_shape, 0));
153 XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
154 it.first->second = XCreateFontCursor(display, cursor_shape);
156 return it.first->second;
160 XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
161 for (std::map<int, ::Cursor>::iterator it =
162 cache_.begin(); it != cache_.end(); ++it) {
163 XFreeCursor(display, it->second);
169 // Maps X11 font cursor shapes to Cursor IDs.
170 std::map<int, ::Cursor> cache_;
172 DISALLOW_COPY_AND_ASSIGN(XCursorCache);
175 XCursorCache* cursor_cache = NULL;
177 #if defined(USE_AURA)
178 // A process wide singleton cache for custom X cursors.
179 class XCustomCursorCache {
181 static XCustomCursorCache* GetInstance() {
182 return Singleton<XCustomCursorCache>::get();
185 ::Cursor InstallCustomCursor(XcursorImage* image) {
186 XCustomCursor* custom_cursor = new XCustomCursor(image);
187 ::Cursor xcursor = custom_cursor->cursor();
188 cache_[xcursor] = custom_cursor;
192 void Ref(::Cursor cursor) {
193 cache_[cursor]->Ref();
196 void Unref(::Cursor cursor) {
197 if (cache_[cursor]->Unref())
198 cache_.erase(cursor);
206 friend struct DefaultSingletonTraits<XCustomCursorCache>;
208 class XCustomCursor {
210 // This takes ownership of the image.
211 XCustomCursor(XcursorImage* image)
214 cursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image);
218 XcursorImageDestroy(image_);
219 XFreeCursor(gfx::GetXDisplay(), cursor_);
222 ::Cursor cursor() const { return cursor_; }
228 // Returns true if the cursor was destroyed because of the unref.
238 XcursorImage* image_;
242 DISALLOW_COPY_AND_ASSIGN(XCustomCursor);
245 XCustomCursorCache() {}
246 ~XCustomCursorCache() {
250 std::map< ::Cursor, XCustomCursor*> cache_;
251 DISALLOW_COPY_AND_ASSIGN(XCustomCursorCache);
253 #endif // defined(USE_AURA)
255 bool IsShapeAvailable() {
257 static bool is_shape_available =
258 XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy);
259 return is_shape_available;
263 // A list of bogus sizes in mm that X detects that should be ignored.
264 // See crbug.com/136533. The first element maintains the minimum
265 // size required to be valid size.
266 const unsigned long kInvalidDisplaySizeList[][2] = {
275 bool XDisplayExists() {
276 return (gfx::GetXDisplay() != NULL);
279 bool IsXInput2Available() {
280 return DeviceDataManager::GetInstance()->IsXInput2Available();
283 static SharedMemorySupport DoQuerySharedMemorySupport(XDisplay* dpy) {
285 Bool pixmaps_supported;
286 // Query the server's support for XSHM.
287 if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
288 return SHARED_MEMORY_NONE;
290 #if defined(OS_FREEBSD)
291 // On FreeBSD we can't access the shared memory after it was marked for
292 // deletion, unless this behaviour is explicitly enabled by the user.
293 // In case it's not enabled disable shared memory support.
295 size_t length = sizeof(allow_removed);
297 if ((sysctlbyname("kern.ipc.shm_allow_removed", &allow_removed, &length,
298 NULL, 0) < 0) || allow_removed < 1) {
299 return SHARED_MEMORY_NONE;
303 // Next we probe to see if shared memory will really work
304 int shmkey = shmget(IPC_PRIVATE, 1, 0600);
306 LOG(WARNING) << "Failed to get shared memory segment.";
307 return SHARED_MEMORY_NONE;
309 VLOG(1) << "Got shared memory segment " << shmkey;
312 void* address = shmat(shmkey, NULL, 0);
313 // Mark the shared memory region for deletion
314 shmctl(shmkey, IPC_RMID, NULL);
316 XShmSegmentInfo shminfo;
317 memset(&shminfo, 0, sizeof(shminfo));
318 shminfo.shmid = shmkey;
320 base::X11ErrorTracker err_tracker;
321 bool result = XShmAttach(dpy, &shminfo);
323 VLOG(1) << "X got shared memory segment " << shmkey;
325 LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
326 if (err_tracker.FoundNewError())
330 LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
331 return SHARED_MEMORY_NONE;
334 VLOG(1) << "X attached to shared memory segment " << shmkey;
336 XShmDetach(dpy, &shminfo);
337 return pixmaps_supported ? SHARED_MEMORY_PIXMAP : SHARED_MEMORY_PUTIMAGE;
340 SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy) {
341 static SharedMemorySupport shared_memory_support = SHARED_MEMORY_NONE;
342 static bool shared_memory_support_cached = false;
344 if (shared_memory_support_cached)
345 return shared_memory_support;
347 shared_memory_support = DoQuerySharedMemorySupport(dpy);
348 shared_memory_support_cached = true;
350 return shared_memory_support;
353 bool QueryRenderSupport(XDisplay* dpy) {
354 static bool render_supported = false;
355 static bool render_supported_cached = false;
357 if (render_supported_cached)
358 return render_supported;
360 // We don't care about the version of Xrender since all the features which
361 // we use are included in every version.
363 render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
364 render_supported_cached = true;
366 return render_supported;
369 int GetDefaultScreen(XDisplay* display) {
370 return XDefaultScreen(display);
373 ::Cursor GetXCursor(int cursor_shape) {
375 cursor_cache = new XCursorCache;
376 return cursor_cache->GetCursor(cursor_shape);
379 void ResetXCursorCache() {
384 #if defined(USE_AURA)
385 ::Cursor CreateReffedCustomXCursor(XcursorImage* image) {
386 return XCustomCursorCache::GetInstance()->InstallCustomCursor(image);
389 void RefCustomXCursor(::Cursor cursor) {
390 XCustomCursorCache::GetInstance()->Ref(cursor);
393 void UnrefCustomXCursor(::Cursor cursor) {
394 XCustomCursorCache::GetInstance()->Unref(cursor);
397 XcursorImage* SkBitmapToXcursorImage(const SkBitmap* cursor_image,
398 const gfx::Point& hotspot) {
399 DCHECK(cursor_image->config() == SkBitmap::kARGB_8888_Config);
400 gfx::Point hotspot_point = hotspot;
403 // X11 seems to have issues with cursors when images get larger than 64
404 // pixels. So rescale the image if necessary.
405 const float kMaxPixel = 64.f;
406 bool needs_scale = false;
407 if (cursor_image->width() > kMaxPixel || cursor_image->height() > kMaxPixel) {
409 if (cursor_image->width() > cursor_image->height())
410 scale = kMaxPixel / cursor_image->width();
412 scale = kMaxPixel / cursor_image->height();
414 scaled = skia::ImageOperations::Resize(*cursor_image,
415 skia::ImageOperations::RESIZE_BETTER,
416 static_cast<int>(cursor_image->width() * scale),
417 static_cast<int>(cursor_image->height() * scale));
418 hotspot_point = gfx::ToFlooredPoint(gfx::ScalePoint(hotspot, scale));
422 const SkBitmap* bitmap = needs_scale ? &scaled : cursor_image;
423 XcursorImage* image = XcursorImageCreate(bitmap->width(), bitmap->height());
424 image->xhot = std::min(bitmap->width() - 1, hotspot_point.x());
425 image->yhot = std::min(bitmap->height() - 1, hotspot_point.y());
427 if (bitmap->width() && bitmap->height()) {
428 bitmap->lockPixels();
429 // The |bitmap| contains ARGB image, so just copy it.
430 memcpy(image->pixels,
432 bitmap->width() * bitmap->height() * 4);
433 bitmap->unlockPixels();
440 int CoalescePendingMotionEvents(const XEvent* xev,
441 XEvent* last_event) {
442 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
443 int num_coalesced = 0;
444 XDisplay* display = xev->xany.display;
445 int event_type = xev->xgeneric.evtype;
447 DCHECK(event_type == XI_Motion || event_type == XI_TouchUpdate);
449 while (XPending(display)) {
451 XPeekEvent(display, &next_event);
453 // If we can't get the cookie, abort the check.
454 if (!XGetEventData(next_event.xgeneric.display, &next_event.xcookie))
455 return num_coalesced;
457 // If this isn't from a valid device, throw the event away, as
458 // that's what the message pump would do. Device events come in pairs
459 // with one from the master and one from the slave so there will
460 // always be at least one pending.
461 if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(&next_event)) {
462 XFreeEventData(display, &next_event.xcookie);
463 XNextEvent(display, &next_event);
467 if (next_event.type == GenericEvent &&
468 next_event.xgeneric.evtype == event_type &&
469 !ui::DeviceDataManager::GetInstance()->IsCMTGestureEvent(
471 XIDeviceEvent* next_xievent =
472 static_cast<XIDeviceEvent*>(next_event.xcookie.data);
473 // Confirm that the motion event is targeted at the same window
474 // and that no buttons or modifiers have changed.
475 if (xievent->event == next_xievent->event &&
476 xievent->child == next_xievent->child &&
477 xievent->detail == next_xievent->detail &&
478 xievent->buttons.mask_len == next_xievent->buttons.mask_len &&
479 (memcmp(xievent->buttons.mask,
480 next_xievent->buttons.mask,
481 xievent->buttons.mask_len) == 0) &&
482 xievent->mods.base == next_xievent->mods.base &&
483 xievent->mods.latched == next_xievent->mods.latched &&
484 xievent->mods.locked == next_xievent->mods.locked &&
485 xievent->mods.effective == next_xievent->mods.effective) {
486 XFreeEventData(display, &next_event.xcookie);
487 // Free the previous cookie.
488 if (num_coalesced > 0)
489 XFreeEventData(display, &last_event->xcookie);
490 // Get the event and its cookie data.
491 XNextEvent(display, last_event);
492 XGetEventData(display, &last_event->xcookie);
497 // This isn't an event we want so free its cookie data.
498 XFreeEventData(display, &next_event.xcookie);
502 if (event_type == XI_Motion && num_coalesced > 0) {
503 base::TimeDelta delta = ui::EventTimeFromNative(last_event) -
504 ui::EventTimeFromNative(const_cast<XEvent*>(xev));
505 UMA_HISTOGRAM_COUNTS_10000("Event.CoalescedCount.Mouse", num_coalesced);
506 UMA_HISTOGRAM_TIMES("Event.CoalescedLatency.Mouse", delta);
508 return num_coalesced;
512 void HideHostCursor() {
513 CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
514 (CreateInvisibleCursor(), gfx::GetXDisplay()));
515 XDefineCursor(gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()),
516 invisible_cursor.get());
519 ::Cursor CreateInvisibleCursor() {
520 XDisplay* xdisplay = gfx::GetXDisplay();
521 ::Cursor invisible_cursor;
522 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
524 black.red = black.green = black.blue = 0;
525 Pixmap blank = XCreateBitmapFromData(xdisplay,
526 DefaultRootWindow(xdisplay),
528 invisible_cursor = XCreatePixmapCursor(xdisplay, blank, blank,
529 &black, &black, 0, 0);
530 XFreePixmap(xdisplay, blank);
531 return invisible_cursor;
534 XID GetX11RootWindow() {
535 return DefaultRootWindow(gfx::GetXDisplay());
538 bool GetCurrentDesktop(int* desktop) {
539 return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
542 #if defined(TOOLKIT_GTK)
543 XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
544 return GDK_WINDOW_XID(gtk_widget_get_window(widget));
547 XID GetX11WindowFromGdkWindow(GdkWindow* window) {
548 return GDK_WINDOW_XID(window);
551 GtkWindow* GetGtkWindowFromX11Window(XID xid) {
552 GdkWindow* gdk_window =
553 gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);
556 GtkWindow* gtk_window = NULL;
557 gdk_window_get_user_data(gdk_window,
558 reinterpret_cast<gpointer*>(>k_window));
564 void* GetVisualFromGtkWidget(GtkWidget* widget) {
565 return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
567 #endif // defined(TOOLKIT_GTK)
569 void SetHideTitlebarWhenMaximizedProperty(XID window,
570 HideTitlebarWhenMaximized property) {
571 // XChangeProperty() expects "hide" to be long.
572 unsigned long hide = property;
573 XChangeProperty(gfx::GetXDisplay(),
575 GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
579 reinterpret_cast<unsigned char*>(&hide),
583 void ClearX11DefaultRootWindow() {
584 XDisplay* display = gfx::GetXDisplay();
585 XID root_window = GetX11RootWindow();
586 gfx::Rect root_bounds;
587 if (!GetWindowRect(root_window, &root_bounds)) {
588 LOG(ERROR) << "Failed to get the bounds of the X11 root window";
592 XGCValues gc_values = {0};
593 gc_values.foreground = BlackPixel(display, DefaultScreen(display));
594 GC gc = XCreateGC(display, root_window, GCForeground, &gc_values);
595 XFillRectangle(display, root_window, gc,
599 root_bounds.height());
600 XFreeGC(display, gc);
603 bool IsWindowVisible(XID window) {
604 TRACE_EVENT0("ui", "IsWindowVisible");
606 XWindowAttributes win_attributes;
607 if (!XGetWindowAttributes(gfx::GetXDisplay(), window, &win_attributes))
609 if (win_attributes.map_state != IsViewable)
611 // Some compositing window managers (notably kwin) do not actually unmap
612 // windows on desktop switch, so we also must check the current desktop.
613 int window_desktop, current_desktop;
614 return (!GetWindowDesktop(window, &window_desktop) ||
615 !GetCurrentDesktop(¤t_desktop) ||
616 window_desktop == kAllDesktops ||
617 window_desktop == current_desktop);
620 bool GetWindowRect(XID window, gfx::Rect* rect) {
623 unsigned int width, height;
624 unsigned int border_width, depth;
626 if (!XGetGeometry(gfx::GetXDisplay(), window, &root, &x, &y,
627 &width, &height, &border_width, &depth))
630 if (!XTranslateCoordinates(gfx::GetXDisplay(), window, root,
631 0, 0, &x, &y, &child))
634 *rect = gfx::Rect(x, y, width, height);
639 bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
640 TRACE_EVENT0("ui", "WindowContainsPoint");
642 gfx::Rect window_rect;
643 if (!GetWindowRect(window, &window_rect))
646 if (!window_rect.Contains(screen_loc))
649 if (!IsShapeAvailable())
652 // According to http://www.x.org/releases/X11R7.6/doc/libXext/shapelib.html,
653 // if an X display supports the shape extension the bounds of a window are
654 // defined as the intersection of the window bounds and the interior
655 // rectangles. This means to determine if a point is inside a window for the
656 // purpose of input handling we have to check the rectangles in the ShapeInput
658 // According to http://www.x.org/releases/current/doc/xextproto/shape.html,
659 // we need to also respect the ShapeBounding rectangles.
660 // The effective input region of a window is defined to be the intersection
661 // of the client input region with both the default input region and the
662 // client bounding region. Any portion of the client input region that is not
663 // included in both the default input region and the client bounding region
664 // will not be included in the effective input region on the screen.
665 int rectangle_kind[] = {ShapeInput, ShapeBounding};
666 for (size_t kind_index = 0;
667 kind_index < arraysize(rectangle_kind);
670 int shape_rects_size = 0;
671 XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
673 rectangle_kind[kind_index],
678 bool is_in_shape_rects = false;
679 for (int i = 0; i < shape_rects_size; ++i) {
680 // The ShapeInput and ShapeBounding rects are to be in window space, so we
681 // have to translate by the window_rect's offset to map to screen space.
682 gfx::Rect shape_rect =
683 gfx::Rect(shape_rects[i].x + window_rect.x(),
684 shape_rects[i].y + window_rect.y(),
685 shape_rects[i].width, shape_rects[i].height);
686 if (shape_rect.Contains(screen_loc)) {
687 is_in_shape_rects = true;
692 if (!is_in_shape_rects)
699 bool PropertyExists(XID window, const std::string& property_name) {
701 int format = 0; // size in bits of each item in 'property'
702 unsigned long num_items = 0;
703 unsigned char* property = NULL;
705 int result = GetProperty(window, property_name, 1,
706 &type, &format, &num_items, &property);
707 if (result != Success)
711 return num_items > 0;
714 bool GetRawBytesOfProperty(XID window,
716 scoped_refptr<base::RefCountedMemory>* out_data,
717 size_t* out_data_bytes,
718 size_t* out_data_items,
720 // Retrieve the data from our window.
721 unsigned long nitems = 0;
722 unsigned long nbytes = 0;
723 Atom prop_type = None;
725 unsigned char* property_data = NULL;
726 if (XGetWindowProperty(gfx::GetXDisplay(), window, property,
727 0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
728 AnyPropertyType, &prop_type, &prop_format,
729 &nitems, &nbytes, &property_data) != Success) {
733 if (prop_type == None)
737 // So even though we should theoretically have nbytes (and we can't
738 // pass NULL there), we need to manually calculate the byte length here
739 // because nbytes always returns zero.
740 switch (prop_format) {
745 bytes = sizeof(short) * nitems;
748 bytes = sizeof(long) * nitems;
756 *out_data_bytes = bytes;
759 *out_data = new XRefcountedMemory(property_data, bytes);
761 XFree(property_data);
764 *out_data_items = nitems;
767 *out_type = prop_type;
772 bool GetIntProperty(XID window, const std::string& property_name, int* value) {
774 int format = 0; // size in bits of each item in 'property'
775 unsigned long num_items = 0;
776 unsigned char* property = NULL;
778 int result = GetProperty(window, property_name, 1,
779 &type, &format, &num_items, &property);
780 if (result != Success)
783 if (format != 32 || num_items != 1) {
788 *value = static_cast<int>(*(reinterpret_cast<long*>(property)));
793 bool GetXIDProperty(XID window, const std::string& property_name, XID* value) {
795 int format = 0; // size in bits of each item in 'property'
796 unsigned long num_items = 0;
797 unsigned char* property = NULL;
799 int result = GetProperty(window, property_name, 1,
800 &type, &format, &num_items, &property);
801 if (result != Success)
804 if (format != 32 || num_items != 1) {
809 *value = *(reinterpret_cast<XID*>(property));
814 bool GetIntArrayProperty(XID window,
815 const std::string& property_name,
816 std::vector<int>* value) {
818 int format = 0; // size in bits of each item in 'property'
819 unsigned long num_items = 0;
820 unsigned char* properties = NULL;
822 int result = GetProperty(window, property_name,
823 (~0L), // (all of them)
824 &type, &format, &num_items, &properties);
825 if (result != Success)
833 long* int_properties = reinterpret_cast<long*>(properties);
835 for (unsigned long i = 0; i < num_items; ++i) {
836 value->push_back(static_cast<int>(int_properties[i]));
842 bool GetAtomArrayProperty(XID window,
843 const std::string& property_name,
844 std::vector<Atom>* value) {
846 int format = 0; // size in bits of each item in 'property'
847 unsigned long num_items = 0;
848 unsigned char* properties = NULL;
850 int result = GetProperty(window, property_name,
851 (~0L), // (all of them)
852 &type, &format, &num_items, &properties);
853 if (result != Success)
856 if (type != XA_ATOM) {
861 Atom* atom_properties = reinterpret_cast<Atom*>(properties);
863 value->insert(value->begin(), atom_properties, atom_properties + num_items);
868 bool GetStringProperty(
869 XID window, const std::string& property_name, std::string* value) {
871 int format = 0; // size in bits of each item in 'property'
872 unsigned long num_items = 0;
873 unsigned char* property = NULL;
875 int result = GetProperty(window, property_name, 1024,
876 &type, &format, &num_items, &property);
877 if (result != Success)
885 value->assign(reinterpret_cast<char*>(property), num_items);
890 bool SetIntProperty(XID window,
891 const std::string& name,
892 const std::string& type,
894 std::vector<int> values(1, value);
895 return SetIntArrayProperty(window, name, type, values);
898 bool SetIntArrayProperty(XID window,
899 const std::string& name,
900 const std::string& type,
901 const std::vector<int>& value) {
902 DCHECK(!value.empty());
903 Atom name_atom = GetAtom(name.c_str());
904 Atom type_atom = GetAtom(type.c_str());
906 // XChangeProperty() expects values of type 32 to be longs.
907 scoped_ptr<long[]> data(new long[value.size()]);
908 for (size_t i = 0; i < value.size(); ++i)
911 base::X11ErrorTracker err_tracker;
912 XChangeProperty(gfx::GetXDisplay(),
916 32, // size in bits of items in 'value'
918 reinterpret_cast<const unsigned char*>(data.get()),
919 value.size()); // num items
920 return !err_tracker.FoundNewError();
923 bool SetAtomArrayProperty(XID window,
924 const std::string& name,
925 const std::string& type,
926 const std::vector<Atom>& value) {
927 DCHECK(!value.empty());
928 Atom name_atom = GetAtom(name.c_str());
929 Atom type_atom = GetAtom(type.c_str());
931 // XChangeProperty() expects values of type 32 to be longs.
932 scoped_ptr<Atom[]> data(new Atom[value.size()]);
933 for (size_t i = 0; i < value.size(); ++i)
936 base::X11ErrorTracker err_tracker;
937 XChangeProperty(gfx::GetXDisplay(),
941 32, // size in bits of items in 'value'
943 reinterpret_cast<const unsigned char*>(data.get()),
944 value.size()); // num items
945 return !err_tracker.FoundNewError();
948 Atom GetAtom(const char* name) {
949 #if defined(TOOLKIT_GTK)
950 return gdk_x11_get_xatom_by_name_for_display(
951 gdk_display_get_default(), name);
953 // TODO(derat): Cache atoms to avoid round-trips to the server.
954 return XInternAtom(gfx::GetXDisplay(), name, false);
958 void SetWindowClassHint(XDisplay* display,
960 const std::string& res_name,
961 const std::string& res_class) {
962 XClassHint class_hints;
963 // const_cast is safe because XSetClassHint does not modify the strings.
964 // Just to be safe, the res_name and res_class parameters are local copies,
965 // not const references.
966 class_hints.res_name = const_cast<char*>(res_name.c_str());
967 class_hints.res_class = const_cast<char*>(res_class.c_str());
968 XSetClassHint(display, window, &class_hints);
971 void SetWindowRole(XDisplay* display, XID window, const std::string& role) {
973 XDeleteProperty(display, window, GetAtom("WM_WINDOW_ROLE"));
975 char* role_c = const_cast<char*>(role.c_str());
976 XChangeProperty(display, window, GetAtom("WM_WINDOW_ROLE"), XA_STRING, 8,
978 reinterpret_cast<unsigned char*>(role_c),
983 XID GetParentWindow(XID window) {
986 XID* children = NULL;
987 unsigned int num_children = 0;
988 XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children, &num_children);
994 XID GetHighestAncestorWindow(XID window, XID root) {
996 XID parent = GetParentWindow(window);
1005 bool GetWindowDesktop(XID window, int* desktop) {
1006 return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
1009 std::string GetX11ErrorString(XDisplay* display, int err) {
1011 XGetErrorText(display, err, buffer, arraysize(buffer));
1015 // Returns true if |window| is a named window.
1016 bool IsWindowNamed(XID window) {
1018 if (!XGetWMName(gfx::GetXDisplay(), window, &prop) || !prop.value)
1025 bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
1026 const int max_depth, int depth) {
1027 if (depth > max_depth)
1030 XID root, parent, *children;
1031 unsigned int num_children;
1032 int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children,
1037 std::vector<XID> windows;
1038 for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
1039 windows.push_back(children[i]);
1043 // XQueryTree returns the children of |window| in bottom-to-top order, so
1044 // reverse-iterate the list to check the windows from top-to-bottom.
1045 std::vector<XID>::iterator iter;
1046 for (iter = windows.begin(); iter != windows.end(); iter++) {
1047 if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
1051 // If we're at this point, we didn't find the window we're looking for at the
1052 // current level, so we need to recurse to the next level. We use a second
1053 // loop because the recursion and call to XQueryTree are expensive and is only
1054 // needed for a small number of cases.
1055 if (++depth <= max_depth) {
1056 for (iter = windows.begin(); iter != windows.end(); iter++) {
1057 if (EnumerateChildren(delegate, *iter, max_depth, depth))
1065 bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
1066 XID root = GetX11RootWindow();
1067 return EnumerateChildren(delegate, root, max_depth, 0);
1070 void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
1071 std::vector<XID> stack;
1072 if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
1073 // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
1074 // to old school enumeration of all X windows. Some WMs parent 'top-level'
1075 // windows in unnamed actual top-level windows (ion WM), so extend the
1076 // search depth to all children of top-level windows.
1077 const int kMaxSearchDepth = 1;
1078 ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
1082 std::vector<XID>::iterator iter;
1083 for (iter = stack.begin(); iter != stack.end(); iter++) {
1084 if (delegate->ShouldStopIterating(*iter))
1089 bool GetXWindowStack(Window window, std::vector<XID>* windows) {
1094 unsigned long count;
1095 unsigned char *data = NULL;
1096 if (GetProperty(window,
1097 "_NET_CLIENT_LIST_STACKING",
1102 &data) != Success) {
1106 bool result = false;
1107 if (type == XA_WINDOW && format == 32 && data && count > 0) {
1109 XID* stack = reinterpret_cast<XID*>(data);
1110 for (long i = static_cast<long>(count) - 1; i >= 0; i--)
1111 windows->push_back(stack[i]);
1120 void RestackWindow(XID window, XID sibling, bool above) {
1121 XWindowChanges changes;
1122 changes.sibling = sibling;
1123 changes.stack_mode = above ? Above : Below;
1124 XConfigureWindow(gfx::GetXDisplay(), window, CWSibling | CWStackMode, &changes);
1127 XSharedMemoryId AttachSharedMemory(XDisplay* display, int shared_memory_key) {
1128 DCHECK(QuerySharedMemorySupport(display));
1130 XShmSegmentInfo shminfo;
1131 memset(&shminfo, 0, sizeof(shminfo));
1132 shminfo.shmid = shared_memory_key;
1134 // This function is only called if QuerySharedMemorySupport returned true. In
1135 // which case we've already succeeded in having the X server attach to one of
1136 // our shared memory segments.
1137 if (!XShmAttach(display, &shminfo)) {
1138 LOG(WARNING) << "X failed to attach to shared memory segment "
1142 VLOG(1) << "X attached to shared memory segment " << shminfo.shmid;
1145 return shminfo.shmseg;
1148 void DetachSharedMemory(XDisplay* display, XSharedMemoryId shmseg) {
1149 DCHECK(QuerySharedMemorySupport(display));
1151 XShmSegmentInfo shminfo;
1152 memset(&shminfo, 0, sizeof(shminfo));
1153 shminfo.shmseg = shmseg;
1155 if (!XShmDetach(display, &shminfo))
1159 bool CopyAreaToCanvas(XID drawable,
1160 gfx::Rect source_bounds,
1161 gfx::Point dest_offset,
1162 gfx::Canvas* canvas) {
1163 ui::XScopedImage scoped_image(
1164 XGetImage(gfx::GetXDisplay(), drawable,
1165 source_bounds.x(), source_bounds.y(),
1166 source_bounds.width(), source_bounds.height(),
1167 AllPlanes, ZPixmap));
1168 XImage* image = scoped_image.get();
1170 LOG(ERROR) << "XGetImage failed";
1174 if (image->bits_per_pixel == 32) {
1175 if ((0xff << SK_R32_SHIFT) != image->red_mask ||
1176 (0xff << SK_G32_SHIFT) != image->green_mask ||
1177 (0xff << SK_B32_SHIFT) != image->blue_mask) {
1178 LOG(WARNING) << "XImage and Skia byte orders differ";
1182 // Set the alpha channel before copying to the canvas. Otherwise, areas of
1183 // the framebuffer that were cleared by ply-image rather than being obscured
1184 // by an image during boot may end up transparent.
1185 // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
1186 // set the framebuffer's alpha channel regardless of whether the device
1187 // claims to support alpha or not.
1188 for (int i = 0; i < image->width * image->height * 4; i += 4)
1189 image->data[i + 3] = 0xff;
1192 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
1193 image->width, image->height,
1194 image->bytes_per_line);
1195 bitmap.setPixels(image->data);
1196 gfx::ImageSkia image_skia;
1197 gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
1198 image_skia.AddRepresentation(image_rep);
1199 canvas->DrawImageInt(image_skia, dest_offset.x(), dest_offset.y());
1201 NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
1208 XID CreatePictureFromSkiaPixmap(XDisplay* display, XID pixmap) {
1209 XID picture = XRenderCreatePicture(
1210 display, pixmap, GetRenderARGB32Format(display), 0, NULL);
1215 void FreePicture(XDisplay* display, XID picture) {
1216 XRenderFreePicture(display, picture);
1219 void FreePixmap(XDisplay* display, XID pixmap) {
1220 XFreePixmap(display, pixmap);
1223 bool GetWindowManagerName(std::string* wm_name) {
1226 if (!GetIntProperty(GetX11RootWindow(),
1227 "_NET_SUPPORTING_WM_CHECK",
1232 // It's possible that a window manager started earlier in this X session left
1233 // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
1234 // non-EWMH window manager, so we trap errors in the following requests to
1235 // avoid crashes (issue 23860).
1237 // EWMH requires the supporting-WM window to also have a
1238 // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
1239 // property referencing an ID that's been recycled for another window), so we
1241 base::X11ErrorTracker err_tracker;
1242 int wm_window_property = 0;
1243 bool result = GetIntProperty(
1244 wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
1245 if (err_tracker.FoundNewError() || !result ||
1246 wm_window_property != wm_window) {
1250 result = GetStringProperty(
1251 static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
1252 return !err_tracker.FoundNewError() && result;
1255 WindowManagerName GuessWindowManager() {
1257 if (GetWindowManagerName(&name)) {
1258 // These names are taken from the WMs' source code.
1259 if (name == "Blackbox")
1261 if (name == "chromeos-wm")
1262 return WM_CHROME_OS;
1263 if (name == "Compiz" || name == "compiz")
1266 return WM_ENLIGHTENMENT;
1267 if (StartsWithASCII(name, "IceWM", true))
1271 if (name == "Metacity")
1273 if (name == "Mutter (Muffin)")
1275 if (name == "GNOME Shell")
1276 return WM_MUTTER; // GNOME Shell uses Mutter
1277 if (name == "Mutter")
1279 if (name == "Openbox")
1281 if (name == "Xfwm4")
1287 bool ChangeWindowDesktop(XID window, XID destination) {
1289 if (!GetWindowDesktop(destination, &desktop))
1292 // If |window| is sticky, use the current desktop.
1293 if (desktop == kAllDesktops &&
1294 !GetCurrentDesktop(&desktop))
1298 event.xclient.type = ClientMessage;
1299 event.xclient.window = window;
1300 event.xclient.message_type = GetAtom("_NET_WM_DESKTOP");
1301 event.xclient.format = 32;
1302 event.xclient.data.l[0] = desktop;
1303 event.xclient.data.l[1] = 1; // source indication
1305 int result = XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), False,
1306 SubstructureNotifyMask, &event);
1307 return result == Success;
1310 void SetDefaultX11ErrorHandlers() {
1311 SetX11ErrorHandlers(NULL, NULL);
1314 bool IsX11WindowFullScreen(XID window) {
1315 // If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
1316 // absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
1317 // whether we're fullscreen.
1318 std::vector<Atom> supported_atoms;
1319 if (GetAtomArrayProperty(GetX11RootWindow(),
1321 &supported_atoms)) {
1322 Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
1324 if (std::find(supported_atoms.begin(), supported_atoms.end(), atom)
1325 != supported_atoms.end()) {
1326 std::vector<Atom> atom_properties;
1327 if (GetAtomArrayProperty(window,
1329 &atom_properties)) {
1330 return std::find(atom_properties.begin(), atom_properties.end(), atom)
1331 != atom_properties.end();
1336 gfx::Rect window_rect;
1337 if (!ui::GetWindowRect(window, &window_rect))
1340 #if defined(TOOLKIT_GTK)
1341 // As the last resort, check if the window size is as large as the main
1343 GdkRectangle monitor_rect;
1344 gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect);
1346 return monitor_rect.x == window_rect.x() &&
1347 monitor_rect.y == window_rect.y() &&
1348 monitor_rect.width == window_rect.width() &&
1349 monitor_rect.height == window_rect.height();
1351 // We can't use gfx::Screen here because we don't have an aura::Window. So
1352 // instead just look at the size of the default display.
1354 // TODO(erg): Actually doing this correctly would require pulling out xrandr,
1355 // which we don't even do in the desktop screen yet.
1356 ::XDisplay* display = gfx::GetXDisplay();
1357 ::Screen* screen = DefaultScreenOfDisplay(display);
1358 int width = WidthOfScreen(screen);
1359 int height = HeightOfScreen(screen);
1360 return window_rect.size() == gfx::Size(width, height);
1364 bool IsXDisplaySizeBlackListed(unsigned long mm_width,
1365 unsigned long mm_height) {
1366 // Ignore if the reported display is smaller than minimum size.
1367 if (mm_width <= kInvalidDisplaySizeList[0][0] ||
1368 mm_height <= kInvalidDisplaySizeList[0][1]) {
1369 LOG(WARNING) << "Smaller than minimum display size";
1372 for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
1373 const unsigned long* size = kInvalidDisplaySizeList[i];
1374 if (mm_width == size[0] && mm_height == size[1]) {
1375 LOG(WARNING) << "Black listed display size detected:"
1376 << size[0] << "x" << size[1];
1383 const unsigned char* XRefcountedMemory::front() const {
1387 size_t XRefcountedMemory::size() const {
1391 XRefcountedMemory::~XRefcountedMemory() {
1395 XScopedString::~XScopedString() {
1399 XScopedImage::~XScopedImage() {
1403 void XScopedImage::reset(XImage* image) {
1404 if (image_ == image)
1407 XDestroyImage(image_);
1411 XScopedCursor::XScopedCursor(::Cursor cursor, XDisplay* display)
1416 XScopedCursor::~XScopedCursor() {
1420 ::Cursor XScopedCursor::get() const {
1424 void XScopedCursor::reset(::Cursor cursor) {
1426 XFreeCursor(display_, cursor_);
1430 // ----------------------------------------------------------------------------
1431 // These functions are declared in x11_util_internal.h because they require
1432 // XLib.h to be included, and it conflicts with many other headers.
1433 XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
1434 static XRenderPictFormat* pictformat = NULL;
1438 // First look for a 32-bit format which ignores the alpha value
1439 XRenderPictFormat templ;
1441 templ.type = PictTypeDirect;
1442 templ.direct.red = 16;
1443 templ.direct.green = 8;
1444 templ.direct.blue = 0;
1445 templ.direct.redMask = 0xff;
1446 templ.direct.greenMask = 0xff;
1447 templ.direct.blueMask = 0xff;
1448 templ.direct.alphaMask = 0;
1450 static const unsigned long kMask =
1451 PictFormatType | PictFormatDepth |
1452 PictFormatRed | PictFormatRedMask |
1453 PictFormatGreen | PictFormatGreenMask |
1454 PictFormatBlue | PictFormatBlueMask |
1455 PictFormatAlphaMask;
1457 pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
1460 // Not all X servers support xRGB32 formats. However, the XRENDER spec says
1461 // that they must support an ARGB32 format, so we can always return that.
1462 pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
1463 CHECK(pictformat) << "XRENDER ARGB32 not supported.";
1469 XRenderPictFormat* GetRenderVisualFormat(XDisplay* dpy, Visual* visual) {
1470 DCHECK(QueryRenderSupport(dpy));
1472 CachedPictFormats* formats = get_cached_pict_formats();
1474 for (CachedPictFormats::const_iterator i = formats->begin();
1475 i != formats->end(); ++i) {
1476 if (i->equals(dpy, visual))
1480 // Not cached, look up the value.
1481 XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
1482 CHECK(pictformat) << "XRENDER does not support default visual";
1484 // And store it in the cache.
1485 CachedPictFormat cached_value;
1486 cached_value.visual = visual;
1487 cached_value.display = dpy;
1488 cached_value.format = pictformat;
1489 formats->push_front(cached_value);
1491 if (formats->size() == kMaxCacheSize) {
1492 formats->pop_back();
1493 // We should really only have at most 2 display/visual combinations:
1494 // one for normal browser windows, and possibly another for an argb window
1495 // created to display a menu.
1497 // If we get here it's not fatal, we just need to make sure we aren't
1498 // always blowing away the cache. If we are, then we should figure out why
1499 // and make it bigger.
1506 void SetX11ErrorHandlers(XErrorHandler error_handler,
1507 XIOErrorHandler io_error_handler) {
1508 XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
1510 io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
1513 void LogErrorEventDescription(XDisplay* dpy,
1514 const XErrorEvent& error_event) {
1515 char error_str[256];
1516 char request_str[256];
1518 XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
1520 strncpy(request_str, "Unknown", sizeof(request_str));
1521 if (error_event.request_code < 128) {
1522 std::string num = base::UintToString(error_event.request_code);
1523 XGetErrorDatabaseText(
1524 dpy, "XRequest", num.c_str(), "Unknown", request_str,
1525 sizeof(request_str));
1528 char** ext_list = XListExtensions(dpy, &num_ext);
1530 for (int i = 0; i < num_ext; i++) {
1531 int ext_code, first_event, first_error;
1532 XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
1533 if (error_event.request_code == ext_code) {
1534 std::string msg = base::StringPrintf(
1535 "%s.%d", ext_list[i], error_event.minor_code);
1536 XGetErrorDatabaseText(
1537 dpy, "XRequest", msg.c_str(), "Unknown", request_str,
1538 sizeof(request_str));
1542 XFreeExtensionList(ext_list);
1546 << "X error received: "
1547 << "serial " << error_event.serial << ", "
1548 << "error_code " << static_cast<int>(error_event.error_code)
1549 << " (" << error_str << "), "
1550 << "request_code " << static_cast<int>(error_event.request_code) << ", "
1551 << "minor_code " << static_cast<int>(error_event.minor_code)
1552 << " (" << request_str << ")";
1555 // ----------------------------------------------------------------------------
1556 // End of x11_util_internal.h