x11_util.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/XInput2.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/extensions/Xrandr.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/extensions/randr.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/extensions/shape.h>
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_number_conversions.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stringprintf.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_byteorder.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event_utils.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/keycodes/keyboard_code_conversion_x.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/touch/touch_factory.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/valuators.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util_internal.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point_conversions.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_FREEBSD)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/sysctl.h>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xcursor/Xcursor.h>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h"
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gdk/gdk.h>
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gdk/gdkx.h>
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h>
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gdk_x_compat.h"
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_compat.h"
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(sad): Use the new way of handling X errors when
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://codereview.chromium.org/7889040/ lands.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define gdk_error_trap_push()
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define gdk_error_trap_pop() false
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define gdk_flush()
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to cache the XRenderPictFormat for a visual/display pair.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct CachedPictFormat {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool equals(Display* display, Visual* visual) const {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return display == this->display && visual == this->visual;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Display* display;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Visual* visual;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat* format;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::list<CachedPictFormat> CachedPictFormats;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the cache of pict formats.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CachedPictFormats* get_cached_pict_formats() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static CachedPictFormats* formats = NULL;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!formats)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    formats = new CachedPictFormats();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return formats;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of CachedPictFormats we keep around.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxCacheSize = 5;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (MessageLoop::current()) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MessageLoop::current()->PostTask(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         FROM_HERE,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         base::Bind(&LogErrorEventDescription, d, *e));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "X error received: "
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "serial " << e->serial << ", "
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "error_code " << static_cast<int>(e->error_code) << ", "
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "request_code " << static_cast<int>(e->request_code) << ", "
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "minor_code " << static_cast<int>(e->minor_code);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DefaultX11IOErrorHandler(Display* d) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there's an IO error it likely means the X server has gone away
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "X IO error received (X server probably went away)";
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _exit(1);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: The caller should free the resulting value data.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetProperty(XID window, const std::string& property_name, long max_length,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 Atom* type, int* format, unsigned long* num_items,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 unsigned char** property) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom property_atom = GetAtom(property_name.c_str());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long remaining_bytes = 0;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XGetWindowProperty(GetXDisplay(),
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            window,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            property_atom,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0,          // offset into property data to read
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            max_length, // max length to get
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            False,      // deleted
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            AnyPropertyType,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            type,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            format,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            num_items,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &remaining_bytes,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            property);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts ui::EventType to XKeyEvent state.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned int XKeyEventState(int flags) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((flags & ui::EF_SHIFT_DOWN) ? ShiftMask : 0) |
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((flags & ui::EF_CONTROL_DOWN) ? ControlMask : 0) |
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((flags & ui::EF_ALT_DOWN) ? Mod1Mask : 0) |
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((flags & ui::EF_CAPS_LOCK_DOWN) ? LockMask : 0);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts EventType to XKeyEvent type.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int XKeyEventType(ui::EventType type) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_KEY_PRESSED:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return KeyPress;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_KEY_RELEASED:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return KeyRelease;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts KeyboardCode to XKeyEvent keycode.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned int XKeyEventKeyCode(ui::KeyboardCode key_code,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              int flags,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              Display* display) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int keysym = XKeysymForWindowsKeyCode(key_code,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              flags & ui::EF_SHIFT_DOWN);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tests assume the keycode for XK_less is equal to the one of XK_comma,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but XKeysymToKeycode returns 94 for XK_less while it returns 59 for
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // XK_comma. Here we convert the value for XK_less to the value for XK_comma.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (keysym == XK_less) ? 59 : XKeysymToKeycode(display, keysym);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A process wide singleton that manages the usage of X cursors.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XCursorCache {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCursorCache() {}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XCursorCache() {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Clear();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor GetCursor(int cursor_shape) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Lookup cursor by attempting to insert a null value, which avoids
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a second pass through the map after a cache miss.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::pair<std::map<int, ::Cursor>::iterator, bool> it = cache_.insert(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::make_pair(cursor_shape, 0));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it.second) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it.first->second = XCreateFontCursor(display, cursor_shape);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it.first->second;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Clear() {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::map<int, ::Cursor>::iterator it =
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cache_.begin(); it != cache_.end(); ++it) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XFreeCursor(display, it->second);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_.clear();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Maps X11 font cursor shapes to Cursor IDs.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<int, ::Cursor> cache_;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XCursorCache);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)XCursorCache* cursor_cache = NULL;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A process wide singleton cache for custom X cursors.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XCustomCursorCache {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static XCustomCursorCache* GetInstance() {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<XCustomCursorCache>::get();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor InstallCustomCursor(XcursorImage* image) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XCustomCursor* custom_cursor = new XCustomCursor(image);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor xcursor = custom_cursor->cursor();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_[xcursor] = custom_cursor;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return xcursor;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Ref(::Cursor cursor) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_[cursor]->Ref();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Unref(::Cursor cursor) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cache_[cursor]->Unref())
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_.erase(cursor);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Clear() {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_.clear();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<XCustomCursorCache>;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class XCustomCursor {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This takes ownership of the image.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XCustomCursor(XcursorImage* image)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : image_(image),
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ref_(1) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cursor_ = XcursorImageLoadCursor(GetXDisplay(), image);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~XCustomCursor() {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XcursorImageDestroy(image_);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XFreeCursor(GetXDisplay(), cursor_);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor cursor() const { return cursor_; }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void Ref() {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++ref_;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Returns true if the cursor was destroyed because of the unref.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool Unref() {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (--ref_ == 0) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delete this;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XcursorImage* image_;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ref_;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Cursor cursor_;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(XCustomCursor);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache() {}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XCustomCursorCache() {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Clear();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map< ::Cursor, XCustomCursor*> cache_;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XCustomCursorCache);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_AURA)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A singleton object that remembers remappings of mouse buttons.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class XButtonMap {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static XButtonMap* GetInstance() {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<XButtonMap>::get();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateMapping() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count_ = XGetPointerMapping(ui::GetXDisplay(), map_, arraysize(map_));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetMappedButton(int button) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return button > 0 && button <= count_ ? map_[button - 1] : button;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<XButtonMap>;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XButtonMap() {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateMapping();
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~XButtonMap() {}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char map_[256];
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count_;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XButtonMap);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsRandRAvailable() {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int randr_version_major = 0;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int randr_version_minor = 0;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool is_randr_available = XRRQueryVersion(
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetXDisplay(), &randr_version_major, &randr_version_minor);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_randr_available;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsShapeAvailable() {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool is_shape_available =
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XShapeQueryExtension(ui::GetXDisplay(), &dummy, &dummy);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_shape_available;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Get the EDID data from the |output| and stores to |prop|. |nitem| will store
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the number of characters |prop| will have. It doesn't take the ownership of
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |prop|, so caller must release it by XFree().
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if EDID property is successfully obtained. Otherwise returns
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// false and does not touch |prop| and |nitems|.
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetEDIDProperty(XID output, unsigned long* nitems, unsigned char** prop) {
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsRandRAvailable())
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static Atom edid_property = GetAtom(RR_PROPERTY_RANDR_EDID);
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Display* display = GetXDisplay();
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_edid_property = false;
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int num_properties = 0;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Atom* properties = XRRListOutputProperties(display, output, &num_properties);
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < num_properties; ++i) {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (properties[i] == edid_property) {
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      has_edid_property = true;
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFree(properties);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!has_edid_property)
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Atom actual_type;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int actual_format;
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned long bytes_after;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XRRGetOutputProperty(display,
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       output,
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       edid_property,
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       0,                // offset
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       128,              // length
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       false,            // _delete
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       false,            // pending
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       AnyPropertyType,  // req_type
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &actual_type,
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &actual_format,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       nitems,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &bytes_after,
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       prop);
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(XA_INTEGER, actual_type);
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(8, actual_format);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XDisplayExists() {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (GetXDisplay() != NULL);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Display* GetXDisplay() {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::MessagePumpForUI::GetDefaultXDisplay();
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SharedMemorySupport DoQuerySharedMemorySupport(Display* dpy) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bool pixmaps_supported;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Query the server's support for XSHM.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_FREEBSD)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On FreeBSD we can't access the shared memory after it was marked for
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deletion, unless this behaviour is explicitly enabled by the user.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In case it's not enabled disable shared memory support.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int allow_removed;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t length = sizeof(allow_removed);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((sysctlbyname("kern.ipc.shm_allow_removed", &allow_removed, &length,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, 0) < 0) || allow_removed < 1) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next we probe to see if shared memory will really work
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shmkey = shmget(IPC_PRIVATE, 1, 0600);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shmkey == -1) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Failed to get shared memory segment.";
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Got shared memory segment " << shmkey;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* address = shmat(shmkey, NULL, 0);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the shared memory region for deletion
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shmctl(shmkey, IPC_RMID, NULL);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmid = shmkey;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_error_trap_push();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = XShmAttach(dpy, &shminfo);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "X got shared memory segment " << shmkey;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSync(dpy, False);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gdk_error_trap_pop())
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = false;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shmdt(address);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment " << shmkey;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SHARED_MEMORY_NONE;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "X attached to shared memory segment " << shmkey;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmDetach(dpy, &shminfo);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pixmaps_supported ? SHARED_MEMORY_PIXMAP : SHARED_MEMORY_PUTIMAGE;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SharedMemorySupport QuerySharedMemorySupport(Display* dpy) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SharedMemorySupport shared_memory_support = SHARED_MEMORY_NONE;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool shared_memory_support_cached = false;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shared_memory_support_cached)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return shared_memory_support;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shared_memory_support = DoQuerySharedMemorySupport(dpy);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shared_memory_support_cached = true;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shared_memory_support;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool QueryRenderSupport(Display* dpy) {
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool render_supported = false;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool render_supported_cached = false;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (render_supported_cached)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return render_supported;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't care about the version of Xrender since all the features which
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we use are included in every version.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_supported_cached = true;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return render_supported;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetDefaultScreen(Display* display) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XDefaultScreen(display);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor GetXCursor(int cursor_shape) {
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!cursor_cache)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cursor_cache = new XCursorCache;
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return cursor_cache->GetCursor(cursor_shape);
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResetXCursorCache() {
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete cursor_cache;
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cursor_cache = NULL;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor CreateReffedCustomXCursor(XcursorImage* image) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XCustomCursorCache::GetInstance()->InstallCustomCursor(image);
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RefCustomXCursor(::Cursor cursor) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache::GetInstance()->Ref(cursor);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnrefCustomXCursor(::Cursor cursor) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCustomCursorCache::GetInstance()->Unref(cursor);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XcursorImage* SkBitmapToXcursorImage(const SkBitmap* cursor_image,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const gfx::Point& hotspot) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cursor_image->config() == SkBitmap::kARGB_8888_Config);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point hotspot_point = hotspot;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap scaled;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // X11 seems to have issues with cursors when images get larger than 64
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pixels. So rescale the image if necessary.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const float kMaxPixel = 64.f;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool needs_scale = false;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cursor_image->width() > kMaxPixel || cursor_image->height() > kMaxPixel) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float scale = 1.f;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cursor_image->width() > cursor_image->height())
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scale = kMaxPixel / cursor_image->width();
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scale = kMaxPixel / cursor_image->height();
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scaled = skia::ImageOperations::Resize(*cursor_image,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        skia::ImageOperations::RESIZE_BETTER,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<int>(cursor_image->width() * scale),
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<int>(cursor_image->height() * scale));
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hotspot_point = gfx::ToFlooredPoint(gfx::ScalePoint(hotspot, scale));
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needs_scale = true;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SkBitmap* bitmap = needs_scale ? &scaled : cursor_image;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XcursorImage* image = XcursorImageCreate(bitmap->width(), bitmap->height());
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image->xhot = hotspot_point.x();
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image->yhot = hotspot_point.y();
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bitmap->width() && bitmap->height()) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap->lockPixels();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The |bitmap| contains ARGB image, so just copy it.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(image->pixels,
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           bitmap->getPixels(),
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           bitmap->width() * bitmap->height() * 4);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap->unlockPixels();
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return image;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CoalescePendingMotionEvents(const XEvent* xev,
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                XEvent* last_event) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_coalesed = 0;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Display* display = xev->xany.display;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int event_type = xev->xgeneric.evtype;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_XI2_MT)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float tracking_id = -1;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event_type == XI_TouchUpdate) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ui::ValuatorTracker::GetInstance()->ExtractValuator(*xev,
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ui::ValuatorTracker::VAL_TRACKING_ID, &tracking_id))
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tracking_id = -1;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (XPending(display)) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XEvent next_event;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XPeekEvent(display, &next_event);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we can't get the cookie, abort the check.
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!XGetEventData(next_event.xgeneric.display, &next_event.xcookie))
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return num_coalesed;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this isn't from a valid device, throw the event away, as
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that's what the message pump would do. Device events come in pairs
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with one from the master and one from the slave so there will
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // always be at least one pending.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(&next_event)) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XFreeEventData(display, &next_event.xcookie);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XNextEvent(display, &next_event);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (next_event.type == GenericEvent &&
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_event.xgeneric.evtype == event_type &&
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        !ui::GetScrollOffsets(&next_event, NULL, NULL, NULL, NULL, NULL) &&
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        !ui::GetFlingData(&next_event, NULL, NULL, NULL, NULL, NULL)) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XIDeviceEvent* next_xievent =
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<XIDeviceEvent*>(next_event.xcookie.data);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_XI2_MT)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      float next_tracking_id = -1;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (event_type == XI_TouchUpdate) {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If this is a touch motion event (as opposed to mouse motion event),
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // then make sure the events are from the same touch-point.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!ui::ValuatorTracker::GetInstance()->ExtractValuator(next_event,
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              ui::ValuatorTracker::VAL_TRACKING_ID, &next_tracking_id))
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          next_tracking_id = -1;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Confirm that the motion event is targeted at the same window
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and that no buttons or modifiers have changed.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (xievent->event == next_xievent->event &&
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->child == next_xievent->child &&
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_XI2_MT)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (event_type == XI_Motion || tracking_id == next_tracking_id) &&
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->buttons.mask_len == next_xievent->buttons.mask_len &&
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (memcmp(xievent->buttons.mask,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  next_xievent->buttons.mask,
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  xievent->buttons.mask_len) == 0) &&
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.base == next_xievent->mods.base &&
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.latched == next_xievent->mods.latched &&
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.locked == next_xievent->mods.locked &&
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          xievent->mods.effective == next_xievent->mods.effective) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XFreeEventData(display, &next_event.xcookie);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Free the previous cookie.
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (num_coalesed > 0)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          XFreeEventData(display, &last_event->xcookie);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Get the event and its cookie data.
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XNextEvent(display, last_event);
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XGetEventData(display, &last_event->xcookie);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++num_coalesed;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This isn't an event we want so free its cookie data.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XFreeEventData(display, &next_event.xcookie);
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    break;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return num_coalesed;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HideHostCursor() {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         (CreateInvisibleCursor(), ui::GetXDisplay()));
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XDefineCursor(ui::GetXDisplay(), DefaultRootWindow(ui::GetXDisplay()),
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                invisible_cursor.get());
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor CreateInvisibleCursor() {
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Display* xdisplay = ui::GetXDisplay();
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::Cursor invisible_cursor;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XColor black;
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  black.red = black.green = black.blue = 0;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Pixmap blank = XCreateBitmapFromData(xdisplay,
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       DefaultRootWindow(xdisplay),
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       nodata, 8, 8);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invisible_cursor = XCreatePixmapCursor(xdisplay, blank, blank,
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &black, &black, 0, 0);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFreePixmap(xdisplay, blank);
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return invisible_cursor;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11RootWindow() {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DefaultRootWindow(GetXDisplay());
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetCurrentDesktop(int* desktop) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_WINDOW_XID(gtk_widget_get_window(widget));
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetX11WindowFromGdkWindow(GdkWindow* window) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_WINDOW_XID(window);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWindow* GetGtkWindowFromX11Window(XID xid) {
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkWindow* gdk_window =
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gdk_window)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWindow* gtk_window = NULL;
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_window_get_user_data(gdk_window,
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           reinterpret_cast<gpointer*>(&gtk_window));
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gtk_window)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gtk_window;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GetVisualFromGtkWidget(GtkWidget* widget) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(TOOLKIT_GTK)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetHideTitlebarWhenMaximizedProperty(XID window,
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          HideTitlebarWhenMaximized property) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 hide = property;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XChangeProperty(GetXDisplay(),
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window,
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XA_CARDINAL,
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      32,  // size in bits
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PropModeReplace,
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<unsigned char*>(&hide),
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1);
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ClearX11DefaultRootWindow() {
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Display* display = GetXDisplay();
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XID root_window = GetX11RootWindow();
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect root_bounds;
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetWindowRect(root_window, &root_bounds)) {
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to get the bounds of the X11 root window";
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XGCValues gc_values = {0};
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gc_values.foreground = BlackPixel(display, DefaultScreen(display));
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GC gc = XCreateGC(display, root_window, GCForeground, &gc_values);
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFillRectangle(display, root_window, gc,
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.x(),
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.y(),
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.width(),
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 root_bounds.height());
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFreeGC(display, gc);
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BitsPerPixelForPixmapDepth(Display* dpy, int depth) {
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!formats)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bits_per_pixel = -1;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < count; ++i) {
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (formats[i].depth == depth) {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bits_per_pixel = formats[i].bits_per_pixel;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(formats);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bits_per_pixel;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsWindowVisible(XID window) {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowAttributes win_attributes;
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XGetWindowAttributes(GetXDisplay(), window, &win_attributes))
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (win_attributes.map_state != IsViewable)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some compositing window managers (notably kwin) do not actually unmap
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // windows on desktop switch, so we also must check the current desktop.
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int window_desktop, current_desktop;
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (!GetWindowDesktop(window, &window_desktop) ||
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          !GetCurrentDesktop(&current_desktop) ||
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window_desktop == kAllDesktops ||
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window_desktop == current_desktop);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowRect(XID window, gfx::Rect* rect) {
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window root, child;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x, y;
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int width, height;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int border_width, depth;
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XGetGeometry(GetXDisplay(), window, &root, &x, &y,
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    &width, &height, &border_width, &depth))
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XTranslateCoordinates(GetXDisplay(), window, root,
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             0, 0, &x, &y, &child))
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *rect = gfx::Rect(x, y, width, height);
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_rect;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetWindowRect(window, &window_rect))
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window_rect.Contains(screen_loc))
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsShapeAvailable())
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // According to http://www.x.org/releases/X11R7.6/doc/libXext/shapelib.html,
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if an X display supports the shape extension the bounds of a window are
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // defined as the intersection of the window bounds and the interior
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // rectangles. This means to determine if a point is inside a window for the
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // purpose of input handling we have to check the rectangles in the ShapeInput
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // list.
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dummy;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_rects_size = 0;
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRectangle* input_rects = XShapeGetRectangles(
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::GetXDisplay(), window, ShapeInput, &input_rects_size, &dummy);
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!input_rects)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_in_input_rects = false;
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < input_rects_size; ++i) {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ShapeInput rects appear to be in window space, so we have to
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // translate by the window_rect's offset to map to screen space.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect input_rect =
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gfx::Rect(input_rects[i].x + window_rect.x(),
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  input_rects[i].y + window_rect.y(),
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  input_rects[i].width, input_rects[i].height);
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (input_rect.Contains(screen_loc)) {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_in_input_rects = true;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(input_rects);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_in_input_rects;
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PropertyExists(XID window, const std::string& property_name) {
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1,
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return num_items > 0;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetIntProperty(XID window, const std::string& property_name, int* value) {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1,
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 32 || num_items != 1) {
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(property);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *value = static_cast<int>(*(reinterpret_cast<long*>(property)));
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetIntArrayProperty(XID window,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& property_name,
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         std::vector<int>* value) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* properties = NULL;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name,
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           (~0L), // (all of them)
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &properties);
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 32) {
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(properties);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  long* int_properties = reinterpret_cast<long*>(properties);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->clear();
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned long i = 0; i < num_items; ++i) {
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->push_back(static_cast<int>(int_properties[i]));
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(properties);
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetAtomArrayProperty(XID window,
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const std::string& property_name,
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          std::vector<Atom>* value) {
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* properties = NULL;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name,
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           (~0L), // (all of them)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &properties);
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type != XA_ATOM) {
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(properties);
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom* atom_properties = reinterpret_cast<Atom*>(properties);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->clear();
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->insert(value->begin(), atom_properties, atom_properties + num_items);
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(properties);
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetStringProperty(
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID window, const std::string& property_name, std::string* value) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type = None;
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format = 0;  // size in bits of each item in 'property'
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long num_items = 0;
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* property = NULL;
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = GetProperty(window, property_name, 1024,
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &type, &format, &num_items, &property);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != Success)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format != 8) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(property);
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->assign(reinterpret_cast<char*>(property), num_items);
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(property);
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetIntProperty(XID window,
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& name,
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& type,
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int value) {
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> values(1, value);
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SetIntArrayProperty(window, name, type, values);
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetIntArrayProperty(XID window,
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& name,
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& type,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::vector<int>& value) {
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!value.empty());
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom name_atom = GetAtom(name.c_str());
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type_atom = GetAtom(type.c_str());
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // XChangeProperty() expects values of type 32 to be longs.
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<long[]> data(new long[value.size()]);
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < value.size(); ++i)
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data[i] = value[i];
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_error_trap_push();
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XChangeProperty(ui::GetXDisplay(),
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  window,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  name_atom,
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  type_atom,
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  32,  // size in bits of items in 'value'
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  PropModeReplace,
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  reinterpret_cast<const unsigned char*>(data.get()),
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  value.size());  // num items
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSync(ui::GetXDisplay(), False);
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gdk_error_trap_pop() == 0;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Atom GetAtom(const char* name) {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gdk_x11_get_xatom_by_name_for_display(
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_display_get_default(), name);
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(derat): Cache atoms to avoid round-trips to the server.
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XInternAtom(GetXDisplay(), name, false);
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetParentWindow(XID window) {
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root = None;
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID parent = None;
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID* children = NULL;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int num_children = 0;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XQueryTree(GetXDisplay(), window, &root, &parent, &children, &num_children);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (children)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(children);
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID GetHighestAncestorWindow(XID window, XID root) {
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID parent = GetParentWindow(window);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == None)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return None;
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == root)
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return window;
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window = parent;
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowDesktop(XID window, int* desktop) {
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetX11ErrorString(Display* display, int err) {
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer[256];
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XGetErrorText(display, err, buffer, arraysize(buffer));
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffer;
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |window| is a named window.
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsWindowNamed(XID window) {
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XTextProperty prop;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XGetWMName(GetXDisplay(), window, &prop) || !prop.value)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(prop.value);
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const int max_depth, int depth) {
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (depth > max_depth)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root, parent, *children;
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int num_children;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int status = XQueryTree(GetXDisplay(), window, &root, &parent, &children,
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &num_children);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == 0)
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID> windows;
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows.push_back(children[i]);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(children);
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // XQueryTree returns the children of |window| in bottom-to-top order, so
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reverse-iterate the list to check the windows from top-to-bottom.
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID>::iterator iter;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = windows.begin(); iter != windows.end(); iter++) {
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're at this point, we didn't find the window we're looking for at the
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // current level, so we need to recurse to the next level.  We use a second
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loop because the recursion and call to XQueryTree are expensive and is only
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // needed for a small number of cases.
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (++depth <= max_depth) {
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (iter = windows.begin(); iter != windows.end(); iter++) {
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (EnumerateChildren(delegate, *iter, max_depth, depth))
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID root = GetX11RootWindow();
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EnumerateChildren(delegate, root, max_depth, 0);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID> stack;
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to old school enumeration of all X windows.  Some WMs parent 'top-level'
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // windows in unnamed actual top-level windows (ion WM), so extend the
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // search depth to all children of top-level windows.
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kMaxSearchDepth = 1;
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<XID>::iterator iter;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = stack.begin(); iter != stack.end(); iter++) {
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate->ShouldStopIterating(*iter))
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetXWindowStack(Window window, std::vector<XID>* windows) {
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows->clear();
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atom type;
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int format;
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long count;
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *data = NULL;
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProperty(window,
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "_NET_CLIENT_LIST_STACKING",
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ~0L,
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &type,
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &format,
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &count,
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  &data) != Success) {
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == XA_WINDOW && format == 32 && data && count > 0) {
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XID* stack = reinterpret_cast<XID*>(data);
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (long i = static_cast<long>(count) - 1; i >= 0; i--)
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows->push_back(stack[i]);
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFree(data);
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RestackWindow(XID window, XID sibling, bool above) {
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowChanges changes;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  changes.sibling = sibling;
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  changes.stack_mode = above ? Above : Below;
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XConfigureWindow(GetXDisplay(), window, CWSibling | CWStackMode, &changes);
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XSharedMemoryId AttachSharedMemory(Display* display, int shared_memory_key) {
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QuerySharedMemorySupport(display));
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmid = shared_memory_key;
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function is only called if QuerySharedMemorySupport returned true. In
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which case we've already succeeded in having the X server attach to one of
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our shared memory segments.
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmAttach(display, &shminfo)) {
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "X failed to attach to shared memory segment "
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << shminfo.shmid;
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "X attached to shared memory segment " << shminfo.shmid;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shminfo.shmseg;
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DetachSharedMemory(Display* display, XSharedMemoryId shmseg) {
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QuerySharedMemorySupport(display));
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XShmSegmentInfo shminfo;
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&shminfo, 0, sizeof(shminfo));
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shminfo.shmseg = shmseg;
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XShmDetach(display, &shminfo))
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap) {
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID picture = XRenderCreatePicture(
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      display, pixmap, GetRenderARGB32Format(display), 0, NULL);
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return picture;
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PutARGBImage(Display* display,
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  void* visual, int depth,
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  XID pixmap, void* pixmap_gc,
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const uint8* data,
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  int width, int height) {
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PutARGBImage(display,
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               visual, depth,
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               pixmap, pixmap_gc,
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               data, width, height,
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               0, 0, // src_x, src_y
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               0, 0, // dst_x, dst_y
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               width, height);
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PutARGBImage(Display* display,
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  void* visual, int depth,
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  XID pixmap, void* pixmap_gc,
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const uint8* data,
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  int data_width, int data_height,
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  int src_x, int src_y,
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  int dst_x, int dst_y,
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  int copy_width, int copy_height) {
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(scherkus): potential performance impact... consider passing in as a
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // parameter.
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth);
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XImage image;
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&image, 0, sizeof(image));
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.width = data_width;
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.height = data_height;
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.format = ZPixmap;
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.byte_order = LSBFirst;
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.bitmap_unit = 8;
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.bitmap_bit_order = LSBFirst;
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.depth = depth;
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.bits_per_pixel = pixmap_bpp;
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image.bytes_per_line = data_width * pixmap_bpp / 8;
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pixmap_bpp == 32) {
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.red_mask = 0xff0000;
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.green_mask = 0xff00;
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.blue_mask = 0xff;
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the X server depth is already 32-bits and the color masks match,
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // then our job is easy.
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Visual* vis = static_cast<Visual*>(visual);
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (image.red_mask == vis->red_mask &&
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        image.green_mask == vis->green_mask &&
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        image.blue_mask == vis->blue_mask) {
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image.data = const_cast<char*>(reinterpret_cast<const char*>(data));
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                src_x, src_y, dst_x, dst_y,
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                copy_width, copy_height);
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Otherwise, we need to shuffle the colors around. Assume red and blue
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // need to be swapped.
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // It's possible to use some fancy SSE tricks here, but since this is the
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // slow path anyway, we do it slowly.
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint8_t* bitmap32 =
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<uint8_t*>(malloc(4 * data_width * data_height));
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!bitmap32)
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint8_t* const orig_bitmap32 = bitmap32;
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int y = 0; y < data_height; ++y) {
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int x = 0; x < data_width; ++x) {
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          const uint32_t pixel = *(bitmap_in++);
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bitmap32[0] = (pixel >> 16) & 0xff;  // Red
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bitmap32[1] = (pixel >> 8) & 0xff;   // Green
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bitmap32[2] = pixel & 0xff;          // Blue
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bitmap32[3] = (pixel >> 24) & 0xff;  // Alpha
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bitmap32 += 4;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image.data = reinterpret_cast<char*>(orig_bitmap32);
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                src_x, src_y, dst_x, dst_y,
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                copy_width, copy_height);
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      free(orig_bitmap32);
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (pixmap_bpp == 16) {
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some folks have VNC setups which still use 16-bit visuals and VNC
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // doesn't include Xrender.
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint16_t* bitmap16 =
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<uint16_t*>(malloc(2 * data_width * data_height));
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!bitmap16)
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint16_t* const orig_bitmap16 = bitmap16;
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < data_height; ++y) {
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int x = 0; x < data_width; ++x) {
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const uint32_t pixel = *(bitmap_in++);
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             ((pixel >> 5) & 0x07e0) |
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             ((pixel >> 3) & 0x001f);
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *(bitmap16++) = out_pixel;
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.data = reinterpret_cast<char*>(orig_bitmap16);
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.red_mask = 0xf800;
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.green_mask = 0x07e0;
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image.blue_mask = 0x001f;
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              src_x, src_y, dst_x, dst_y,
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              copy_width, copy_height);
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(orig_bitmap16);
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "Sorry, we don't support your visual depth without "
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "Xrender support (depth:" << depth
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " bpp:" << pixmap_bpp << ")";
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FreePicture(Display* display, XID picture) {
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderFreePicture(display, picture);
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FreePixmap(Display* display, XID pixmap) {
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFreePixmap(display, pixmap);
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetOutputDeviceData(XID output,
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         uint16* manufacturer_id,
12872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         uint16* product_code,
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         std::string* human_readable_name) {
12892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned long nitems = 0;
12902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned char *prop = NULL;
12912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetEDIDProperty(output, &nitems, &prop))
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool result = ParseOutputDeviceData(
12952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prop, nitems, manufacturer_id, product_code, human_readable_name);
12962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFree(prop);
12972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
12982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ParseOutputDeviceData(const unsigned char* prop,
13012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           unsigned long nitems,
13022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           uint16* manufacturer_id,
13032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           uint16* product_code,
13042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           std::string* human_readable_name) {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See http://en.wikipedia.org/wiki/Extended_display_identification_data
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the details of EDID data format.  We use the following data:
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   bytes 8-9: manufacturer EISA ID, in big-endian
13082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   bytes 10-11: represents product code, in little-endian
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   bytes 54-125: four descriptors (18-bytes each) which may contain
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     the display name.
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kManufacturerOffset = 8;
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kManufacturerLength = 2;
13132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kProductCodeOffset = 10;
13142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kProductCodeLength = 2;
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kDescriptorOffset = 54;
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kNumDescriptors = 4;
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kDescriptorLength = 18;
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The specifier types.
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char kMonitorNameDescriptor = 0xfc;
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (manufacturer_id) {
13222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (nitems < kManufacturerOffset + kManufacturerLength)
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
13242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *manufacturer_id =
13262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *reinterpret_cast<const uint16*>(prop + kManufacturerOffset);
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(ARCH_CPU_LITTLE_ENDIAN)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *manufacturer_id = base::ByteSwap(*manufacturer_id);
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (product_code) {
13332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (nitems < kProductCodeOffset + kProductCodeLength)
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
13352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *product_code = base::ByteSwapToLE16(
13372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *reinterpret_cast<const uint16*>(prop + kProductCodeOffset));
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!human_readable_name)
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  human_readable_name->clear();
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < kNumDescriptors; ++i) {
13452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength)
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const unsigned char* desc_buf =
13492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        prop + kDescriptorOffset + i * kDescriptorLength;
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the descriptor contains the display name, it has the following
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // structure:
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   bytes 0-2, 4: \0
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   byte 3: descriptor type, defined above.
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   bytes 5-17: text data, ending with \r, padding with spaces
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we should check bytes 0-2 and 4, since it may have other values in
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // case that the descriptor contains other type of data.
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (desc_buf[0] == 0 && desc_buf[1] == 0 && desc_buf[2] == 0 &&
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        desc_buf[4] == 0) {
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (desc_buf[3] == kMonitorNameDescriptor) {
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string found_name(
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            reinterpret_cast<const char*>(desc_buf + 5), kDescriptorLength - 5);
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TrimWhitespaceASCII(found_name, TRIM_TRAILING, human_readable_name);
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (human_readable_name->empty())
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify if the |human_readable_name| consists of printable characters only.
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < human_readable_name->size(); ++i) {
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char c = (*human_readable_name)[i];
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!isascii(c) || !isprint(c)) {
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      human_readable_name->clear();
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetOutputOverscanFlag(XID output, bool* flag) {
13842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned long nitems = 0;
13852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned char *prop = NULL;
13862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetEDIDProperty(output, &nitems, &prop))
13872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
13882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool found = ParseOutputOverscanFlag(prop, nitems, flag);
13902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  XFree(prop);
13912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return found;
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ParseOutputOverscanFlag(const unsigned char* prop,
13952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             unsigned long nitems,
13962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             bool *flag) {
13972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See http://en.wikipedia.org/wiki/Extended_display_identification_data
13982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for the extension format of EDID.  Also see EIA/CEA-861 spec for
13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the format of the extensions and how video capability is encoded.
14002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //  - byte 0: tag.  should be 02h.
14012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //  - byte 1: revision.  only cares revision 3 (03h).
14022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //  - byte 4-: data block.
14032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kExtensionBase = 128;
14042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kExtensionSize = 128;
14052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kNumExtensionsOffset = 126;
14062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kDataBlockOffset = 4;
14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned char kCEAExtensionTag = '\x02';
14082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned char kExpectedExtensionRevision = '\x03';
14092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned char kExtendedTag = 7;
14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned char kExtendedVideoCapabilityTag = 0;
14112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kPTOverscan = 4;
14122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kITOverscan = 2;
14132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const unsigned int kCEOverscan = 0;
14142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nitems <= kNumExtensionsOffset)
14162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
14172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned char num_extensions = prop[kNumExtensionsOffset];
14192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < num_extensions; ++i) {
14212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Skip parsing the whole extension if size is not enough.
14222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (nitems < kExtensionBase + (i + 1) * kExtensionSize)
14232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
14242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const unsigned char* extension = prop + kExtensionBase + i * kExtensionSize;
14262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unsigned char tag = extension[0];
14272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unsigned char revision = extension[1];
14282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision)
14292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
14302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unsigned char timing_descriptors_start =
14322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::min(extension[2], static_cast<unsigned char>(kExtensionSize));
14332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const unsigned char* data_block = extension + kDataBlockOffset;
14342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (data_block < extension + timing_descriptors_start) {
14352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // A data block is encoded as:
14362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // - byte 1 high 3 bits: tag. '07' for extended tags.
14372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // - byte 1 remaining bits: the length of data block.
14382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // - byte 2: the extended tag.  '0' for video capability.
14392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // - byte 3: the capability.
14402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unsigned char tag = data_block[0] >> 5;
14412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unsigned char payload_length = data_block[0] & 0x1f;
14422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (static_cast<unsigned long>(data_block + payload_length - prop) >
14432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          nitems)
14442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
14452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (tag != kExtendedTag && payload_length < 2) {
14472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        data_block += payload_length + 1;
14482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
14492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
14502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unsigned char extended_tag_code = data_block[1];
14522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extended_tag_code != kExtendedVideoCapabilityTag) {
14532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        data_block += payload_length;
14542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
14552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
14562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The difference between preferred, IT, and CE video formats
14582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't matter. Sets |flag| to true if any of these flags are true.
14592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if ((data_block[2] & (1 << kPTOverscan)) ||
14602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (data_block[2] & (1 << kITOverscan)) ||
14612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (data_block[2] & (1 << kCEOverscan))) {
14622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *flag = true;
14632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
14642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *flag = false;
14652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
14672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetWindowManagerName(std::string* wm_name) {
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(wm_name);
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int wm_window = 0;
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetIntProperty(GetX11RootWindow(),
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "_NET_SUPPORTING_WM_CHECK",
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &wm_window)) {
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It's possible that a window manager started earlier in this X session left
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-EWMH window manager, so we trap errors in the following requests to
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avoid crashes (issue 23860).
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // EWMH requires the supporting-WM window to also have a
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // property referencing an ID that's been recycled for another window), so we
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // check that too.
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_error_trap_push();
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int wm_window_property = 0;
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = GetIntProperty(
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_flush();
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool got_error = gdk_error_trap_pop();
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (got_error || !result || wm_window_property != wm_window)
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_error_trap_push();
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = GetStringProperty(
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_flush();
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  got_error = gdk_error_trap_pop();
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !got_error && result;
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowManagerName GuessWindowManager() {
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name;
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetWindowManagerName(&name)) {
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // These names are taken from the WMs' source code.
15122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Blackbox")
15132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_BLACKBOX;
15142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "chromeos-wm")
15152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_CHROME_OS;
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Compiz" || name == "compiz")
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_COMPIZ;
15182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "e16")
15192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_ENLIGHTENMENT;
15202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (StartsWithASCII(name, "IceWM", true))
15212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_ICE_WM;
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "KWin")
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_KWIN;
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Metacity")
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_METACITY;
15262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Mutter (Muffin)")
15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_MUFFIN;
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Mutter")
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_MUTTER;
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name == "Openbox")
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return WM_OPENBOX;
15322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == "Xfwm4")
15332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return WM_XFWM4;
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WM_UNKNOWN;
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ChangeWindowDesktop(XID window, XID destination) {
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int desktop;
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetWindowDesktop(destination, &desktop))
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |window| is sticky, use the current desktop.
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (desktop == kAllDesktops &&
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !GetCurrentDesktop(&desktop))
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XEvent event;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.type = ClientMessage;
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.window = window;
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.message_type = GetAtom("_NET_WM_DESKTOP");
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.format = 32;
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.data.l[0] = desktop;
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.xclient.data.l[1] = 1;  // source indication
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False,
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          SubstructureNotifyMask, &event);
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == Success;
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetDefaultX11ErrorHandlers() {
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetX11ErrorHandlers(NULL, NULL);
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsX11WindowFullScreen(XID window) {
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check if _NET_WM_STATE property contains _NET_WM_STATE_FULLSCREEN.
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<Atom> atom_properties;
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetAtomArrayProperty(window,
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "_NET_WM_STATE",
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &atom_properties) &&
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(atom_properties.begin(), atom_properties.end(), atom)
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          != atom_properties.end())
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As the last resort, check if the window size is as large as the main
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // screen.
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkRectangle monitor_rect;
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect);
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect window_rect;
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ui::GetWindowRect(window, &window_rect))
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return monitor_rect.x == window_rect.x() &&
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.y == window_rect.y() &&
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.width == window_rect.width() &&
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         monitor_rect.height == window_rect.height();
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsMotionEvent(XEvent* event) {
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int type = event->type;
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == GenericEvent)
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type = event->xgeneric.evtype;
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return type == MotionNotify;
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetMappedButton(int button) {
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return XButtonMap::GetInstance()->GetMappedButton(button);
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateButtonMap() {
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XButtonMap::GetInstance()->UpdateMapping();
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitXKeyEventForTesting(EventType type,
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             KeyboardCode key_code,
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int flags,
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             XEvent* event) {
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(event);
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Display* display = GetXDisplay();
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XKeyEvent key_event;
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.type = XKeyEventType(type);
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(0, key_event.type);
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.serial = 0;
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.send_event = 0;
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.display = display;
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.time = 0;
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.window = 0;
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.root = 0;
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.subwindow = 0;
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.x = 0;
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.y = 0;
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.x_root = 0;
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.y_root = 0;
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.state = XKeyEventState(flags);
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.keycode = XKeyEventKeyCode(key_code, flags, display);
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_event.same_screen = 1;
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event->type = key_event.type;
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event->xkey = key_event;
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedString::~XScopedString() {
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XFree(string_);
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedImage::~XScopedImage() {
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reset(NULL);
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void XScopedImage::reset(XImage* image) {
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_ == image)
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_)
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XDestroyImage(image_);
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_ = image;
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedCursor::XScopedCursor(::Cursor cursor, Display* display)
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : cursor_(cursor),
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      display_(display) {
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XScopedCursor::~XScopedCursor() {
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reset(0U);
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::Cursor XScopedCursor::get() const {
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cursor_;
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void XScopedCursor::reset(::Cursor cursor) {
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cursor_)
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFreeCursor(display_, cursor_);
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cursor_ = cursor;
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions are declared in x11_util_internal.h because they require
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// XLib.h to be included, and it conflicts with many other headers.
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XRenderPictFormat* GetRenderARGB32Format(Display* dpy) {
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static XRenderPictFormat* pictformat = NULL;
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pictformat)
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pictformat;
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First look for a 32-bit format which ignores the alpha value
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat templ;
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.depth = 32;
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.type = PictTypeDirect;
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.red = 16;
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.green = 8;
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.blue = 0;
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.redMask = 0xff;
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.greenMask = 0xff;
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.blueMask = 0xff;
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  templ.direct.alphaMask = 0;
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const unsigned long kMask =
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatType | PictFormatDepth |
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatRed | PictFormatRedMask |
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatGreen | PictFormatGreenMask |
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatBlue | PictFormatBlueMask |
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PictFormatAlphaMask;
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pictformat) {
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not all X servers support xRGB32 formats. However, the XRENDER spec says
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that they must support an ARGB32 format, so we can always return that.
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(pictformat) << "XRENDER ARGB32 not supported.";
17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pictformat;
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) {
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(QueryRenderSupport(dpy));
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CachedPictFormats* formats = get_cached_pict_formats();
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CachedPictFormats::const_iterator i = formats->begin();
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != formats->end(); ++i) {
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->equals(dpy, visual))
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i->format;
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not cached, look up the value.
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(pictformat) << "XRENDER does not support default visual";
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And store it in the cache.
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CachedPictFormat cached_value;
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.visual = visual;
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.display = dpy;
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_value.format = pictformat;
17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  formats->push_front(cached_value);
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (formats->size() == kMaxCacheSize) {
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    formats->pop_back();
17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should really only have at most 2 display/visual combinations:
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one for normal browser windows, and possibly another for an argb window
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // created to display a menu.
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we get here it's not fatal, we just need to make sure we aren't
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // always blowing away the cache. If we are, then we should figure out why
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and make it bigger.
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pictformat;
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetX11ErrorHandlers(XErrorHandler error_handler,
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         XIOErrorHandler io_error_handler) {
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSetIOErrorHandler(
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogErrorEventDescription(Display* dpy,
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const XErrorEvent& error_event) {
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char error_str[256];
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char request_str[256];
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str));
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strncpy(request_str, "Unknown", sizeof(request_str));
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_event.request_code < 128) {
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string num = base::UintToString(error_event.request_code);
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XGetErrorDatabaseText(
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dpy, "XRequest", num.c_str(), "Unknown", request_str,
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sizeof(request_str));
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int num_ext;
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char** ext_list = XListExtensions(dpy, &num_ext);
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < num_ext; i++) {
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int ext_code, first_event, first_error;
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error_event.request_code == ext_code) {
17782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string msg = base::StringPrintf(
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "%s.%d", ext_list[i], error_event.minor_code);
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XGetErrorDatabaseText(
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dpy, "XRequest", msg.c_str(), "Unknown", request_str,
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sizeof(request_str));
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XFreeExtensionList(ext_list);
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR)
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "X error received: "
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "serial " << error_event.serial << ", "
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "error_code " << static_cast<int>(error_event.error_code)
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << " (" << error_str << "), "
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "request_code " << static_cast<int>(error_event.request_code) << ", "
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "minor_code " << static_cast<int>(error_event.minor_code)
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << " (" << request_str << ")";
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// End of x11_util_internal.h
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ui
1804