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