15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines utility functions for X11 (Linux only). This code has been
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ported from XCB since we can't use XCB on Ubuntu while its 32-bit support
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// remains woefully incomplete.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ipc.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/shm.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/extensions/shape.h>
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <X11/extensions/XInput2.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/debug/trace_event.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h"
317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_byteorder.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/x11/x11_error_tracker.h"
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "third_party/skia/include/core/SkPostConfig.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util_internal.h"
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event_utils.h"
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/keycodes/keyboard_code_conversion_x.h"
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/events/x/device_data_manager.h"
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/events/x/touch_factory_x11.h"
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/canvas.h"
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/image/image_skia_rep.h"
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/point.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point_conversions.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_FREEBSD)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/sysctl.h>
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xcursor/Xcursor.h>
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h"
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h"
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gdk/gdk.h>
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h>
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/gdk_compat.h"
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/gtk_compat.h"
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to cache the XRenderPictFormat for a visual/display pair.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct CachedPictFormat {
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool equals(XDisplay* display, Visual* visual) const {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return display == this->display && visual == this->visual;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Visual* visual;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat* format;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::list<CachedPictFormat> CachedPictFormats;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the cache of pict formats.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CachedPictFormats* get_cached_pict_formats() {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static CachedPictFormats* formats = NULL;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!formats)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    formats = new CachedPictFormats();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return formats;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of CachedPictFormats we keep around.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxCacheSize = 5;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (base::MessageLoop::current()) {
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(&LogErrorEventDescription, d, *e));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "X error received: "
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "serial " << e->serial << ", "
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "error_code " << static_cast<int>(e->error_code) << ", "
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "request_code " << static_cast<int>(e->request_code) << ", "
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "minor_code " << static_cast<int>(e->minor_code);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int DefaultX11IOErrorHandler(XDisplay* d) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there's an IO error it likely means the X server has gone away
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "X IO error received (X server probably went away)";
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _exit(1);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: The caller should free the resulting value data.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetProperty(XID window, const std::string& property_name, long max_length,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 Atom* type, int* format, unsigned long* num_items,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 unsigned char** property) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom property_atom = GetAtom(property_name.c_str());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long remaining_bytes = 0;
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return XGetWindowProperty(gfx::GetXDisplay(),
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            window,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            property_atom,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0,          // offset into property data to read
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            max_length, // max length to get
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            False,      // deleted
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            AnyPropertyType,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            type,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            format,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            num_items,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &remaining_bytes,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            property);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A process wide singleton that manages the usage of X cursors.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XCursorCache {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCursorCache() {}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XCursorCache() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Clear();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor GetCursor(int cursor_shape) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Lookup cursor by attempting to insert a null value, which avoids
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a second pass through the map after a cache miss.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::pair<std::map<int, ::Cursor>::iterator, bool> it = cache_.insert(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::make_pair(cursor_shape, 0));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it.second) {
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it.first->second = XCreateFontCursor(display, cursor_shape);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it.first->second;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Clear() {
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::map<int, ::Cursor>::iterator it =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cache_.begin(); it != cache_.end(); ++it) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XFreeCursor(display, it->second);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_.clear();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Maps X11 font cursor shapes to Cursor IDs.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<int, ::Cursor> cache_;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XCursorCache);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)XCursorCache* cursor_cache = NULL;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A process wide singleton cache for custom X cursors.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XCustomCursorCache {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static XCustomCursorCache* GetInstance() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<XCustomCursorCache>::get();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor InstallCustomCursor(XcursorImage* image) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XCustomCursor* custom_cursor = new XCustomCursor(image);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor xcursor = custom_cursor->cursor();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_[xcursor] = custom_cursor;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return xcursor;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Ref(::Cursor cursor) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_[cursor]->Ref();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Unref(::Cursor cursor) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cache_[cursor]->Unref())
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_.erase(cursor);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Clear() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_.clear();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<XCustomCursorCache>;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class XCustomCursor {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This takes ownership of the image.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XCustomCursor(XcursorImage* image)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : image_(image),
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ref_(1) {
21468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      cursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~XCustomCursor() {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XcursorImageDestroy(image_);
21968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      XFreeCursor(gfx::GetXDisplay(), cursor_);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor cursor() const { return cursor_; }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void Ref() {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++ref_;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Returns true if the cursor was destroyed because of the unref.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool Unref() {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (--ref_ == 0) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delete this;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XcursorImage* image_;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ref_;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor cursor_;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(XCustomCursor);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache() {}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XCustomCursorCache() {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Clear();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map< ::Cursor, XCustomCursor*> cache_;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XCustomCursorCache);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_AURA)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsShapeAvailable() {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool is_shape_available =
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_shape_available;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// A list of bogus sizes in mm that X detects that should be ignored.
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// See crbug.com/136533. The first element maintains the minimum
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// size required to be valid size.
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const unsigned long kInvalidDisplaySizeList[][2] = {
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {40, 30},
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {50, 40},
269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {160, 90},
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {160, 100},
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XDisplayExists() {
27668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return (gfx::GetXDisplay() != NULL);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsXInput2Available() {
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return DeviceDataManager::GetInstance()->IsXInput2Available();
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
28368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static SharedMemorySupport DoQuerySharedMemorySupport(XDisplay* dpy) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bool pixmaps_supported;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Query the server's support for XSHM.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_FREEBSD)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On FreeBSD we can't access the shared memory after it was marked for
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deletion, unless this behaviour is explicitly enabled by the user.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In case it's not enabled disable shared memory support.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int allow_removed;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t length = sizeof(allow_removed);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((sysctlbyname("kern.ipc.shm_allow_removed", &allow_removed, &length,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, 0) < 0) || allow_removed < 1) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next we probe to see if shared memory will really work
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shmkey = shmget(IPC_PRIVATE, 1, 0600);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shmkey == -1) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Failed to get shared memory segment.";
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Got shared memory segment " << shmkey;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* address = shmat(shmkey, NULL, 0);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the shared memory region for deletion
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shmctl(shmkey, IPC_RMID, NULL);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmid = shmkey;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::X11ErrorTracker err_tracker;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = XShmAttach(dpy, &shminfo);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "X got shared memory segment " << shmkey;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
326d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (err_tracker.FoundNewError())
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = false;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shmdt(address);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "X attached to shared memory segment " << shmkey;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmDetach(dpy, &shminfo);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pixmaps_supported ? SHARED_MEMORY_PIXMAP : SHARED_MEMORY_PUTIMAGE;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SharedMemorySupport shared_memory_support = SHARED_MEMORY_NONE;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool shared_memory_support_cached = false;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shared_memory_support_cached)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return shared_memory_support;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shared_memory_support = DoQuerySharedMemorySupport(dpy);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shared_memory_support_cached = true;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shared_memory_support;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool QueryRenderSupport(XDisplay* dpy) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool render_supported = false;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool render_supported_cached = false;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (render_supported_cached)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return render_supported;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't care about the version of Xrender since all the features which
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we use are included in every version.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_supported_cached = true;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return render_supported;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int GetDefaultScreen(XDisplay* display) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XDefaultScreen(display);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor GetXCursor(int cursor_shape) {
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!cursor_cache)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cursor_cache = new XCursorCache;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return cursor_cache->GetCursor(cursor_shape);
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResetXCursorCache() {
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete cursor_cache;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cursor_cache = NULL;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor CreateReffedCustomXCursor(XcursorImage* image) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XCustomCursorCache::GetInstance()->InstallCustomCursor(image);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RefCustomXCursor(::Cursor cursor) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache::GetInstance()->Ref(cursor);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnrefCustomXCursor(::Cursor cursor) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache::GetInstance()->Unref(cursor);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XcursorImage* SkBitmapToXcursorImage(const SkBitmap* cursor_image,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const gfx::Point& hotspot) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cursor_image->config() == SkBitmap::kARGB_8888_Config);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point hotspot_point = hotspot;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap scaled;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // X11 seems to have issues with cursors when images get larger than 64
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pixels. So rescale the image if necessary.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const float kMaxPixel = 64.f;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool needs_scale = false;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cursor_image->width() > kMaxPixel || cursor_image->height() > kMaxPixel) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float scale = 1.f;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cursor_image->width() > cursor_image->height())
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scale = kMaxPixel / cursor_image->width();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scale = kMaxPixel / cursor_image->height();
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scaled = skia::ImageOperations::Resize(*cursor_image,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        skia::ImageOperations::RESIZE_BETTER,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<int>(cursor_image->width() * scale),
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<int>(cursor_image->height() * scale));
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hotspot_point = gfx::ToFlooredPoint(gfx::ScalePoint(hotspot, scale));
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needs_scale = true;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SkBitmap* bitmap = needs_scale ? &scaled : cursor_image;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XcursorImage* image = XcursorImageCreate(bitmap->width(), bitmap->height());
424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  image->xhot = std::min(bitmap->width() - 1, hotspot_point.x());
425a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  image->yhot = std::min(bitmap->height() - 1, hotspot_point.y());
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bitmap->width() && bitmap->height()) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap->lockPixels();
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The |bitmap| contains ARGB image, so just copy it.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(image->pixels,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           bitmap->getPixels(),
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           bitmap->width() * bitmap->height() * 4);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap->unlockPixels();
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return image;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CoalescePendingMotionEvents(const XEvent* xev,
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                XEvent* last_event) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int num_coalesced = 0;
44468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display = xev->xany.display;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int event_type = xev->xgeneric.evtype;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(event_type == XI_Motion || event_type == XI_TouchUpdate);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (XPending(display)) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XEvent next_event;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XPeekEvent(display, &next_event);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we can't get the cookie, abort the check.
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!XGetEventData(next_event.xgeneric.display, &next_event.xcookie))
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return num_coalesced;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this isn't from a valid device, throw the event away, as
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that's what the message pump would do. Device events come in pairs
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with one from the master and one from the slave so there will
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // always be at least one pending.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(&next_event)) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XFreeEventData(display, &next_event.xcookie);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XNextEvent(display, &next_event);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (next_event.type == GenericEvent &&
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_event.xgeneric.evtype == event_type &&
4697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        !ui::DeviceDataManager::GetInstance()->IsCMTGestureEvent(
4707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            &next_event)) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XIDeviceEvent* next_xievent =
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<XIDeviceEvent*>(next_event.xcookie.data);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Confirm that the motion event is targeted at the same window
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and that no buttons or modifiers have changed.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (xievent->event == next_xievent->event &&
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->child == next_xievent->child &&
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          xievent->detail == next_xievent->detail &&
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->buttons.mask_len == next_xievent->buttons.mask_len &&
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (memcmp(xievent->buttons.mask,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  next_xievent->buttons.mask,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  xievent->buttons.mask_len) == 0) &&
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.base == next_xievent->mods.base &&
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.latched == next_xievent->mods.latched &&
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.locked == next_xievent->mods.locked &&
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.effective == next_xievent->mods.effective) {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XFreeEventData(display, &next_event.xcookie);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Free the previous cookie.
48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (num_coalesced > 0)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          XFreeEventData(display, &last_event->xcookie);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Get the event and its cookie data.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XNextEvent(display, last_event);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XGetEventData(display, &last_event->xcookie);
49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        ++num_coalesced;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // This isn't an event we want so free its cookie data.
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    XFreeEventData(display, &next_event.xcookie);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    break;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (event_type == XI_Motion && num_coalesced > 0) {
503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::TimeDelta delta = ui::EventTimeFromNative(last_event) -
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ui::EventTimeFromNative(const_cast<XEvent*>(xev));
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UMA_HISTOGRAM_COUNTS_10000("Event.CoalescedCount.Mouse", num_coalesced);
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UMA_HISTOGRAM_TIMES("Event.CoalescedLatency.Mouse", delta);
507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return num_coalesced;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HideHostCursor() {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
51468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                         (CreateInvisibleCursor(), gfx::GetXDisplay()));
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDefineCursor(gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()),
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                invisible_cursor.get());
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor CreateInvisibleCursor() {
52068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* xdisplay = gfx::GetXDisplay();
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor invisible_cursor;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XColor black;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  black.red = black.green = black.blue = 0;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Pixmap blank = XCreateBitmapFromData(xdisplay,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       DefaultRootWindow(xdisplay),
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       nodata, 8, 8);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invisible_cursor = XCreatePixmapCursor(xdisplay, blank, blank,
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &black, &black, 0, 0);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFreePixmap(xdisplay, blank);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return invisible_cursor;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11RootWindow() {
53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return DefaultRootWindow(gfx::GetXDisplay());
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetCurrentDesktop(int* desktop) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_WINDOW_XID(gtk_widget_get_window(widget));
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11WindowFromGdkWindow(GdkWindow* window) {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_WINDOW_XID(window);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWindow* GetGtkWindowFromX11Window(XID xid) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkWindow* gdk_window =
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gdk_window)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWindow* gtk_window = NULL;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_window_get_user_data(gdk_window,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           reinterpret_cast<gpointer*>(&gtk_window));
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gtk_window)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gtk_window;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GetVisualFromGtkWidget(GtkWidget* widget) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(TOOLKIT_GTK)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetHideTitlebarWhenMaximizedProperty(XID window,
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HideTitlebarWhenMaximized property) {
5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // XChangeProperty() expects "hide" to be long.
5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  unsigned long hide = property;
57368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XChangeProperty(gfx::GetXDisplay(),
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XA_CARDINAL,
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      32,  // size in bits
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PropModeReplace,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<unsigned char*>(&hide),
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ClearX11DefaultRootWindow() {
58468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display = gfx::GetXDisplay();
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XID root_window = GetX11RootWindow();
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect root_bounds;
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetWindowRect(root_window, &root_bounds)) {
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to get the bounds of the X11 root window";
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XGCValues gc_values = {0};
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gc_values.foreground = BlackPixel(display, DefaultScreen(display));
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GC gc = XCreateGC(display, root_window, GCForeground, &gc_values);
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFillRectangle(display, root_window, gc,
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.x(),
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.y(),
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.width(),
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.height());
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFreeGC(display, gc);
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsWindowVisible(XID window) {
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("ui", "IsWindowVisible");
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowAttributes win_attributes;
60768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!XGetWindowAttributes(gfx::GetXDisplay(), window, &win_attributes))
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (win_attributes.map_state != IsViewable)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some compositing window managers (notably kwin) do not actually unmap
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // windows on desktop switch, so we also must check the current desktop.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int window_desktop, current_desktop;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (!GetWindowDesktop(window, &window_desktop) ||
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          !GetCurrentDesktop(&current_desktop) ||
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window_desktop == kAllDesktops ||
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window_desktop == current_desktop);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowRect(XID window, gfx::Rect* rect) {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window root, child;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x, y;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int width, height;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int border_width, depth;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
62668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!XGetGeometry(gfx::GetXDisplay(), window, &root, &x, &y,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    &width, &height, &border_width, &depth))
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
63068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!XTranslateCoordinates(gfx::GetXDisplay(), window, root,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             0, 0, &x, &y, &child))
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *rect = gfx::Rect(x, y, width, height);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("ui", "WindowContainsPoint");
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_rect;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetWindowRect(window, &window_rect))
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window_rect.Contains(screen_loc))
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsShapeAvailable())
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // According to http://www.x.org/releases/X11R7.6/doc/libXext/shapelib.html,
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if an X display supports the shape extension the bounds of a window are
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // defined as the intersection of the window bounds and the interior
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // rectangles. This means to determine if a point is inside a window for the
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // purpose of input handling we have to check the rectangles in the ShapeInput
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // list.
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_rects_size = 0;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRectangle* input_rects = XShapeGetRectangles(
66168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      gfx::GetXDisplay(), window, ShapeInput, &input_rects_size, &dummy);
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!input_rects)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_in_input_rects = false;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < input_rects_size; ++i) {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ShapeInput rects appear to be in window space, so we have to
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // translate by the window_rect's offset to map to screen space.
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect input_rect =
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gfx::Rect(input_rects[i].x + window_rect.x(),
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  input_rects[i].y + window_rect.y(),
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  input_rects[i].width, input_rects[i].height);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (input_rect.Contains(screen_loc)) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_in_input_rects = true;
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(input_rects);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_in_input_rects;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PropertyExists(XID window, const std::string& property_name) {
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1,
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return num_items > 0;
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
697eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool GetRawBytesOfProperty(XID window,
698eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           Atom property,
699eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           scoped_refptr<base::RefCountedMemory>* out_data,
700eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           size_t* out_data_bytes,
701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           size_t* out_data_items,
702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           Atom* out_type) {
703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Retrieve the data from our window.
704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned long nitems = 0;
705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned long nbytes = 0;
706eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Atom prop_type = None;
707eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int prop_format = 0;
708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned char* property_data = NULL;
70968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (XGetWindowProperty(gfx::GetXDisplay(), window, property,
710eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
711eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         AnyPropertyType, &prop_type, &prop_format,
712eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         &nitems, &nbytes, &property_data) != Success) {
713eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
714eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
715eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
716eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (prop_type == None)
717eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
718eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
719eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t bytes = 0;
720eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // So even though we should theoretically have nbytes (and we can't
721eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // pass NULL there), we need to manually calculate the byte length here
722eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // because nbytes always returns zero.
723eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (prop_format) {
724eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case 8:
725eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bytes = nitems;
726eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
727eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case 16:
728eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bytes = sizeof(short) * nitems;
729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
730eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case 32:
731eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bytes = sizeof(long) * nitems;
732eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
733eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default:
734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NOTREACHED();
735eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
736eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
737eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
738eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (out_data_bytes)
739eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *out_data_bytes = bytes;
740eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
741eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (out_data)
742eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *out_data = new XRefcountedMemory(property_data, bytes);
743eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  else
744eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    XFree(property_data);
745eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
746eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (out_data_items)
747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *out_data_items = nitems;
748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (out_type)
750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *out_type = prop_type;
751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetIntProperty(XID window, const std::string& property_name, int* value) {
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1,
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 32 || num_items != 1) {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(property);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *value = static_cast<int>(*(reinterpret_cast<long*>(property)));
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
776eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool GetXIDProperty(XID window, const std::string& property_name, XID* value) {
777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Atom type = None;
778eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int format = 0;  // size in bits of each item in 'property'
779eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned long num_items = 0;
780eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned char* property = NULL;
781eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
782eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int result = GetProperty(window, property_name, 1,
783eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           &type, &format, &num_items, &property);
784eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (result != Success)
785eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
786eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
787eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (format != 32 || num_items != 1) {
788eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    XFree(property);
789eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
790eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
791eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
792eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  *value = *(reinterpret_cast<XID*>(property));
793eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  XFree(property);
794eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
795eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
796eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetIntArrayProperty(XID window,
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& property_name,
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         std::vector<int>* value) {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* properties = NULL;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name,
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           (~0L), // (all of them)
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &properties);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 32) {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(properties);
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  long* int_properties = reinterpret_cast<long*>(properties);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->clear();
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned long i = 0; i < num_items; ++i) {
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->push_back(static_cast<int>(int_properties[i]));
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(properties);
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetAtomArrayProperty(XID window,
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const std::string& property_name,
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          std::vector<Atom>* value) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* properties = NULL;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name,
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           (~0L), // (all of them)
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &properties);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type != XA_ATOM) {
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(properties);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom* atom_properties = reinterpret_cast<Atom*>(properties);
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->clear();
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->insert(value->begin(), atom_properties, atom_properties + num_items);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(properties);
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetStringProperty(
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID window, const std::string& property_name, std::string* value) {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1024,
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 8) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(property);
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->assign(reinterpret_cast<char*>(property), num_items);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetIntProperty(XID window,
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& name,
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& type,
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int value) {
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> values(1, value);
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SetIntArrayProperty(window, name, type, values);
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetIntArrayProperty(XID window,
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& name,
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& type,
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::vector<int>& value) {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!value.empty());
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom name_atom = GetAtom(name.c_str());
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type_atom = GetAtom(type.c_str());
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // XChangeProperty() expects values of type 32 to be longs.
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<long[]> data(new long[value.size()]);
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < value.size(); ++i)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data[i] = value[i];
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::X11ErrorTracker err_tracker;
89568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XChangeProperty(gfx::GetXDisplay(),
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  window,
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  name_atom,
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  type_atom,
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  32,  // size in bits of items in 'value'
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  PropModeReplace,
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  reinterpret_cast<const unsigned char*>(data.get()),
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  value.size());  // num items
903d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return !err_tracker.FoundNewError();
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
906eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SetAtomArrayProperty(XID window,
907eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::string& name,
908eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::string& type,
909eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::vector<Atom>& value) {
910eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!value.empty());
911eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Atom name_atom = GetAtom(name.c_str());
912eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Atom type_atom = GetAtom(type.c_str());
913eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
914eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // XChangeProperty() expects values of type 32 to be longs.
915eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<Atom[]> data(new Atom[value.size()]);
916eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < value.size(); ++i)
917eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    data[i] = value[i];
918eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::X11ErrorTracker err_tracker;
92068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XChangeProperty(gfx::GetXDisplay(),
921eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  window,
922eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  name_atom,
923eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  type_atom,
924eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  32,  // size in bits of items in 'value'
925eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  PropModeReplace,
926eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  reinterpret_cast<const unsigned char*>(data.get()),
927eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  value.size());  // num items
928d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return !err_tracker.FoundNewError();
929eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
930eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Atom GetAtom(const char* name) {
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gdk_x11_get_xatom_by_name_for_display(
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_display_get_default(), name);
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(derat): Cache atoms to avoid round-trips to the server.
93768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return XInternAtom(gfx::GetXDisplay(), name, false);
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
94168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void SetWindowClassHint(XDisplay* display,
94258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                        XID window,
943f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        const std::string& res_name,
944f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        const std::string& res_class) {
94558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  XClassHint class_hints;
94658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // const_cast is safe because XSetClassHint does not modify the strings.
94758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Just to be safe, the res_name and res_class parameters are local copies,
94858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // not const references.
94958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  class_hints.res_name = const_cast<char*>(res_name.c_str());
95058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  class_hints.res_class = const_cast<char*>(res_class.c_str());
95158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  XSetClassHint(display, window, &class_hints);
95258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
95358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
954f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SetWindowRole(XDisplay* display, XID window, const std::string& role) {
955f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (role.empty()) {
956f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    XDeleteProperty(display, window, GetAtom("WM_WINDOW_ROLE"));
957f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
958f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    char* role_c = const_cast<char*>(role.c_str());
959f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    XChangeProperty(display, window, GetAtom("WM_WINDOW_ROLE"), XA_STRING, 8,
960f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    PropModeReplace,
961f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    reinterpret_cast<unsigned char*>(role_c),
962f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    role.size());
963f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
964f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
965f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetParentWindow(XID window) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root = None;
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID parent = None;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID* children = NULL;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int num_children = 0;
97168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children, &num_children);
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (children)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(children);
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent;
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetHighestAncestorWindow(XID window, XID root) {
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID parent = GetParentWindow(window);
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == None)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return None;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == root)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return window;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window = parent;
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowDesktop(XID window, int* desktop) {
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
99268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string GetX11ErrorString(XDisplay* display, int err) {
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer[256];
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XGetErrorText(display, err, buffer, arraysize(buffer));
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffer;
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |window| is a named window.
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsWindowNamed(XID window) {
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XTextProperty prop;
100168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!XGetWMName(gfx::GetXDisplay(), window, &prop) || !prop.value)
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(prop.value);
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const int max_depth, int depth) {
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (depth > max_depth)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root, parent, *children;
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int num_children;
101568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children,
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &num_children);
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == 0)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID> windows;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows.push_back(children[i]);
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(children);
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // XQueryTree returns the children of |window| in bottom-to-top order, so
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reverse-iterate the list to check the windows from top-to-bottom.
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID>::iterator iter;
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = windows.begin(); iter != windows.end(); iter++) {
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're at this point, we didn't find the window we're looking for at the
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // current level, so we need to recurse to the next level.  We use a second
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loop because the recursion and call to XQueryTree are expensive and is only
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // needed for a small number of cases.
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (++depth <= max_depth) {
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (iter = windows.begin(); iter != windows.end(); iter++) {
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (EnumerateChildren(delegate, *iter, max_depth, depth))
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root = GetX11RootWindow();
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EnumerateChildren(delegate, root, max_depth, 0);
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID> stack;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to old school enumeration of all X windows.  Some WMs parent 'top-level'
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // windows in unnamed actual top-level windows (ion WM), so extend the
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // search depth to all children of top-level windows.
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kMaxSearchDepth = 1;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID>::iterator iter;
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = stack.begin(); iter != stack.end(); iter++) {
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate->ShouldStopIterating(*iter))
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetXWindowStack(Window window, std::vector<XID>* windows) {
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows->clear();
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type;
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format;
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long count;
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *data = NULL;
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProperty(window,
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "_NET_CLIENT_LIST_STACKING",
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ~0L,
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &type,
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &format,
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &count,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &data) != Success) {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == XA_WINDOW && format == 32 && data && count > 0) {
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID* stack = reinterpret_cast<XID*>(data);
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (long i = static_cast<long>(count) - 1; i >= 0; i--)
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows->push_back(stack[i]);
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(data);
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RestackWindow(XID window, XID sibling, bool above) {
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowChanges changes;
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  changes.sibling = sibling;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  changes.stack_mode = above ? Above : Below;
110768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XConfigureWindow(gfx::GetXDisplay(), window, CWSibling | CWStackMode, &changes);
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XSharedMemoryId AttachSharedMemory(XDisplay* display, int shared_memory_key) {
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QuerySharedMemorySupport(display));
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmid = shared_memory_key;
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function is only called if QuerySharedMemorySupport returned true. In
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which case we've already succeeded in having the X server attach to one of
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our shared memory segments.
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmAttach(display, &shminfo)) {
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment "
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << shminfo.shmid;
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "X attached to shared memory segment " << shminfo.shmid;
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shminfo.shmseg;
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
113168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DetachSharedMemory(XDisplay* display, XSharedMemoryId shmseg) {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QuerySharedMemorySupport(display));
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmseg = shmseg;
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmDetach(display, &shminfo))
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool CopyAreaToCanvas(XID drawable,
11433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      gfx::Rect source_bounds,
11443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      gfx::Point dest_offset,
11453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      gfx::Canvas* canvas) {
11463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ui::XScopedImage scoped_image(
114768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      XGetImage(gfx::GetXDisplay(), drawable,
11483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                source_bounds.x(), source_bounds.y(),
11493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                source_bounds.width(), source_bounds.height(),
11503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                AllPlanes, ZPixmap));
11513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  XImage* image = scoped_image.get();
11523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!image) {
11533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "XGetImage failed";
11543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
11553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
11563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (image->bits_per_pixel == 32) {
11583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ((0xff << SK_R32_SHIFT) != image->red_mask ||
11593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (0xff << SK_G32_SHIFT) != image->green_mask ||
11603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (0xff << SK_B32_SHIFT) != image->blue_mask) {
11613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      LOG(WARNING) << "XImage and Skia byte orders differ";
11623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return false;
11633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
11643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Set the alpha channel before copying to the canvas.  Otherwise, areas of
11663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // the framebuffer that were cleared by ply-image rather than being obscured
11673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // by an image during boot may end up transparent.
11683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
11693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // set the framebuffer's alpha channel regardless of whether the device
11703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // claims to support alpha or not.
11713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for (int i = 0; i < image->width * image->height * 4; i += 4)
11723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      image->data[i + 3] = 0xff;
11733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SkBitmap bitmap;
11753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bitmap.setConfig(SkBitmap::kARGB_8888_Config,
11763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     image->width, image->height,
11773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     image->bytes_per_line);
11783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bitmap.setPixels(image->data);
11793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    gfx::ImageSkia image_skia;
118068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
11813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    image_skia.AddRepresentation(image_rep);
11823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    canvas->DrawImageInt(image_skia, dest_offset.x(), dest_offset.y());
11833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
11843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
11853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
11863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
11873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
11893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
11903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
119168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XID CreatePictureFromSkiaPixmap(XDisplay* display, XID pixmap) {
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID picture = XRenderCreatePicture(
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      display, pixmap, GetRenderARGB32Format(display), 0, NULL);
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return picture;
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
119868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void FreePicture(XDisplay* display, XID picture) {
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderFreePicture(display, picture);
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
120268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void FreePixmap(XDisplay* display, XID pixmap) {
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFreePixmap(display, pixmap);
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowManagerName(std::string* wm_name) {
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(wm_name);
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int wm_window = 0;
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetIntProperty(GetX11RootWindow(),
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "_NET_SUPPORTING_WM_CHECK",
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &wm_window)) {
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It's possible that a window manager started earlier in this X session left
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-EWMH window manager, so we trap errors in the following requests to
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avoid crashes (issue 23860).
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // EWMH requires the supporting-WM window to also have a
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // property referencing an ID that's been recycled for another window), so we
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // check that too.
12244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::X11ErrorTracker err_tracker;
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int wm_window_property = 0;
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = GetIntProperty(
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
1228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (err_tracker.FoundNewError() || !result ||
1229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      wm_window_property != wm_window) {
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = GetStringProperty(
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
1235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return !err_tracker.FoundNewError() && result;
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowManagerName GuessWindowManager() {
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name;
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetWindowManagerName(&name)) {
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // These names are taken from the WMs' source code.
12422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Blackbox")
12432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_BLACKBOX;
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "chromeos-wm")
12452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_CHROME_OS;
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Compiz" || name == "compiz")
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_COMPIZ;
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "e16")
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_ENLIGHTENMENT;
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (StartsWithASCII(name, "IceWM", true))
12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_ICE_WM;
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "KWin")
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_KWIN;
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Metacity")
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_METACITY;
12562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Mutter (Muffin)")
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_MUFFIN;
1258a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (name == "GNOME Shell")
1259a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return WM_MUTTER; // GNOME Shell uses Mutter
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Mutter")
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_MUTTER;
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Openbox")
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_OPENBOX;
12642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Xfwm4")
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_XFWM4;
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WM_UNKNOWN;
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ChangeWindowDesktop(XID window, XID destination) {
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int desktop;
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetWindowDesktop(destination, &desktop))
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |window| is sticky, use the current desktop.
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (desktop == kAllDesktops &&
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !GetCurrentDesktop(&desktop))
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XEvent event;
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.type = ClientMessage;
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.window = window;
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.message_type = GetAtom("_NET_WM_DESKTOP");
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.format = 32;
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.data.l[0] = desktop;
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.data.l[1] = 1;  // source indication
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int result = XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), False,
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          SubstructureNotifyMask, &event);
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == Success;
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetDefaultX11ErrorHandlers() {
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetX11ErrorHandlers(NULL, NULL);
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsX11WindowFullScreen(XID window) {
1298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
1299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
1300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // whether we're fullscreen.
1301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<Atom> supported_atoms;
1302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (GetAtomArrayProperty(GetX11RootWindow(),
1303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           "_NET_SUPPORTED",
1304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           &supported_atoms)) {
1305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
1306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (std::find(supported_atoms.begin(), supported_atoms.end(), atom)
1308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        != supported_atoms.end()) {
1309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::vector<Atom> atom_properties;
1310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (GetAtomArrayProperty(window,
1311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               "_NET_WM_STATE",
1312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               &atom_properties)) {
1313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return std::find(atom_properties.begin(), atom_properties.end(), atom)
1314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            != atom_properties.end();
1315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
1316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
1317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Rect window_rect;
1320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!ui::GetWindowRect(window, &window_rect))
1321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As the last resort, check if the window size is as large as the main
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // screen.
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkRectangle monitor_rect;
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect);
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return monitor_rect.x == window_rect.x() &&
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.y == window_rect.y() &&
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.width == window_rect.width() &&
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.height == window_rect.height();
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // We can't use gfx::Screen here because we don't have an aura::Window. So
1335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // instead just look at the size of the default display.
1336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //
1337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(erg): Actually doing this correctly would require pulling out xrandr,
1338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // which we don't even do in the desktop screen yet.
133968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ::XDisplay* display = gfx::GetXDisplay();
1340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ::Screen* screen = DefaultScreenOfDisplay(display);
1341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int width = WidthOfScreen(screen);
1342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int height = HeightOfScreen(screen);
1343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return window_rect.size() == gfx::Size(width, height);
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsXDisplaySizeBlackListed(unsigned long mm_width,
1348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                               unsigned long mm_height) {
1349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Ignore if the reported display is smaller than minimum size.
1350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (mm_width <= kInvalidDisplaySizeList[0][0] ||
1351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      mm_height <= kInvalidDisplaySizeList[0][1]) {
1352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(WARNING) << "Smaller than minimum display size";
1353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
1354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
1356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const unsigned long* size = kInvalidDisplaySizeList[i];
1357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (mm_width == size[0] && mm_height == size[1]) {
1358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      LOG(WARNING) << "Black listed display size detected:"
1359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   << size[0] << "x" << size[1];
1360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
1361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
1364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst unsigned char* XRefcountedMemory::front() const {
1367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return x11_data_;
1368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochsize_t XRefcountedMemory::size() const {
1371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return length_;
1372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochXRefcountedMemory::~XRefcountedMemory() {
1375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  XFree(x11_data_);
1376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedString::~XScopedString() {
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(string_);
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedImage::~XScopedImage() {
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reset(NULL);
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void XScopedImage::reset(XImage* image) {
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_ == image)
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_)
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XDestroyImage(image_);
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_ = image;
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
139468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XScopedCursor::XScopedCursor(::Cursor cursor, XDisplay* display)
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : cursor_(cursor),
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      display_(display) {
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedCursor::~XScopedCursor() {
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reset(0U);
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor XScopedCursor::get() const {
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cursor_;
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void XScopedCursor::reset(::Cursor cursor) {
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cursor_)
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFreeCursor(display_, cursor_);
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cursor_ = cursor;
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions are declared in x11_util_internal.h because they require
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// XLib.h to be included, and it conflicts with many other headers.
141668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static XRenderPictFormat* pictformat = NULL;
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pictformat)
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pictformat;
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First look for a 32-bit format which ignores the alpha value
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat templ;
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.depth = 32;
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.type = PictTypeDirect;
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.red = 16;
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.green = 8;
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.blue = 0;
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.redMask = 0xff;
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.greenMask = 0xff;
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.blueMask = 0xff;
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.alphaMask = 0;
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const unsigned long kMask =
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatType | PictFormatDepth |
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatRed | PictFormatRedMask |
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatGreen | PictFormatGreenMask |
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatBlue | PictFormatBlueMask |
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatAlphaMask;
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pictformat) {
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not all X servers support xRGB32 formats. However, the XRENDER spec says
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that they must support an ARGB32 format, so we can always return that.
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(pictformat) << "XRENDER ARGB32 not supported.";
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pictformat;
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XRenderPictFormat* GetRenderVisualFormat(XDisplay* dpy, Visual* visual) {
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QueryRenderSupport(dpy));
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CachedPictFormats* formats = get_cached_pict_formats();
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CachedPictFormats::const_iterator i = formats->begin();
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != formats->end(); ++i) {
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->equals(dpy, visual))
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i->format;
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not cached, look up the value.
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(pictformat) << "XRENDER does not support default visual";
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And store it in the cache.
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CachedPictFormat cached_value;
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.visual = visual;
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.display = dpy;
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.format = pictformat;
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  formats->push_front(cached_value);
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (formats->size() == kMaxCacheSize) {
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    formats->pop_back();
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should really only have at most 2 display/visual combinations:
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one for normal browser windows, and possibly another for an argb window
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // created to display a menu.
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we get here it's not fatal, we just need to make sure we aren't
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // always blowing away the cache. If we are, then we should figure out why
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and make it bigger.
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pictformat;
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetX11ErrorHandlers(XErrorHandler error_handler,
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         XIOErrorHandler io_error_handler) {
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSetIOErrorHandler(
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
149668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void LogErrorEventDescription(XDisplay* dpy,
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const XErrorEvent& error_event) {
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char error_str[256];
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char request_str[256];
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strncpy(request_str, "Unknown", sizeof(request_str));
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_event.request_code < 128) {
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string num = base::UintToString(error_event.request_code);
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XGetErrorDatabaseText(
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dpy, "XRequest", num.c_str(), "Unknown", request_str,
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sizeof(request_str));
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int num_ext;
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char** ext_list = XListExtensions(dpy, &num_ext);
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < num_ext; i++) {
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int ext_code, first_event, first_error;
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error_event.request_code == ext_code) {
15172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string msg = base::StringPrintf(
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "%s.%d", ext_list[i], error_event.minor_code);
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XGetErrorDatabaseText(
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dpy, "XRequest", msg.c_str(), "Unknown", request_str,
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sizeof(request_str));
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFreeExtensionList(ext_list);
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  LOG(WARNING)
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "X error received: "
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "serial " << error_event.serial << ", "
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "error_code " << static_cast<int>(error_event.error_code)
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << " (" << error_str << "), "
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "request_code " << static_cast<int>(error_event.request_code) << ", "
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "minor_code " << static_cast<int>(error_event.minor_code)
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << " (" << request_str << ")";
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// End of x11_util_internal.h
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ui
1543