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