Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / base / x / x11_util.cc
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   // According to http://www.x.org/releases/current/doc/xextproto/shape.html,
659   // we need to also respect the ShapeBounding rectangles.
660   // The effective input region of a window is defined to be the intersection
661   // of the client input region with both the default input region and the
662   // client bounding region. Any portion of the client input region that is not
663   // included in both the default input region and the client bounding region
664   // will not be included in the effective input region on the screen.
665   int rectangle_kind[] = {ShapeInput, ShapeBounding};
666   for (size_t kind_index = 0;
667        kind_index < arraysize(rectangle_kind);
668        kind_index++) {
669     int dummy;
670     int shape_rects_size = 0;
671     XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
672                                                   window,
673                                                   rectangle_kind[kind_index],
674                                                   &shape_rects_size,
675                                                   &dummy);
676     if (!shape_rects)
677       continue;
678     bool is_in_shape_rects = false;
679     for (int i = 0; i < shape_rects_size; ++i) {
680       // The ShapeInput and ShapeBounding rects are to be in window space, so we
681       // have to translate by the window_rect's offset to map to screen space.
682       gfx::Rect shape_rect =
683           gfx::Rect(shape_rects[i].x + window_rect.x(),
684                     shape_rects[i].y + window_rect.y(),
685                     shape_rects[i].width, shape_rects[i].height);
686       if (shape_rect.Contains(screen_loc)) {
687         is_in_shape_rects = true;
688         break;
689       }
690     }
691     XFree(shape_rects);
692     if (!is_in_shape_rects)
693       return false;
694   }
695   return true;
696 }
697
698
699 bool PropertyExists(XID window, const std::string& property_name) {
700   Atom type = None;
701   int format = 0;  // size in bits of each item in 'property'
702   unsigned long num_items = 0;
703   unsigned char* property = NULL;
704
705   int result = GetProperty(window, property_name, 1,
706                            &type, &format, &num_items, &property);
707   if (result != Success)
708     return false;
709
710   XFree(property);
711   return num_items > 0;
712 }
713
714 bool GetRawBytesOfProperty(XID window,
715                            Atom property,
716                            scoped_refptr<base::RefCountedMemory>* out_data,
717                            size_t* out_data_bytes,
718                            size_t* out_data_items,
719                            Atom* out_type) {
720   // Retrieve the data from our window.
721   unsigned long nitems = 0;
722   unsigned long nbytes = 0;
723   Atom prop_type = None;
724   int prop_format = 0;
725   unsigned char* property_data = NULL;
726   if (XGetWindowProperty(gfx::GetXDisplay(), window, property,
727                          0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
728                          AnyPropertyType, &prop_type, &prop_format,
729                          &nitems, &nbytes, &property_data) != Success) {
730     return false;
731   }
732
733   if (prop_type == None)
734     return false;
735
736   size_t bytes = 0;
737   // So even though we should theoretically have nbytes (and we can't
738   // pass NULL there), we need to manually calculate the byte length here
739   // because nbytes always returns zero.
740   switch (prop_format) {
741     case 8:
742       bytes = nitems;
743       break;
744     case 16:
745       bytes = sizeof(short) * nitems;
746       break;
747     case 32:
748       bytes = sizeof(long) * nitems;
749       break;
750     default:
751       NOTREACHED();
752       break;
753   }
754
755   if (out_data_bytes)
756     *out_data_bytes = bytes;
757
758   if (out_data)
759     *out_data = new XRefcountedMemory(property_data, bytes);
760   else
761     XFree(property_data);
762
763   if (out_data_items)
764     *out_data_items = nitems;
765
766   if (out_type)
767     *out_type = prop_type;
768
769   return true;
770 }
771
772 bool GetIntProperty(XID window, const std::string& property_name, int* value) {
773   Atom type = None;
774   int format = 0;  // size in bits of each item in 'property'
775   unsigned long num_items = 0;
776   unsigned char* property = NULL;
777
778   int result = GetProperty(window, property_name, 1,
779                            &type, &format, &num_items, &property);
780   if (result != Success)
781     return false;
782
783   if (format != 32 || num_items != 1) {
784     XFree(property);
785     return false;
786   }
787
788   *value = static_cast<int>(*(reinterpret_cast<long*>(property)));
789   XFree(property);
790   return true;
791 }
792
793 bool GetXIDProperty(XID window, const std::string& property_name, XID* value) {
794   Atom type = None;
795   int format = 0;  // size in bits of each item in 'property'
796   unsigned long num_items = 0;
797   unsigned char* property = NULL;
798
799   int result = GetProperty(window, property_name, 1,
800                            &type, &format, &num_items, &property);
801   if (result != Success)
802     return false;
803
804   if (format != 32 || num_items != 1) {
805     XFree(property);
806     return false;
807   }
808
809   *value = *(reinterpret_cast<XID*>(property));
810   XFree(property);
811   return true;
812 }
813
814 bool GetIntArrayProperty(XID window,
815                          const std::string& property_name,
816                          std::vector<int>* value) {
817   Atom type = None;
818   int format = 0;  // size in bits of each item in 'property'
819   unsigned long num_items = 0;
820   unsigned char* properties = NULL;
821
822   int result = GetProperty(window, property_name,
823                            (~0L), // (all of them)
824                            &type, &format, &num_items, &properties);
825   if (result != Success)
826     return false;
827
828   if (format != 32) {
829     XFree(properties);
830     return false;
831   }
832
833   long* int_properties = reinterpret_cast<long*>(properties);
834   value->clear();
835   for (unsigned long i = 0; i < num_items; ++i) {
836     value->push_back(static_cast<int>(int_properties[i]));
837   }
838   XFree(properties);
839   return true;
840 }
841
842 bool GetAtomArrayProperty(XID window,
843                           const std::string& property_name,
844                           std::vector<Atom>* value) {
845   Atom type = None;
846   int format = 0;  // size in bits of each item in 'property'
847   unsigned long num_items = 0;
848   unsigned char* properties = NULL;
849
850   int result = GetProperty(window, property_name,
851                            (~0L), // (all of them)
852                            &type, &format, &num_items, &properties);
853   if (result != Success)
854     return false;
855
856   if (type != XA_ATOM) {
857     XFree(properties);
858     return false;
859   }
860
861   Atom* atom_properties = reinterpret_cast<Atom*>(properties);
862   value->clear();
863   value->insert(value->begin(), atom_properties, atom_properties + num_items);
864   XFree(properties);
865   return true;
866 }
867
868 bool GetStringProperty(
869     XID window, const std::string& property_name, std::string* value) {
870   Atom type = None;
871   int format = 0;  // size in bits of each item in 'property'
872   unsigned long num_items = 0;
873   unsigned char* property = NULL;
874
875   int result = GetProperty(window, property_name, 1024,
876                            &type, &format, &num_items, &property);
877   if (result != Success)
878     return false;
879
880   if (format != 8) {
881     XFree(property);
882     return false;
883   }
884
885   value->assign(reinterpret_cast<char*>(property), num_items);
886   XFree(property);
887   return true;
888 }
889
890 bool SetIntProperty(XID window,
891                     const std::string& name,
892                     const std::string& type,
893                     int value) {
894   std::vector<int> values(1, value);
895   return SetIntArrayProperty(window, name, type, values);
896 }
897
898 bool SetIntArrayProperty(XID window,
899                          const std::string& name,
900                          const std::string& type,
901                          const std::vector<int>& value) {
902   DCHECK(!value.empty());
903   Atom name_atom = GetAtom(name.c_str());
904   Atom type_atom = GetAtom(type.c_str());
905
906   // XChangeProperty() expects values of type 32 to be longs.
907   scoped_ptr<long[]> data(new long[value.size()]);
908   for (size_t i = 0; i < value.size(); ++i)
909     data[i] = value[i];
910
911   base::X11ErrorTracker err_tracker;
912   XChangeProperty(gfx::GetXDisplay(),
913                   window,
914                   name_atom,
915                   type_atom,
916                   32,  // size in bits of items in 'value'
917                   PropModeReplace,
918                   reinterpret_cast<const unsigned char*>(data.get()),
919                   value.size());  // num items
920   return !err_tracker.FoundNewError();
921 }
922
923 bool SetAtomArrayProperty(XID window,
924                           const std::string& name,
925                           const std::string& type,
926                           const std::vector<Atom>& value) {
927   DCHECK(!value.empty());
928   Atom name_atom = GetAtom(name.c_str());
929   Atom type_atom = GetAtom(type.c_str());
930
931   // XChangeProperty() expects values of type 32 to be longs.
932   scoped_ptr<Atom[]> data(new Atom[value.size()]);
933   for (size_t i = 0; i < value.size(); ++i)
934     data[i] = value[i];
935
936   base::X11ErrorTracker err_tracker;
937   XChangeProperty(gfx::GetXDisplay(),
938                   window,
939                   name_atom,
940                   type_atom,
941                   32,  // size in bits of items in 'value'
942                   PropModeReplace,
943                   reinterpret_cast<const unsigned char*>(data.get()),
944                   value.size());  // num items
945   return !err_tracker.FoundNewError();
946 }
947
948 Atom GetAtom(const char* name) {
949 #if defined(TOOLKIT_GTK)
950   return gdk_x11_get_xatom_by_name_for_display(
951       gdk_display_get_default(), name);
952 #else
953   // TODO(derat): Cache atoms to avoid round-trips to the server.
954   return XInternAtom(gfx::GetXDisplay(), name, false);
955 #endif
956 }
957
958 void SetWindowClassHint(XDisplay* display,
959                         XID window,
960                         const std::string& res_name,
961                         const std::string& res_class) {
962   XClassHint class_hints;
963   // const_cast is safe because XSetClassHint does not modify the strings.
964   // Just to be safe, the res_name and res_class parameters are local copies,
965   // not const references.
966   class_hints.res_name = const_cast<char*>(res_name.c_str());
967   class_hints.res_class = const_cast<char*>(res_class.c_str());
968   XSetClassHint(display, window, &class_hints);
969 }
970
971 void SetWindowRole(XDisplay* display, XID window, const std::string& role) {
972   if (role.empty()) {
973     XDeleteProperty(display, window, GetAtom("WM_WINDOW_ROLE"));
974   } else {
975     char* role_c = const_cast<char*>(role.c_str());
976     XChangeProperty(display, window, GetAtom("WM_WINDOW_ROLE"), XA_STRING, 8,
977                     PropModeReplace,
978                     reinterpret_cast<unsigned char*>(role_c),
979                     role.size());
980   }
981 }
982
983 XID GetParentWindow(XID window) {
984   XID root = None;
985   XID parent = None;
986   XID* children = NULL;
987   unsigned int num_children = 0;
988   XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children, &num_children);
989   if (children)
990     XFree(children);
991   return parent;
992 }
993
994 XID GetHighestAncestorWindow(XID window, XID root) {
995   while (true) {
996     XID parent = GetParentWindow(window);
997     if (parent == None)
998       return None;
999     if (parent == root)
1000       return window;
1001     window = parent;
1002   }
1003 }
1004
1005 bool GetWindowDesktop(XID window, int* desktop) {
1006   return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
1007 }
1008
1009 std::string GetX11ErrorString(XDisplay* display, int err) {
1010   char buffer[256];
1011   XGetErrorText(display, err, buffer, arraysize(buffer));
1012   return buffer;
1013 }
1014
1015 // Returns true if |window| is a named window.
1016 bool IsWindowNamed(XID window) {
1017   XTextProperty prop;
1018   if (!XGetWMName(gfx::GetXDisplay(), window, &prop) || !prop.value)
1019     return false;
1020
1021   XFree(prop.value);
1022   return true;
1023 }
1024
1025 bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
1026                        const int max_depth, int depth) {
1027   if (depth > max_depth)
1028     return false;
1029
1030   XID root, parent, *children;
1031   unsigned int num_children;
1032   int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children,
1033                           &num_children);
1034   if (status == 0)
1035     return false;
1036
1037   std::vector<XID> windows;
1038   for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
1039     windows.push_back(children[i]);
1040
1041   XFree(children);
1042
1043   // XQueryTree returns the children of |window| in bottom-to-top order, so
1044   // reverse-iterate the list to check the windows from top-to-bottom.
1045   std::vector<XID>::iterator iter;
1046   for (iter = windows.begin(); iter != windows.end(); iter++) {
1047     if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
1048       return true;
1049   }
1050
1051   // If we're at this point, we didn't find the window we're looking for at the
1052   // current level, so we need to recurse to the next level.  We use a second
1053   // loop because the recursion and call to XQueryTree are expensive and is only
1054   // needed for a small number of cases.
1055   if (++depth <= max_depth) {
1056     for (iter = windows.begin(); iter != windows.end(); iter++) {
1057       if (EnumerateChildren(delegate, *iter, max_depth, depth))
1058         return true;
1059     }
1060   }
1061
1062   return false;
1063 }
1064
1065 bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
1066   XID root = GetX11RootWindow();
1067   return EnumerateChildren(delegate, root, max_depth, 0);
1068 }
1069
1070 void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
1071   std::vector<XID> stack;
1072   if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
1073     // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
1074     // to old school enumeration of all X windows.  Some WMs parent 'top-level'
1075     // windows in unnamed actual top-level windows (ion WM), so extend the
1076     // search depth to all children of top-level windows.
1077     const int kMaxSearchDepth = 1;
1078     ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
1079     return;
1080   }
1081
1082   std::vector<XID>::iterator iter;
1083   for (iter = stack.begin(); iter != stack.end(); iter++) {
1084     if (delegate->ShouldStopIterating(*iter))
1085       return;
1086   }
1087 }
1088
1089 bool GetXWindowStack(Window window, std::vector<XID>* windows) {
1090   windows->clear();
1091
1092   Atom type;
1093   int format;
1094   unsigned long count;
1095   unsigned char *data = NULL;
1096   if (GetProperty(window,
1097                   "_NET_CLIENT_LIST_STACKING",
1098                   ~0L,
1099                   &type,
1100                   &format,
1101                   &count,
1102                   &data) != Success) {
1103     return false;
1104   }
1105
1106   bool result = false;
1107   if (type == XA_WINDOW && format == 32 && data && count > 0) {
1108     result = true;
1109     XID* stack = reinterpret_cast<XID*>(data);
1110     for (long i = static_cast<long>(count) - 1; i >= 0; i--)
1111       windows->push_back(stack[i]);
1112   }
1113
1114   if (data)
1115     XFree(data);
1116
1117   return result;
1118 }
1119
1120 void RestackWindow(XID window, XID sibling, bool above) {
1121   XWindowChanges changes;
1122   changes.sibling = sibling;
1123   changes.stack_mode = above ? Above : Below;
1124   XConfigureWindow(gfx::GetXDisplay(), window, CWSibling | CWStackMode, &changes);
1125 }
1126
1127 XSharedMemoryId AttachSharedMemory(XDisplay* display, int shared_memory_key) {
1128   DCHECK(QuerySharedMemorySupport(display));
1129
1130   XShmSegmentInfo shminfo;
1131   memset(&shminfo, 0, sizeof(shminfo));
1132   shminfo.shmid = shared_memory_key;
1133
1134   // This function is only called if QuerySharedMemorySupport returned true. In
1135   // which case we've already succeeded in having the X server attach to one of
1136   // our shared memory segments.
1137   if (!XShmAttach(display, &shminfo)) {
1138     LOG(WARNING) << "X failed to attach to shared memory segment "
1139                  << shminfo.shmid;
1140     NOTREACHED();
1141   } else {
1142     VLOG(1) << "X attached to shared memory segment " << shminfo.shmid;
1143   }
1144
1145   return shminfo.shmseg;
1146 }
1147
1148 void DetachSharedMemory(XDisplay* display, XSharedMemoryId shmseg) {
1149   DCHECK(QuerySharedMemorySupport(display));
1150
1151   XShmSegmentInfo shminfo;
1152   memset(&shminfo, 0, sizeof(shminfo));
1153   shminfo.shmseg = shmseg;
1154
1155   if (!XShmDetach(display, &shminfo))
1156     NOTREACHED();
1157 }
1158
1159 bool CopyAreaToCanvas(XID drawable,
1160                       gfx::Rect source_bounds,
1161                       gfx::Point dest_offset,
1162                       gfx::Canvas* canvas) {
1163   ui::XScopedImage scoped_image(
1164       XGetImage(gfx::GetXDisplay(), drawable,
1165                 source_bounds.x(), source_bounds.y(),
1166                 source_bounds.width(), source_bounds.height(),
1167                 AllPlanes, ZPixmap));
1168   XImage* image = scoped_image.get();
1169   if (!image) {
1170     LOG(ERROR) << "XGetImage failed";
1171     return false;
1172   }
1173
1174   if (image->bits_per_pixel == 32) {
1175     if ((0xff << SK_R32_SHIFT) != image->red_mask ||
1176         (0xff << SK_G32_SHIFT) != image->green_mask ||
1177         (0xff << SK_B32_SHIFT) != image->blue_mask) {
1178       LOG(WARNING) << "XImage and Skia byte orders differ";
1179       return false;
1180     }
1181
1182     // Set the alpha channel before copying to the canvas.  Otherwise, areas of
1183     // the framebuffer that were cleared by ply-image rather than being obscured
1184     // by an image during boot may end up transparent.
1185     // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
1186     // set the framebuffer's alpha channel regardless of whether the device
1187     // claims to support alpha or not.
1188     for (int i = 0; i < image->width * image->height * 4; i += 4)
1189       image->data[i + 3] = 0xff;
1190
1191     SkBitmap bitmap;
1192     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
1193                      image->width, image->height,
1194                      image->bytes_per_line);
1195     bitmap.setPixels(image->data);
1196     gfx::ImageSkia image_skia;
1197     gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
1198     image_skia.AddRepresentation(image_rep);
1199     canvas->DrawImageInt(image_skia, dest_offset.x(), dest_offset.y());
1200   } else {
1201     NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
1202     return false;
1203   }
1204
1205   return true;
1206 }
1207
1208 XID CreatePictureFromSkiaPixmap(XDisplay* display, XID pixmap) {
1209   XID picture = XRenderCreatePicture(
1210       display, pixmap, GetRenderARGB32Format(display), 0, NULL);
1211
1212   return picture;
1213 }
1214
1215 void FreePicture(XDisplay* display, XID picture) {
1216   XRenderFreePicture(display, picture);
1217 }
1218
1219 void FreePixmap(XDisplay* display, XID pixmap) {
1220   XFreePixmap(display, pixmap);
1221 }
1222
1223 bool GetWindowManagerName(std::string* wm_name) {
1224   DCHECK(wm_name);
1225   int wm_window = 0;
1226   if (!GetIntProperty(GetX11RootWindow(),
1227                       "_NET_SUPPORTING_WM_CHECK",
1228                       &wm_window)) {
1229     return false;
1230   }
1231
1232   // It's possible that a window manager started earlier in this X session left
1233   // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
1234   // non-EWMH window manager, so we trap errors in the following requests to
1235   // avoid crashes (issue 23860).
1236
1237   // EWMH requires the supporting-WM window to also have a
1238   // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
1239   // property referencing an ID that's been recycled for another window), so we
1240   // check that too.
1241   base::X11ErrorTracker err_tracker;
1242   int wm_window_property = 0;
1243   bool result = GetIntProperty(
1244       wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
1245   if (err_tracker.FoundNewError() || !result ||
1246       wm_window_property != wm_window) {
1247     return false;
1248   }
1249
1250   result = GetStringProperty(
1251       static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
1252   return !err_tracker.FoundNewError() && result;
1253 }
1254
1255 WindowManagerName GuessWindowManager() {
1256   std::string name;
1257   if (GetWindowManagerName(&name)) {
1258     // These names are taken from the WMs' source code.
1259     if (name == "Blackbox")
1260       return WM_BLACKBOX;
1261     if (name == "chromeos-wm")
1262       return WM_CHROME_OS;
1263     if (name == "Compiz" || name == "compiz")
1264       return WM_COMPIZ;
1265     if (name == "e16")
1266       return WM_ENLIGHTENMENT;
1267     if (StartsWithASCII(name, "IceWM", true))
1268       return WM_ICE_WM;
1269     if (name == "KWin")
1270       return WM_KWIN;
1271     if (name == "Metacity")
1272       return WM_METACITY;
1273     if (name == "Mutter (Muffin)")
1274       return WM_MUFFIN;
1275     if (name == "GNOME Shell")
1276       return WM_MUTTER; // GNOME Shell uses Mutter
1277     if (name == "Mutter")
1278       return WM_MUTTER;
1279     if (name == "Openbox")
1280       return WM_OPENBOX;
1281     if (name == "Xfwm4")
1282       return WM_XFWM4;
1283   }
1284   return WM_UNKNOWN;
1285 }
1286
1287 bool ChangeWindowDesktop(XID window, XID destination) {
1288   int desktop;
1289   if (!GetWindowDesktop(destination, &desktop))
1290     return false;
1291
1292   // If |window| is sticky, use the current desktop.
1293   if (desktop == kAllDesktops &&
1294       !GetCurrentDesktop(&desktop))
1295     return false;
1296
1297   XEvent event;
1298   event.xclient.type = ClientMessage;
1299   event.xclient.window = window;
1300   event.xclient.message_type = GetAtom("_NET_WM_DESKTOP");
1301   event.xclient.format = 32;
1302   event.xclient.data.l[0] = desktop;
1303   event.xclient.data.l[1] = 1;  // source indication
1304
1305   int result = XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), False,
1306                           SubstructureNotifyMask, &event);
1307   return result == Success;
1308 }
1309
1310 void SetDefaultX11ErrorHandlers() {
1311   SetX11ErrorHandlers(NULL, NULL);
1312 }
1313
1314 bool IsX11WindowFullScreen(XID window) {
1315   // If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
1316   // absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
1317   // whether we're fullscreen.
1318   std::vector<Atom> supported_atoms;
1319   if (GetAtomArrayProperty(GetX11RootWindow(),
1320                            "_NET_SUPPORTED",
1321                            &supported_atoms)) {
1322     Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
1323
1324     if (std::find(supported_atoms.begin(), supported_atoms.end(), atom)
1325         != supported_atoms.end()) {
1326       std::vector<Atom> atom_properties;
1327       if (GetAtomArrayProperty(window,
1328                                "_NET_WM_STATE",
1329                                &atom_properties)) {
1330         return std::find(atom_properties.begin(), atom_properties.end(), atom)
1331             != atom_properties.end();
1332       }
1333     }
1334   }
1335
1336   gfx::Rect window_rect;
1337   if (!ui::GetWindowRect(window, &window_rect))
1338     return false;
1339
1340 #if defined(TOOLKIT_GTK)
1341   // As the last resort, check if the window size is as large as the main
1342   // screen.
1343   GdkRectangle monitor_rect;
1344   gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect);
1345
1346   return monitor_rect.x == window_rect.x() &&
1347          monitor_rect.y == window_rect.y() &&
1348          monitor_rect.width == window_rect.width() &&
1349          monitor_rect.height == window_rect.height();
1350 #else
1351   // We can't use gfx::Screen here because we don't have an aura::Window. So
1352   // instead just look at the size of the default display.
1353   //
1354   // TODO(erg): Actually doing this correctly would require pulling out xrandr,
1355   // which we don't even do in the desktop screen yet.
1356   ::XDisplay* display = gfx::GetXDisplay();
1357   ::Screen* screen = DefaultScreenOfDisplay(display);
1358   int width = WidthOfScreen(screen);
1359   int height = HeightOfScreen(screen);
1360   return window_rect.size() == gfx::Size(width, height);
1361 #endif
1362 }
1363
1364 bool IsXDisplaySizeBlackListed(unsigned long mm_width,
1365                                unsigned long mm_height) {
1366   // Ignore if the reported display is smaller than minimum size.
1367   if (mm_width <= kInvalidDisplaySizeList[0][0] ||
1368       mm_height <= kInvalidDisplaySizeList[0][1]) {
1369     LOG(WARNING) << "Smaller than minimum display size";
1370     return true;
1371   }
1372   for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
1373     const unsigned long* size = kInvalidDisplaySizeList[i];
1374     if (mm_width == size[0] && mm_height == size[1]) {
1375       LOG(WARNING) << "Black listed display size detected:"
1376                    << size[0] << "x" << size[1];
1377       return true;
1378     }
1379   }
1380   return false;
1381 }
1382
1383 const unsigned char* XRefcountedMemory::front() const {
1384   return x11_data_;
1385 }
1386
1387 size_t XRefcountedMemory::size() const {
1388   return length_;
1389 }
1390
1391 XRefcountedMemory::~XRefcountedMemory() {
1392   XFree(x11_data_);
1393 }
1394
1395 XScopedString::~XScopedString() {
1396   XFree(string_);
1397 }
1398
1399 XScopedImage::~XScopedImage() {
1400   reset(NULL);
1401 }
1402
1403 void XScopedImage::reset(XImage* image) {
1404   if (image_ == image)
1405     return;
1406   if (image_)
1407     XDestroyImage(image_);
1408   image_ = image;
1409 }
1410
1411 XScopedCursor::XScopedCursor(::Cursor cursor, XDisplay* display)
1412     : cursor_(cursor),
1413       display_(display) {
1414 }
1415
1416 XScopedCursor::~XScopedCursor() {
1417   reset(0U);
1418 }
1419
1420 ::Cursor XScopedCursor::get() const {
1421   return cursor_;
1422 }
1423
1424 void XScopedCursor::reset(::Cursor cursor) {
1425   if (cursor_)
1426     XFreeCursor(display_, cursor_);
1427   cursor_ = cursor;
1428 }
1429
1430 // ----------------------------------------------------------------------------
1431 // These functions are declared in x11_util_internal.h because they require
1432 // XLib.h to be included, and it conflicts with many other headers.
1433 XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
1434   static XRenderPictFormat* pictformat = NULL;
1435   if (pictformat)
1436     return pictformat;
1437
1438   // First look for a 32-bit format which ignores the alpha value
1439   XRenderPictFormat templ;
1440   templ.depth = 32;
1441   templ.type = PictTypeDirect;
1442   templ.direct.red = 16;
1443   templ.direct.green = 8;
1444   templ.direct.blue = 0;
1445   templ.direct.redMask = 0xff;
1446   templ.direct.greenMask = 0xff;
1447   templ.direct.blueMask = 0xff;
1448   templ.direct.alphaMask = 0;
1449
1450   static const unsigned long kMask =
1451     PictFormatType | PictFormatDepth |
1452     PictFormatRed | PictFormatRedMask |
1453     PictFormatGreen | PictFormatGreenMask |
1454     PictFormatBlue | PictFormatBlueMask |
1455     PictFormatAlphaMask;
1456
1457   pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
1458
1459   if (!pictformat) {
1460     // Not all X servers support xRGB32 formats. However, the XRENDER spec says
1461     // that they must support an ARGB32 format, so we can always return that.
1462     pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
1463     CHECK(pictformat) << "XRENDER ARGB32 not supported.";
1464   }
1465
1466   return pictformat;
1467 }
1468
1469 XRenderPictFormat* GetRenderVisualFormat(XDisplay* dpy, Visual* visual) {
1470   DCHECK(QueryRenderSupport(dpy));
1471
1472   CachedPictFormats* formats = get_cached_pict_formats();
1473
1474   for (CachedPictFormats::const_iterator i = formats->begin();
1475        i != formats->end(); ++i) {
1476     if (i->equals(dpy, visual))
1477       return i->format;
1478   }
1479
1480   // Not cached, look up the value.
1481   XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
1482   CHECK(pictformat) << "XRENDER does not support default visual";
1483
1484   // And store it in the cache.
1485   CachedPictFormat cached_value;
1486   cached_value.visual = visual;
1487   cached_value.display = dpy;
1488   cached_value.format = pictformat;
1489   formats->push_front(cached_value);
1490
1491   if (formats->size() == kMaxCacheSize) {
1492     formats->pop_back();
1493     // We should really only have at most 2 display/visual combinations:
1494     // one for normal browser windows, and possibly another for an argb window
1495     // created to display a menu.
1496     //
1497     // If we get here it's not fatal, we just need to make sure we aren't
1498     // always blowing away the cache. If we are, then we should figure out why
1499     // and make it bigger.
1500     NOTREACHED();
1501   }
1502
1503   return pictformat;
1504 }
1505
1506 void SetX11ErrorHandlers(XErrorHandler error_handler,
1507                          XIOErrorHandler io_error_handler) {
1508   XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
1509   XSetIOErrorHandler(
1510       io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
1511 }
1512
1513 void LogErrorEventDescription(XDisplay* dpy,
1514                               const XErrorEvent& error_event) {
1515   char error_str[256];
1516   char request_str[256];
1517
1518   XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
1519
1520   strncpy(request_str, "Unknown", sizeof(request_str));
1521   if (error_event.request_code < 128) {
1522     std::string num = base::UintToString(error_event.request_code);
1523     XGetErrorDatabaseText(
1524         dpy, "XRequest", num.c_str(), "Unknown", request_str,
1525         sizeof(request_str));
1526   } else {
1527     int num_ext;
1528     char** ext_list = XListExtensions(dpy, &num_ext);
1529
1530     for (int i = 0; i < num_ext; i++) {
1531       int ext_code, first_event, first_error;
1532       XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
1533       if (error_event.request_code == ext_code) {
1534         std::string msg = base::StringPrintf(
1535             "%s.%d", ext_list[i], error_event.minor_code);
1536         XGetErrorDatabaseText(
1537             dpy, "XRequest", msg.c_str(), "Unknown", request_str,
1538             sizeof(request_str));
1539         break;
1540       }
1541     }
1542     XFreeExtensionList(ext_list);
1543   }
1544
1545   LOG(WARNING)
1546       << "X error received: "
1547       << "serial " << error_event.serial << ", "
1548       << "error_code " << static_cast<int>(error_event.error_code)
1549       << " (" << error_str << "), "
1550       << "request_code " << static_cast<int>(error_event.request_code) << ", "
1551       << "minor_code " << static_cast<int>(error_event.minor_code)
1552       << " (" << request_str << ")";
1553 }
1554
1555 // ----------------------------------------------------------------------------
1556 // End of x11_util_internal.h
1557
1558
1559 }  // namespace ui