1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/views/test/x11_property_change_waiter.h"
6
7#include <X11/Xlib.h>
8
9#include "base/run_loop.h"
10#include "ui/events/platform/platform_event_source.h"
11#include "ui/events/platform/scoped_event_dispatcher.h"
12#include "ui/gfx/x/x11_atom_cache.h"
13
14namespace views {
15
16X11PropertyChangeWaiter::X11PropertyChangeWaiter(XID window,
17                                                 const char* property)
18    : x_window_(window),
19      property_(property),
20      wait_(true),
21      old_event_mask_(0) {
22  Display* display = gfx::GetXDisplay();
23
24  // Ensure that we are listening to PropertyNotify events for |window|. This
25  // is not the case for windows which were not created by
26  // DesktopWindowTreeHostX11.
27  XWindowAttributes attributes;
28  XGetWindowAttributes(display, x_window_, &attributes);
29  old_event_mask_ = attributes.your_event_mask;
30  XSelectInput(display, x_window_, old_event_mask_ | PropertyChangeMask);
31
32  const char* kAtomsToCache[] = { property, NULL };
33  atom_cache_.reset(new ui::X11AtomCache(display, kAtomsToCache));
34
35  // Override the dispatcher so that we get events before
36  // DesktopWindowTreeHostX11 does. We must do this because
37  // DesktopWindowTreeHostX11 stops propagation.
38  dispatcher_ = ui::PlatformEventSource::GetInstance()->
39      OverrideDispatcher(this).Pass();
40}
41
42X11PropertyChangeWaiter::~X11PropertyChangeWaiter() {
43  XSelectInput(gfx::GetXDisplay(), x_window_, old_event_mask_);
44}
45
46void X11PropertyChangeWaiter::Wait() {
47  if (!wait_)
48    return;
49
50  base::RunLoop run_loop;
51  quit_closure_ = run_loop.QuitClosure();
52  run_loop.Run();
53
54  dispatcher_.reset();
55}
56
57bool X11PropertyChangeWaiter::ShouldKeepOnWaiting(
58    const ui::PlatformEvent& event) {
59  // Stop waiting once we get a property change.
60  return true;
61}
62
63bool X11PropertyChangeWaiter::CanDispatchEvent(const ui::PlatformEvent& event) {
64  NOTREACHED();
65  return true;
66}
67
68uint32_t X11PropertyChangeWaiter::DispatchEvent(
69    const ui::PlatformEvent& event) {
70  if (!wait_ ||
71      event->type != PropertyNotify ||
72      event->xproperty.window != x_window_ ||
73      event->xproperty.atom != atom_cache_->GetAtom(property_) ||
74      ShouldKeepOnWaiting(event)) {
75    return ui::POST_DISPATCH_PERFORM_DEFAULT;
76  }
77
78  wait_ = false;
79  if (!quit_closure_.is_null())
80    quit_closure_.Run();
81  return ui::POST_DISPATCH_PERFORM_DEFAULT;
82}
83
84}  // namespace views
85