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