Home | History | Annotate | Download | only in x
      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.
      4 
      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.
      8 
      9 #include "ui/base/x/x11_util.h"
     10 
     11 #include <ctype.h>
     12 #include <sys/ipc.h>
     13 #include <sys/shm.h>
     14 
     15 #include <list>
     16 #include <map>
     17 #include <utility>
     18 #include <vector>
     19 
     20 #include <X11/extensions/shape.h>
     21 #include <X11/extensions/XInput2.h>
     22 #include <X11/Xcursor/Xcursor.h>
     23 
     24 #include "base/bind.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 "skia/ext/image_operations.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_menu_list.h"
     40 #include "ui/base/x/x11_util_internal.h"
     41 #include "ui/events/event_utils.h"
     42 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
     43 #include "ui/events/x/device_data_manager.h"
     44 #include "ui/events/x/touch_factory_x11.h"
     45 #include "ui/gfx/canvas.h"
     46 #include "ui/gfx/image/image_skia.h"
     47 #include "ui/gfx/image/image_skia_rep.h"
     48 #include "ui/gfx/point.h"
     49 #include "ui/gfx/point_conversions.h"
     50 #include "ui/gfx/rect.h"
     51 #include "ui/gfx/size.h"
     52 #include "ui/gfx/skia_util.h"
     53 #include "ui/gfx/x/x11_error_tracker.h"
     54 
     55 #if defined(OS_FREEBSD)
     56 #include <sys/sysctl.h>
     57 #include <sys/types.h>
     58 #endif
     59 
     60 namespace ui {
     61 
     62 namespace {
     63 
     64 int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
     65   if (base::MessageLoop::current()) {
     66     base::MessageLoop::current()->PostTask(
     67         FROM_HERE, base::Bind(&LogErrorEventDescription, d, *e));
     68   } else {
     69     LOG(ERROR)
     70         << "X error received: "
     71         << "serial " << e->serial << ", "
     72         << "error_code " << static_cast<int>(e->error_code) << ", "
     73         << "request_code " << static_cast<int>(e->request_code) << ", "
     74         << "minor_code " << static_cast<int>(e->minor_code);
     75   }
     76   return 0;
     77 }
     78 
     79 int DefaultX11IOErrorHandler(XDisplay* d) {
     80   // If there's an IO error it likely means the X server has gone away
     81   LOG(ERROR) << "X IO error received (X server probably went away)";
     82   _exit(1);
     83 }
     84 
     85 // Note: The caller should free the resulting value data.
     86 bool GetProperty(XID window, const std::string& property_name, long max_length,
     87                  Atom* type, int* format, unsigned long* num_items,
     88                  unsigned char** property) {
     89   Atom property_atom = GetAtom(property_name.c_str());
     90   unsigned long remaining_bytes = 0;
     91   return XGetWindowProperty(gfx::GetXDisplay(),
     92                             window,
     93                             property_atom,
     94                             0,          // offset into property data to read
     95                             max_length, // max length to get
     96                             False,      // deleted
     97                             AnyPropertyType,
     98                             type,
     99                             format,
    100                             num_items,
    101                             &remaining_bytes,
    102                             property);
    103 }
    104 
    105 // A process wide singleton that manages the usage of X cursors.
    106 class XCursorCache {
    107  public:
    108   XCursorCache() {}
    109   ~XCursorCache() {
    110     Clear();
    111   }
    112 
    113   ::Cursor GetCursor(int cursor_shape) {
    114     // Lookup cursor by attempting to insert a null value, which avoids
    115     // a second pass through the map after a cache miss.
    116     std::pair<std::map<int, ::Cursor>::iterator, bool> it = cache_.insert(
    117         std::make_pair(cursor_shape, 0));
    118     if (it.second) {
    119       XDisplay* display = gfx::GetXDisplay();
    120       it.first->second = XCreateFontCursor(display, cursor_shape);
    121     }
    122     return it.first->second;
    123   }
    124 
    125   void Clear() {
    126     XDisplay* display = gfx::GetXDisplay();
    127     for (std::map<int, ::Cursor>::iterator it =
    128         cache_.begin(); it != cache_.end(); ++it) {
    129       XFreeCursor(display, it->second);
    130     }
    131     cache_.clear();
    132   }
    133 
    134  private:
    135   // Maps X11 font cursor shapes to Cursor IDs.
    136   std::map<int, ::Cursor> cache_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(XCursorCache);
    139 };
    140 
    141 XCursorCache* cursor_cache = NULL;
    142 
    143 // A process wide singleton cache for custom X cursors.
    144 class XCustomCursorCache {
    145  public:
    146   static XCustomCursorCache* GetInstance() {
    147     return Singleton<XCustomCursorCache>::get();
    148   }
    149 
    150   ::Cursor InstallCustomCursor(XcursorImage* image) {
    151     XCustomCursor* custom_cursor = new XCustomCursor(image);
    152     ::Cursor xcursor = custom_cursor->cursor();
    153     cache_[xcursor] = custom_cursor;
    154     return xcursor;
    155   }
    156 
    157   void Ref(::Cursor cursor) {
    158     cache_[cursor]->Ref();
    159   }
    160 
    161   void Unref(::Cursor cursor) {
    162     if (cache_[cursor]->Unref())
    163       cache_.erase(cursor);
    164   }
    165 
    166   void Clear() {
    167     cache_.clear();
    168   }
    169 
    170   const XcursorImage* GetXcursorImage(::Cursor cursor) const {
    171     return cache_.find(cursor)->second->image();
    172   }
    173 
    174  private:
    175   friend struct DefaultSingletonTraits<XCustomCursorCache>;
    176 
    177   class XCustomCursor {
    178    public:
    179     // This takes ownership of the image.
    180     XCustomCursor(XcursorImage* image)
    181         : image_(image),
    182           ref_(1) {
    183       cursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image);
    184     }
    185 
    186     ~XCustomCursor() {
    187       XcursorImageDestroy(image_);
    188       XFreeCursor(gfx::GetXDisplay(), cursor_);
    189     }
    190 
    191     ::Cursor cursor() const { return cursor_; }
    192 
    193     void Ref() {
    194       ++ref_;
    195     }
    196 
    197     // Returns true if the cursor was destroyed because of the unref.
    198     bool Unref() {
    199       if (--ref_ == 0) {
    200         delete this;
    201         return true;
    202       }
    203       return false;
    204     }
    205 
    206     const XcursorImage* image() const {
    207       return image_;
    208     };
    209 
    210    private:
    211     XcursorImage* image_;
    212     int ref_;
    213     ::Cursor cursor_;
    214 
    215     DISALLOW_COPY_AND_ASSIGN(XCustomCursor);
    216   };
    217 
    218   XCustomCursorCache() {}
    219   ~XCustomCursorCache() {
    220     Clear();
    221   }
    222 
    223   std::map< ::Cursor, XCustomCursor*> cache_;
    224   DISALLOW_COPY_AND_ASSIGN(XCustomCursorCache);
    225 };
    226 
    227 }  // namespace
    228 
    229 bool IsXInput2Available() {
    230   return DeviceDataManager::GetInstance()->IsXInput2Available();
    231 }
    232 
    233 static SharedMemorySupport DoQuerySharedMemorySupport(XDisplay* dpy) {
    234   int dummy;
    235   Bool pixmaps_supported;
    236   // Query the server's support for XSHM.
    237   if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
    238     return SHARED_MEMORY_NONE;
    239 
    240 #if defined(OS_FREEBSD)
    241   // On FreeBSD we can't access the shared memory after it was marked for
    242   // deletion, unless this behaviour is explicitly enabled by the user.
    243   // In case it's not enabled disable shared memory support.
    244   int allow_removed;
    245   size_t length = sizeof(allow_removed);
    246 
    247   if ((sysctlbyname("kern.ipc.shm_allow_removed", &allow_removed, &length,
    248       NULL, 0) < 0) || allow_removed < 1) {
    249     return SHARED_MEMORY_NONE;
    250   }
    251 #endif
    252 
    253   // Next we probe to see if shared memory will really work
    254   int shmkey = shmget(IPC_PRIVATE, 1, 0600);
    255   if (shmkey == -1) {
    256     LOG(WARNING) << "Failed to get shared memory segment.";
    257     return SHARED_MEMORY_NONE;
    258   } else {
    259     VLOG(1) << "Got shared memory segment " << shmkey;
    260   }
    261 
    262   void* address = shmat(shmkey, NULL, 0);
    263   // Mark the shared memory region for deletion
    264   shmctl(shmkey, IPC_RMID, NULL);
    265 
    266   XShmSegmentInfo shminfo;
    267   memset(&shminfo, 0, sizeof(shminfo));
    268   shminfo.shmid = shmkey;
    269 
    270   gfx::X11ErrorTracker err_tracker;
    271   bool result = XShmAttach(dpy, &shminfo);
    272   if (result)
    273     VLOG(1) << "X got shared memory segment " << shmkey;
    274   else
    275     LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
    276   if (err_tracker.FoundNewError())
    277     result = false;
    278   shmdt(address);
    279   if (!result) {
    280     LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
    281     return SHARED_MEMORY_NONE;
    282   }
    283 
    284   VLOG(1) << "X attached to shared memory segment " << shmkey;
    285 
    286   XShmDetach(dpy, &shminfo);
    287   return pixmaps_supported ? SHARED_MEMORY_PIXMAP : SHARED_MEMORY_PUTIMAGE;
    288 }
    289 
    290 SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy) {
    291   static SharedMemorySupport shared_memory_support = SHARED_MEMORY_NONE;
    292   static bool shared_memory_support_cached = false;
    293 
    294   if (shared_memory_support_cached)
    295     return shared_memory_support;
    296 
    297   shared_memory_support = DoQuerySharedMemorySupport(dpy);
    298   shared_memory_support_cached = true;
    299 
    300   return shared_memory_support;
    301 }
    302 
    303 bool QueryRenderSupport(Display* dpy) {
    304   int dummy;
    305   // We don't care about the version of Xrender since all the features which
    306   // we use are included in every version.
    307   static bool render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
    308 
    309   return render_supported;
    310 }
    311 
    312 ::Cursor GetXCursor(int cursor_shape) {
    313   if (!cursor_cache)
    314     cursor_cache = new XCursorCache;
    315   return cursor_cache->GetCursor(cursor_shape);
    316 }
    317 
    318 ::Cursor CreateReffedCustomXCursor(XcursorImage* image) {
    319   return XCustomCursorCache::GetInstance()->InstallCustomCursor(image);
    320 }
    321 
    322 void RefCustomXCursor(::Cursor cursor) {
    323   XCustomCursorCache::GetInstance()->Ref(cursor);
    324 }
    325 
    326 void UnrefCustomXCursor(::Cursor cursor) {
    327   XCustomCursorCache::GetInstance()->Unref(cursor);
    328 }
    329 
    330 XcursorImage* SkBitmapToXcursorImage(const SkBitmap* cursor_image,
    331                                      const gfx::Point& hotspot) {
    332   DCHECK(cursor_image->colorType() == kPMColor_SkColorType);
    333   gfx::Point hotspot_point = hotspot;
    334   SkBitmap scaled;
    335 
    336   // X11 seems to have issues with cursors when images get larger than 64
    337   // pixels. So rescale the image if necessary.
    338   const float kMaxPixel = 64.f;
    339   bool needs_scale = false;
    340   if (cursor_image->width() > kMaxPixel || cursor_image->height() > kMaxPixel) {
    341     float scale = 1.f;
    342     if (cursor_image->width() > cursor_image->height())
    343       scale = kMaxPixel / cursor_image->width();
    344     else
    345       scale = kMaxPixel / cursor_image->height();
    346 
    347     scaled = skia::ImageOperations::Resize(*cursor_image,
    348         skia::ImageOperations::RESIZE_BETTER,
    349         static_cast<int>(cursor_image->width() * scale),
    350         static_cast<int>(cursor_image->height() * scale));
    351     hotspot_point = gfx::ToFlooredPoint(gfx::ScalePoint(hotspot, scale));
    352     needs_scale = true;
    353   }
    354 
    355   const SkBitmap* bitmap = needs_scale ? &scaled : cursor_image;
    356   XcursorImage* image = XcursorImageCreate(bitmap->width(), bitmap->height());
    357   image->xhot = std::min(bitmap->width() - 1, hotspot_point.x());
    358   image->yhot = std::min(bitmap->height() - 1, hotspot_point.y());
    359 
    360   if (bitmap->width() && bitmap->height()) {
    361     bitmap->lockPixels();
    362     // The |bitmap| contains ARGB image, so just copy it.
    363     memcpy(image->pixels,
    364            bitmap->getPixels(),
    365            bitmap->width() * bitmap->height() * 4);
    366     bitmap->unlockPixels();
    367   }
    368 
    369   return image;
    370 }
    371 
    372 
    373 int CoalescePendingMotionEvents(const XEvent* xev,
    374                                 XEvent* last_event) {
    375   XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    376   int num_coalesced = 0;
    377   XDisplay* display = xev->xany.display;
    378   int event_type = xev->xgeneric.evtype;
    379 
    380   DCHECK(event_type == XI_Motion || event_type == XI_TouchUpdate);
    381 
    382   while (XPending(display)) {
    383     XEvent next_event;
    384     XPeekEvent(display, &next_event);
    385 
    386     // If we can't get the cookie, abort the check.
    387     if (!XGetEventData(next_event.xgeneric.display, &next_event.xcookie))
    388       return num_coalesced;
    389 
    390     // If this isn't from a valid device, throw the event away, as
    391     // that's what the message pump would do. Device events come in pairs
    392     // with one from the master and one from the slave so there will
    393     // always be at least one pending.
    394     if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(&next_event)) {
    395       XFreeEventData(display, &next_event.xcookie);
    396       XNextEvent(display, &next_event);
    397       continue;
    398     }
    399 
    400     if (next_event.type == GenericEvent &&
    401         next_event.xgeneric.evtype == event_type &&
    402         !ui::DeviceDataManager::GetInstance()->IsCMTGestureEvent(
    403             &next_event)) {
    404       XIDeviceEvent* next_xievent =
    405           static_cast<XIDeviceEvent*>(next_event.xcookie.data);
    406       // Confirm that the motion event is targeted at the same window
    407       // and that no buttons or modifiers have changed.
    408       if (xievent->event == next_xievent->event &&
    409           xievent->child == next_xievent->child &&
    410           xievent->detail == next_xievent->detail &&
    411           xievent->buttons.mask_len == next_xievent->buttons.mask_len &&
    412           (memcmp(xievent->buttons.mask,
    413                   next_xievent->buttons.mask,
    414                   xievent->buttons.mask_len) == 0) &&
    415           xievent->mods.base == next_xievent->mods.base &&
    416           xievent->mods.latched == next_xievent->mods.latched &&
    417           xievent->mods.locked == next_xievent->mods.locked &&
    418           xievent->mods.effective == next_xievent->mods.effective) {
    419         XFreeEventData(display, &next_event.xcookie);
    420         // Free the previous cookie.
    421         if (num_coalesced > 0)
    422           XFreeEventData(display, &last_event->xcookie);
    423         // Get the event and its cookie data.
    424         XNextEvent(display, last_event);
    425         XGetEventData(display, &last_event->xcookie);
    426         ++num_coalesced;
    427         continue;
    428       }
    429     }
    430     // This isn't an event we want so free its cookie data.
    431     XFreeEventData(display, &next_event.xcookie);
    432     break;
    433   }
    434 
    435   if (event_type == XI_Motion && num_coalesced > 0) {
    436     base::TimeDelta delta = ui::EventTimeFromNative(last_event) -
    437         ui::EventTimeFromNative(const_cast<XEvent*>(xev));
    438     UMA_HISTOGRAM_COUNTS_10000("Event.CoalescedCount.Mouse", num_coalesced);
    439     UMA_HISTOGRAM_TIMES("Event.CoalescedLatency.Mouse", delta);
    440   }
    441   return num_coalesced;
    442 }
    443 
    444 void HideHostCursor() {
    445   CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
    446                          (CreateInvisibleCursor(), gfx::GetXDisplay()));
    447   XDefineCursor(gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()),
    448                 invisible_cursor.get());
    449 }
    450 
    451 ::Cursor CreateInvisibleCursor() {
    452   XDisplay* xdisplay = gfx::GetXDisplay();
    453   ::Cursor invisible_cursor;
    454   char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    455   XColor black;
    456   black.red = black.green = black.blue = 0;
    457   Pixmap blank = XCreateBitmapFromData(xdisplay,
    458                                        DefaultRootWindow(xdisplay),
    459                                        nodata, 8, 8);
    460   invisible_cursor = XCreatePixmapCursor(xdisplay, blank, blank,
    461                                          &black, &black, 0, 0);
    462   XFreePixmap(xdisplay, blank);
    463   return invisible_cursor;
    464 }
    465 
    466 void SetUseOSWindowFrame(XID window, bool use_os_window_frame) {
    467   // This data structure represents additional hints that we send to the window
    468   // manager and has a direct lineage back to Motif, which defined this de facto
    469   // standard. This struct doesn't seem 64-bit safe though, but it's what GDK
    470   // does.
    471   typedef struct {
    472     unsigned long flags;
    473     unsigned long functions;
    474     unsigned long decorations;
    475     long input_mode;
    476     unsigned long status;
    477   } MotifWmHints;
    478 
    479   MotifWmHints motif_hints;
    480   memset(&motif_hints, 0, sizeof(motif_hints));
    481   // Signals that the reader of the _MOTIF_WM_HINTS property should pay
    482   // attention to the value of |decorations|.
    483   motif_hints.flags = (1L << 1);
    484   motif_hints.decorations = use_os_window_frame ? 1 : 0;
    485 
    486   ::Atom hint_atom = GetAtom("_MOTIF_WM_HINTS");
    487   XChangeProperty(gfx::GetXDisplay(),
    488                   window,
    489                   hint_atom,
    490                   hint_atom,
    491                   32,
    492                   PropModeReplace,
    493                   reinterpret_cast<unsigned char*>(&motif_hints),
    494                   sizeof(MotifWmHints)/sizeof(long));
    495 }
    496 
    497 bool IsShapeExtensionAvailable() {
    498   int dummy;
    499   static bool is_shape_available =
    500       XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy);
    501   return is_shape_available;
    502 }
    503 
    504 XID GetX11RootWindow() {
    505   return DefaultRootWindow(gfx::GetXDisplay());
    506 }
    507 
    508 bool GetCurrentDesktop(int* desktop) {
    509   return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
    510 }
    511 
    512 void SetHideTitlebarWhenMaximizedProperty(XID window,
    513                                           HideTitlebarWhenMaximized property) {
    514   // XChangeProperty() expects "hide" to be long.
    515   unsigned long hide = property;
    516   XChangeProperty(gfx::GetXDisplay(),
    517       window,
    518       GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
    519       XA_CARDINAL,
    520       32,  // size in bits
    521       PropModeReplace,
    522       reinterpret_cast<unsigned char*>(&hide),
    523       1);
    524 }
    525 
    526 void ClearX11DefaultRootWindow() {
    527   XDisplay* display = gfx::GetXDisplay();
    528   XID root_window = GetX11RootWindow();
    529   gfx::Rect root_bounds;
    530   if (!GetWindowRect(root_window, &root_bounds)) {
    531     LOG(ERROR) << "Failed to get the bounds of the X11 root window";
    532     return;
    533   }
    534 
    535   XGCValues gc_values = {0};
    536   gc_values.foreground = BlackPixel(display, DefaultScreen(display));
    537   GC gc = XCreateGC(display, root_window, GCForeground, &gc_values);
    538   XFillRectangle(display, root_window, gc,
    539                  root_bounds.x(),
    540                  root_bounds.y(),
    541                  root_bounds.width(),
    542                  root_bounds.height());
    543   XFreeGC(display, gc);
    544 }
    545 
    546 bool IsWindowVisible(XID window) {
    547   TRACE_EVENT0("ui", "IsWindowVisible");
    548 
    549   XWindowAttributes win_attributes;
    550   if (!XGetWindowAttributes(gfx::GetXDisplay(), window, &win_attributes))
    551     return false;
    552   if (win_attributes.map_state != IsViewable)
    553     return false;
    554 
    555   // Minimized windows are not visible.
    556   std::vector<Atom> wm_states;
    557   if (GetAtomArrayProperty(window, "_NET_WM_STATE", &wm_states)) {
    558     Atom hidden_atom = GetAtom("_NET_WM_STATE_HIDDEN");
    559     if (std::find(wm_states.begin(), wm_states.end(), hidden_atom) !=
    560             wm_states.end()) {
    561       return false;
    562     }
    563   }
    564 
    565   // Some compositing window managers (notably kwin) do not actually unmap
    566   // windows on desktop switch, so we also must check the current desktop.
    567   int window_desktop, current_desktop;
    568   return (!GetWindowDesktop(window, &window_desktop) ||
    569           !GetCurrentDesktop(&current_desktop) ||
    570           window_desktop == kAllDesktops ||
    571           window_desktop == current_desktop);
    572 }
    573 
    574 bool GetWindowRect(XID window, gfx::Rect* rect) {
    575   Window root, child;
    576   int x, y;
    577   unsigned int width, height;
    578   unsigned int border_width, depth;
    579 
    580   if (!XGetGeometry(gfx::GetXDisplay(), window, &root, &x, &y,
    581                     &width, &height, &border_width, &depth))
    582     return false;
    583 
    584   if (!XTranslateCoordinates(gfx::GetXDisplay(), window, root,
    585                              0, 0, &x, &y, &child))
    586     return false;
    587 
    588   *rect = gfx::Rect(x, y, width, height);
    589 
    590   std::vector<int> insets;
    591   if (GetIntArrayProperty(window, "_NET_FRAME_EXTENTS", &insets) &&
    592       insets.size() == 4) {
    593     rect->Inset(-insets[0], -insets[2], -insets[1], -insets[3]);
    594   }
    595   // Not all window managers support _NET_FRAME_EXTENTS so return true even if
    596   // requesting the property fails.
    597 
    598   return true;
    599 }
    600 
    601 
    602 bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
    603   TRACE_EVENT0("ui", "WindowContainsPoint");
    604 
    605   gfx::Rect window_rect;
    606   if (!GetWindowRect(window, &window_rect))
    607     return false;
    608 
    609   if (!window_rect.Contains(screen_loc))
    610     return false;
    611 
    612   if (!IsShapeExtensionAvailable())
    613     return true;
    614 
    615   // According to http://www.x.org/releases/X11R7.6/doc/libXext/shapelib.html,
    616   // if an X display supports the shape extension the bounds of a window are
    617   // defined as the intersection of the window bounds and the interior
    618   // rectangles. This means to determine if a point is inside a window for the
    619   // purpose of input handling we have to check the rectangles in the ShapeInput
    620   // list.
    621   // According to http://www.x.org/releases/current/doc/xextproto/shape.html,
    622   // we need to also respect the ShapeBounding rectangles.
    623   // The effective input region of a window is defined to be the intersection
    624   // of the client input region with both the default input region and the
    625   // client bounding region. Any portion of the client input region that is not
    626   // included in both the default input region and the client bounding region
    627   // will not be included in the effective input region on the screen.
    628   int rectangle_kind[] = {ShapeInput, ShapeBounding};
    629   for (size_t kind_index = 0;
    630        kind_index < arraysize(rectangle_kind);
    631        kind_index++) {
    632     int dummy;
    633     int shape_rects_size = 0;
    634     XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
    635                                                   window,
    636                                                   rectangle_kind[kind_index],
    637                                                   &shape_rects_size,
    638                                                   &dummy);
    639     if (!shape_rects) {
    640       // The shape is empty. This can occur when |window| is minimized.
    641       DCHECK_EQ(0, shape_rects_size);
    642       return false;
    643     }
    644     bool is_in_shape_rects = false;
    645     for (int i = 0; i < shape_rects_size; ++i) {
    646       // The ShapeInput and ShapeBounding rects are to be in window space, so we
    647       // have to translate by the window_rect's offset to map to screen space.
    648       gfx::Rect shape_rect =
    649           gfx::Rect(shape_rects[i].x + window_rect.x(),
    650                     shape_rects[i].y + window_rect.y(),
    651                     shape_rects[i].width, shape_rects[i].height);
    652       if (shape_rect.Contains(screen_loc)) {
    653         is_in_shape_rects = true;
    654         break;
    655       }
    656     }
    657     XFree(shape_rects);
    658     if (!is_in_shape_rects)
    659       return false;
    660   }
    661   return true;
    662 }
    663 
    664 
    665 bool PropertyExists(XID window, const std::string& property_name) {
    666   Atom type = None;
    667   int format = 0;  // size in bits of each item in 'property'
    668   unsigned long num_items = 0;
    669   unsigned char* property = NULL;
    670 
    671   int result = GetProperty(window, property_name, 1,
    672                            &type, &format, &num_items, &property);
    673   if (result != Success)
    674     return false;
    675 
    676   XFree(property);
    677   return num_items > 0;
    678 }
    679 
    680 bool GetRawBytesOfProperty(XID window,
    681                            Atom property,
    682                            scoped_refptr<base::RefCountedMemory>* out_data,
    683                            size_t* out_data_bytes,
    684                            size_t* out_data_items,
    685                            Atom* out_type) {
    686   // Retrieve the data from our window.
    687   unsigned long nitems = 0;
    688   unsigned long nbytes = 0;
    689   Atom prop_type = None;
    690   int prop_format = 0;
    691   unsigned char* property_data = NULL;
    692   if (XGetWindowProperty(gfx::GetXDisplay(), window, property,
    693                          0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
    694                          AnyPropertyType, &prop_type, &prop_format,
    695                          &nitems, &nbytes, &property_data) != Success) {
    696     return false;
    697   }
    698 
    699   if (prop_type == None)
    700     return false;
    701 
    702   size_t bytes = 0;
    703   // So even though we should theoretically have nbytes (and we can't
    704   // pass NULL there), we need to manually calculate the byte length here
    705   // because nbytes always returns zero.
    706   switch (prop_format) {
    707     case 8:
    708       bytes = nitems;
    709       break;
    710     case 16:
    711       bytes = sizeof(short) * nitems;
    712       break;
    713     case 32:
    714       bytes = sizeof(long) * nitems;
    715       break;
    716     default:
    717       NOTREACHED();
    718       break;
    719   }
    720 
    721   if (out_data_bytes)
    722     *out_data_bytes = bytes;
    723 
    724   if (out_data)
    725     *out_data = new XRefcountedMemory(property_data, bytes);
    726   else
    727     XFree(property_data);
    728 
    729   if (out_data_items)
    730     *out_data_items = nitems;
    731 
    732   if (out_type)
    733     *out_type = prop_type;
    734 
    735   return true;
    736 }
    737 
    738 bool GetIntProperty(XID window, const std::string& property_name, int* value) {
    739   Atom type = None;
    740   int format = 0;  // size in bits of each item in 'property'
    741   unsigned long num_items = 0;
    742   unsigned char* property = NULL;
    743 
    744   int result = GetProperty(window, property_name, 1,
    745                            &type, &format, &num_items, &property);
    746   if (result != Success)
    747     return false;
    748 
    749   if (format != 32 || num_items != 1) {
    750     XFree(property);
    751     return false;
    752   }
    753 
    754   *value = static_cast<int>(*(reinterpret_cast<long*>(property)));
    755   XFree(property);
    756   return true;
    757 }
    758 
    759 bool GetXIDProperty(XID window, const std::string& property_name, XID* value) {
    760   Atom type = None;
    761   int format = 0;  // size in bits of each item in 'property'
    762   unsigned long num_items = 0;
    763   unsigned char* property = NULL;
    764 
    765   int result = GetProperty(window, property_name, 1,
    766                            &type, &format, &num_items, &property);
    767   if (result != Success)
    768     return false;
    769 
    770   if (format != 32 || num_items != 1) {
    771     XFree(property);
    772     return false;
    773   }
    774 
    775   *value = *(reinterpret_cast<XID*>(property));
    776   XFree(property);
    777   return true;
    778 }
    779 
    780 bool GetIntArrayProperty(XID window,
    781                          const std::string& property_name,
    782                          std::vector<int>* value) {
    783   Atom type = None;
    784   int format = 0;  // size in bits of each item in 'property'
    785   unsigned long num_items = 0;
    786   unsigned char* properties = NULL;
    787 
    788   int result = GetProperty(window, property_name,
    789                            (~0L), // (all of them)
    790                            &type, &format, &num_items, &properties);
    791   if (result != Success)
    792     return false;
    793 
    794   if (format != 32) {
    795     XFree(properties);
    796     return false;
    797   }
    798 
    799   long* int_properties = reinterpret_cast<long*>(properties);
    800   value->clear();
    801   for (unsigned long i = 0; i < num_items; ++i) {
    802     value->push_back(static_cast<int>(int_properties[i]));
    803   }
    804   XFree(properties);
    805   return true;
    806 }
    807 
    808 bool GetAtomArrayProperty(XID window,
    809                           const std::string& property_name,
    810                           std::vector<Atom>* value) {
    811   Atom type = None;
    812   int format = 0;  // size in bits of each item in 'property'
    813   unsigned long num_items = 0;
    814   unsigned char* properties = NULL;
    815 
    816   int result = GetProperty(window, property_name,
    817                            (~0L), // (all of them)
    818                            &type, &format, &num_items, &properties);
    819   if (result != Success)
    820     return false;
    821 
    822   if (type != XA_ATOM) {
    823     XFree(properties);
    824     return false;
    825   }
    826 
    827   Atom* atom_properties = reinterpret_cast<Atom*>(properties);
    828   value->clear();
    829   value->insert(value->begin(), atom_properties, atom_properties + num_items);
    830   XFree(properties);
    831   return true;
    832 }
    833 
    834 bool GetStringProperty(
    835     XID window, const std::string& property_name, std::string* value) {
    836   Atom type = None;
    837   int format = 0;  // size in bits of each item in 'property'
    838   unsigned long num_items = 0;
    839   unsigned char* property = NULL;
    840 
    841   int result = GetProperty(window, property_name, 1024,
    842                            &type, &format, &num_items, &property);
    843   if (result != Success)
    844     return false;
    845 
    846   if (format != 8) {
    847     XFree(property);
    848     return false;
    849   }
    850 
    851   value->assign(reinterpret_cast<char*>(property), num_items);
    852   XFree(property);
    853   return true;
    854 }
    855 
    856 bool SetIntProperty(XID window,
    857                     const std::string& name,
    858                     const std::string& type,
    859                     int value) {
    860   std::vector<int> values(1, value);
    861   return SetIntArrayProperty(window, name, type, values);
    862 }
    863 
    864 bool SetIntArrayProperty(XID window,
    865                          const std::string& name,
    866                          const std::string& type,
    867                          const std::vector<int>& value) {
    868   DCHECK(!value.empty());
    869   Atom name_atom = GetAtom(name.c_str());
    870   Atom type_atom = GetAtom(type.c_str());
    871 
    872   // XChangeProperty() expects values of type 32 to be longs.
    873   scoped_ptr<long[]> data(new long[value.size()]);
    874   for (size_t i = 0; i < value.size(); ++i)
    875     data[i] = value[i];
    876 
    877   gfx::X11ErrorTracker err_tracker;
    878   XChangeProperty(gfx::GetXDisplay(),
    879                   window,
    880                   name_atom,
    881                   type_atom,
    882                   32,  // size in bits of items in 'value'
    883                   PropModeReplace,
    884                   reinterpret_cast<const unsigned char*>(data.get()),
    885                   value.size());  // num items
    886   return !err_tracker.FoundNewError();
    887 }
    888 
    889 bool SetAtomProperty(XID window,
    890                      const std::string& name,
    891                      const std::string& type,
    892                      Atom value) {
    893   std::vector<Atom> values(1, value);
    894   return SetAtomArrayProperty(window, name, type, values);
    895 }
    896 
    897 bool SetAtomArrayProperty(XID window,
    898                           const std::string& name,
    899                           const std::string& type,
    900                           const std::vector<Atom>& value) {
    901   DCHECK(!value.empty());
    902   Atom name_atom = GetAtom(name.c_str());
    903   Atom type_atom = GetAtom(type.c_str());
    904 
    905   // XChangeProperty() expects values of type 32 to be longs.
    906   scoped_ptr<Atom[]> data(new Atom[value.size()]);
    907   for (size_t i = 0; i < value.size(); ++i)
    908     data[i] = value[i];
    909 
    910   gfx::X11ErrorTracker err_tracker;
    911   XChangeProperty(gfx::GetXDisplay(),
    912                   window,
    913                   name_atom,
    914                   type_atom,
    915                   32,  // size in bits of items in 'value'
    916                   PropModeReplace,
    917                   reinterpret_cast<const unsigned char*>(data.get()),
    918                   value.size());  // num items
    919   return !err_tracker.FoundNewError();
    920 }
    921 
    922 bool SetStringProperty(XID window,
    923                        Atom property,
    924                        Atom type,
    925                        const std::string& value) {
    926   gfx::X11ErrorTracker err_tracker;
    927   XChangeProperty(gfx::GetXDisplay(),
    928                   window,
    929                   property,
    930                   type,
    931                   8,
    932                   PropModeReplace,
    933                   reinterpret_cast<const unsigned char*>(value.c_str()),
    934                   value.size());
    935   return !err_tracker.FoundNewError();
    936 }
    937 
    938 Atom GetAtom(const char* name) {
    939   // TODO(derat): Cache atoms to avoid round-trips to the server.
    940   return XInternAtom(gfx::GetXDisplay(), name, false);
    941 }
    942 
    943 void SetWindowClassHint(XDisplay* display,
    944                         XID window,
    945                         const std::string& res_name,
    946                         const std::string& res_class) {
    947   XClassHint class_hints;
    948   // const_cast is safe because XSetClassHint does not modify the strings.
    949   // Just to be safe, the res_name and res_class parameters are local copies,
    950   // not const references.
    951   class_hints.res_name = const_cast<char*>(res_name.c_str());
    952   class_hints.res_class = const_cast<char*>(res_class.c_str());
    953   XSetClassHint(display, window, &class_hints);
    954 }
    955 
    956 void SetWindowRole(XDisplay* display, XID window, const std::string& role) {
    957   if (role.empty()) {
    958     XDeleteProperty(display, window, GetAtom("WM_WINDOW_ROLE"));
    959   } else {
    960     char* role_c = const_cast<char*>(role.c_str());
    961     XChangeProperty(display, window, GetAtom("WM_WINDOW_ROLE"), XA_STRING, 8,
    962                     PropModeReplace,
    963                     reinterpret_cast<unsigned char*>(role_c),
    964                     role.size());
    965   }
    966 }
    967 
    968 bool GetCustomFramePrefDefault() {
    969   // Ideally, we'd use the custom frame by default and just fall back on using
    970   // system decorations for the few (?) tiling window managers where the custom
    971   // frame doesn't make sense (e.g. awesome, ion3, ratpoison, xmonad, etc.) or
    972   // other WMs where it has issues (e.g. Fluxbox -- see issue 19130).  The EWMH
    973   // _NET_SUPPORTING_WM property makes it easy to look up a name for the current
    974   // WM, but at least some of the WMs in the latter group don't set it.
    975   // Instead, we default to using system decorations for all WMs and
    976   // special-case the ones where the custom frame should be used.
    977   ui::WindowManagerName wm_type = GuessWindowManager();
    978   return (wm_type == WM_BLACKBOX ||
    979           wm_type == WM_COMPIZ ||
    980           wm_type == WM_ENLIGHTENMENT ||
    981           wm_type == WM_METACITY ||
    982           wm_type == WM_MUFFIN ||
    983           wm_type == WM_MUTTER ||
    984           wm_type == WM_OPENBOX ||
    985           wm_type == WM_XFWM4);
    986 }
    987 
    988 bool GetWindowDesktop(XID window, int* desktop) {
    989   return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
    990 }
    991 
    992 std::string GetX11ErrorString(XDisplay* display, int err) {
    993   char buffer[256];
    994   XGetErrorText(display, err, buffer, arraysize(buffer));
    995   return buffer;
    996 }
    997 
    998 // Returns true if |window| is a named window.
    999 bool IsWindowNamed(XID window) {
   1000   XTextProperty prop;
   1001   if (!XGetWMName(gfx::GetXDisplay(), window, &prop) || !prop.value)
   1002     return false;
   1003 
   1004   XFree(prop.value);
   1005   return true;
   1006 }
   1007 
   1008 bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
   1009                        const int max_depth, int depth) {
   1010   if (depth > max_depth)
   1011     return false;
   1012 
   1013   std::vector<XID> windows;
   1014   std::vector<XID>::iterator iter;
   1015   if (depth == 0) {
   1016     XMenuList::GetInstance()->InsertMenuWindowXIDs(&windows);
   1017     // Enumerate the menus first.
   1018     for (iter = windows.begin(); iter != windows.end(); iter++) {
   1019       if (delegate->ShouldStopIterating(*iter))
   1020         return true;
   1021     }
   1022     windows.clear();
   1023   }
   1024 
   1025   XID root, parent, *children;
   1026   unsigned int num_children;
   1027   int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children,
   1028                           &num_children);
   1029   if (status == 0)
   1030     return false;
   1031 
   1032   for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
   1033     windows.push_back(children[i]);
   1034 
   1035   XFree(children);
   1036 
   1037   // XQueryTree returns the children of |window| in bottom-to-top order, so
   1038   // reverse-iterate the list to check the windows from top-to-bottom.
   1039   for (iter = windows.begin(); iter != windows.end(); iter++) {
   1040     if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
   1041       return true;
   1042   }
   1043 
   1044   // If we're at this point, we didn't find the window we're looking for at the
   1045   // current level, so we need to recurse to the next level.  We use a second
   1046   // loop because the recursion and call to XQueryTree are expensive and is only
   1047   // needed for a small number of cases.
   1048   if (++depth <= max_depth) {
   1049     for (iter = windows.begin(); iter != windows.end(); iter++) {
   1050       if (EnumerateChildren(delegate, *iter, max_depth, depth))
   1051         return true;
   1052     }
   1053   }
   1054 
   1055   return false;
   1056 }
   1057 
   1058 bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
   1059   XID root = GetX11RootWindow();
   1060   return EnumerateChildren(delegate, root, max_depth, 0);
   1061 }
   1062 
   1063 void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
   1064   std::vector<XID> stack;
   1065   if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
   1066     // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
   1067     // to old school enumeration of all X windows.  Some WMs parent 'top-level'
   1068     // windows in unnamed actual top-level windows (ion WM), so extend the
   1069     // search depth to all children of top-level windows.
   1070     const int kMaxSearchDepth = 1;
   1071     ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
   1072     return;
   1073   }
   1074   XMenuList::GetInstance()->InsertMenuWindowXIDs(&stack);
   1075 
   1076   std::vector<XID>::iterator iter;
   1077   for (iter = stack.begin(); iter != stack.end(); iter++) {
   1078     if (delegate->ShouldStopIterating(*iter))
   1079       return;
   1080   }
   1081 }
   1082 
   1083 bool GetXWindowStack(Window window, std::vector<XID>* windows) {
   1084   windows->clear();
   1085 
   1086   Atom type;
   1087   int format;
   1088   unsigned long count;
   1089   unsigned char *data = NULL;
   1090   if (GetProperty(window,
   1091                   "_NET_CLIENT_LIST_STACKING",
   1092                   ~0L,
   1093                   &type,
   1094                   &format,
   1095                   &count,
   1096                   &data) != Success) {
   1097     return false;
   1098   }
   1099 
   1100   bool result = false;
   1101   if (type == XA_WINDOW && format == 32 && data && count > 0) {
   1102     result = true;
   1103     XID* stack = reinterpret_cast<XID*>(data);
   1104     for (long i = static_cast<long>(count) - 1; i >= 0; i--)
   1105       windows->push_back(stack[i]);
   1106   }
   1107 
   1108   if (data)
   1109     XFree(data);
   1110 
   1111   return result;
   1112 }
   1113 
   1114 bool CopyAreaToCanvas(XID drawable,
   1115                       gfx::Rect source_bounds,
   1116                       gfx::Point dest_offset,
   1117                       gfx::Canvas* canvas) {
   1118   ui::XScopedImage scoped_image(
   1119       XGetImage(gfx::GetXDisplay(), drawable,
   1120                 source_bounds.x(), source_bounds.y(),
   1121                 source_bounds.width(), source_bounds.height(),
   1122                 AllPlanes, ZPixmap));
   1123   XImage* image = scoped_image.get();
   1124   if (!image) {
   1125     LOG(ERROR) << "XGetImage failed";
   1126     return false;
   1127   }
   1128 
   1129   if (image->bits_per_pixel == 32) {
   1130     if ((0xff << SK_R32_SHIFT) != image->red_mask ||
   1131         (0xff << SK_G32_SHIFT) != image->green_mask ||
   1132         (0xff << SK_B32_SHIFT) != image->blue_mask) {
   1133       LOG(WARNING) << "XImage and Skia byte orders differ";
   1134       return false;
   1135     }
   1136 
   1137     // Set the alpha channel before copying to the canvas.  Otherwise, areas of
   1138     // the framebuffer that were cleared by ply-image rather than being obscured
   1139     // by an image during boot may end up transparent.
   1140     // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
   1141     // set the framebuffer's alpha channel regardless of whether the device
   1142     // claims to support alpha or not.
   1143     for (int i = 0; i < image->width * image->height * 4; i += 4)
   1144       image->data[i + 3] = 0xff;
   1145 
   1146     SkBitmap bitmap;
   1147     bitmap.installPixels(SkImageInfo::MakeN32Premul(image->width,
   1148                                                     image->height),
   1149                          image->data, image->bytes_per_line);
   1150     gfx::ImageSkia image_skia;
   1151     gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
   1152     image_skia.AddRepresentation(image_rep);
   1153     canvas->DrawImageInt(image_skia, dest_offset.x(), dest_offset.y());
   1154   } else {
   1155     NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
   1156     return false;
   1157   }
   1158 
   1159   return true;
   1160 }
   1161 
   1162 bool GetWindowManagerName(std::string* wm_name) {
   1163   DCHECK(wm_name);
   1164   int wm_window = 0;
   1165   if (!GetIntProperty(GetX11RootWindow(),
   1166                       "_NET_SUPPORTING_WM_CHECK",
   1167                       &wm_window)) {
   1168     return false;
   1169   }
   1170 
   1171   // It's possible that a window manager started earlier in this X session left
   1172   // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
   1173   // non-EWMH window manager, so we trap errors in the following requests to
   1174   // avoid crashes (issue 23860).
   1175 
   1176   // EWMH requires the supporting-WM window to also have a
   1177   // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
   1178   // property referencing an ID that's been recycled for another window), so we
   1179   // check that too.
   1180   gfx::X11ErrorTracker err_tracker;
   1181   int wm_window_property = 0;
   1182   bool result = GetIntProperty(
   1183       wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
   1184   if (err_tracker.FoundNewError() || !result ||
   1185       wm_window_property != wm_window) {
   1186     return false;
   1187   }
   1188 
   1189   result = GetStringProperty(
   1190       static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
   1191   return !err_tracker.FoundNewError() && result;
   1192 }
   1193 
   1194 WindowManagerName GuessWindowManager() {
   1195   std::string name;
   1196   if (GetWindowManagerName(&name)) {
   1197     // These names are taken from the WMs' source code.
   1198     if (name == "Blackbox")
   1199       return WM_BLACKBOX;
   1200     if (name == "chromeos-wm")
   1201       return WM_CHROME_OS;
   1202     if (name == "Compiz" || name == "compiz")
   1203       return WM_COMPIZ;
   1204     if (name == "e16")
   1205       return WM_ENLIGHTENMENT;
   1206     if (StartsWithASCII(name, "IceWM", true))
   1207       return WM_ICE_WM;
   1208     if (name == "KWin")
   1209       return WM_KWIN;
   1210     if (name == "Metacity")
   1211       return WM_METACITY;
   1212     if (name == "Mutter (Muffin)")
   1213       return WM_MUFFIN;
   1214     if (name == "GNOME Shell")
   1215       return WM_MUTTER; // GNOME Shell uses Mutter
   1216     if (name == "Mutter")
   1217       return WM_MUTTER;
   1218     if (name == "Openbox")
   1219       return WM_OPENBOX;
   1220     if (name == "Xfwm4")
   1221       return WM_XFWM4;
   1222   }
   1223   return WM_UNKNOWN;
   1224 }
   1225 
   1226 void SetDefaultX11ErrorHandlers() {
   1227   SetX11ErrorHandlers(NULL, NULL);
   1228 }
   1229 
   1230 bool IsX11WindowFullScreen(XID window) {
   1231   // If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
   1232   // absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
   1233   // whether we're fullscreen.
   1234   Atom fullscreen_atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
   1235   if (WmSupportsHint(fullscreen_atom)) {
   1236     std::vector<Atom> atom_properties;
   1237     if (GetAtomArrayProperty(window,
   1238                              "_NET_WM_STATE",
   1239                              &atom_properties)) {
   1240       return std::find(atom_properties.begin(),
   1241                        atom_properties.end(),
   1242                        fullscreen_atom) !=
   1243           atom_properties.end();
   1244     }
   1245   }
   1246 
   1247   gfx::Rect window_rect;
   1248   if (!ui::GetWindowRect(window, &window_rect))
   1249     return false;
   1250 
   1251   // We can't use gfx::Screen here because we don't have an aura::Window. So
   1252   // instead just look at the size of the default display.
   1253   //
   1254   // TODO(erg): Actually doing this correctly would require pulling out xrandr,
   1255   // which we don't even do in the desktop screen yet.
   1256   ::XDisplay* display = gfx::GetXDisplay();
   1257   ::Screen* screen = DefaultScreenOfDisplay(display);
   1258   int width = WidthOfScreen(screen);
   1259   int height = HeightOfScreen(screen);
   1260   return window_rect.size() == gfx::Size(width, height);
   1261 }
   1262 
   1263 bool WmSupportsHint(Atom atom) {
   1264   std::vector<Atom> supported_atoms;
   1265   if (!GetAtomArrayProperty(GetX11RootWindow(),
   1266                             "_NET_SUPPORTED",
   1267                             &supported_atoms)) {
   1268     return false;
   1269   }
   1270 
   1271   return std::find(supported_atoms.begin(), supported_atoms.end(), atom) !=
   1272       supported_atoms.end();
   1273 }
   1274 
   1275 const unsigned char* XRefcountedMemory::front() const {
   1276   return x11_data_;
   1277 }
   1278 
   1279 size_t XRefcountedMemory::size() const {
   1280   return length_;
   1281 }
   1282 
   1283 XRefcountedMemory::~XRefcountedMemory() {
   1284   XFree(x11_data_);
   1285 }
   1286 
   1287 XScopedString::~XScopedString() {
   1288   XFree(string_);
   1289 }
   1290 
   1291 XScopedImage::~XScopedImage() {
   1292   reset(NULL);
   1293 }
   1294 
   1295 void XScopedImage::reset(XImage* image) {
   1296   if (image_ == image)
   1297     return;
   1298   if (image_)
   1299     XDestroyImage(image_);
   1300   image_ = image;
   1301 }
   1302 
   1303 XScopedCursor::XScopedCursor(::Cursor cursor, XDisplay* display)
   1304     : cursor_(cursor),
   1305       display_(display) {
   1306 }
   1307 
   1308 XScopedCursor::~XScopedCursor() {
   1309   reset(0U);
   1310 }
   1311 
   1312 ::Cursor XScopedCursor::get() const {
   1313   return cursor_;
   1314 }
   1315 
   1316 void XScopedCursor::reset(::Cursor cursor) {
   1317   if (cursor_)
   1318     XFreeCursor(display_, cursor_);
   1319   cursor_ = cursor;
   1320 }
   1321 
   1322 namespace test {
   1323 
   1324 void ResetXCursorCache() {
   1325   delete cursor_cache;
   1326   cursor_cache = NULL;
   1327 }
   1328 
   1329 const XcursorImage* GetCachedXcursorImage(::Cursor cursor) {
   1330   return XCustomCursorCache::GetInstance()->GetXcursorImage(cursor);
   1331 }
   1332 }
   1333 
   1334 // ----------------------------------------------------------------------------
   1335 // These functions are declared in x11_util_internal.h because they require
   1336 // XLib.h to be included, and it conflicts with many other headers.
   1337 XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
   1338   static XRenderPictFormat* pictformat = NULL;
   1339   if (pictformat)
   1340     return pictformat;
   1341 
   1342   // First look for a 32-bit format which ignores the alpha value
   1343   XRenderPictFormat templ;
   1344   templ.depth = 32;
   1345   templ.type = PictTypeDirect;
   1346   templ.direct.red = 16;
   1347   templ.direct.green = 8;
   1348   templ.direct.blue = 0;
   1349   templ.direct.redMask = 0xff;
   1350   templ.direct.greenMask = 0xff;
   1351   templ.direct.blueMask = 0xff;
   1352   templ.direct.alphaMask = 0;
   1353 
   1354   static const unsigned long kMask =
   1355     PictFormatType | PictFormatDepth |
   1356     PictFormatRed | PictFormatRedMask |
   1357     PictFormatGreen | PictFormatGreenMask |
   1358     PictFormatBlue | PictFormatBlueMask |
   1359     PictFormatAlphaMask;
   1360 
   1361   pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
   1362 
   1363   if (!pictformat) {
   1364     // Not all X servers support xRGB32 formats. However, the XRENDER spec says
   1365     // that they must support an ARGB32 format, so we can always return that.
   1366     pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
   1367     CHECK(pictformat) << "XRENDER ARGB32 not supported.";
   1368   }
   1369 
   1370   return pictformat;
   1371 }
   1372 
   1373 void SetX11ErrorHandlers(XErrorHandler error_handler,
   1374                          XIOErrorHandler io_error_handler) {
   1375   XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
   1376   XSetIOErrorHandler(
   1377       io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
   1378 }
   1379 
   1380 void LogErrorEventDescription(XDisplay* dpy,
   1381                               const XErrorEvent& error_event) {
   1382   char error_str[256];
   1383   char request_str[256];
   1384 
   1385   XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
   1386 
   1387   strncpy(request_str, "Unknown", sizeof(request_str));
   1388   if (error_event.request_code < 128) {
   1389     std::string num = base::UintToString(error_event.request_code);
   1390     XGetErrorDatabaseText(
   1391         dpy, "XRequest", num.c_str(), "Unknown", request_str,
   1392         sizeof(request_str));
   1393   } else {
   1394     int num_ext;
   1395     char** ext_list = XListExtensions(dpy, &num_ext);
   1396 
   1397     for (int i = 0; i < num_ext; i++) {
   1398       int ext_code, first_event, first_error;
   1399       XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
   1400       if (error_event.request_code == ext_code) {
   1401         std::string msg = base::StringPrintf(
   1402             "%s.%d", ext_list[i], error_event.minor_code);
   1403         XGetErrorDatabaseText(
   1404             dpy, "XRequest", msg.c_str(), "Unknown", request_str,
   1405             sizeof(request_str));
   1406         break;
   1407       }
   1408     }
   1409     XFreeExtensionList(ext_list);
   1410   }
   1411 
   1412   LOG(WARNING)
   1413       << "X error received: "
   1414       << "serial " << error_event.serial << ", "
   1415       << "error_code " << static_cast<int>(error_event.error_code)
   1416       << " (" << error_str << "), "
   1417       << "request_code " << static_cast<int>(error_event.request_code) << ", "
   1418       << "minor_code " << static_cast<int>(error_event.minor_code)
   1419       << " (" << request_str << ")";
   1420 }
   1421 
   1422 // ----------------------------------------------------------------------------
   1423 // End of x11_util_internal.h
   1424 
   1425 
   1426 }  // namespace ui
   1427