Home | History | Annotate | Download | only in test
      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 
     14 namespace views {
     15 
     16 X11PropertyChangeWaiter::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 
     42 X11PropertyChangeWaiter::~X11PropertyChangeWaiter() {
     43   XSelectInput(gfx::GetXDisplay(), x_window_, old_event_mask_);
     44 }
     45 
     46 void 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 
     57 bool X11PropertyChangeWaiter::ShouldKeepOnWaiting(
     58     const ui::PlatformEvent& event) {
     59   // Stop waiting once we get a property change.
     60   return true;
     61 }
     62 
     63 bool X11PropertyChangeWaiter::CanDispatchEvent(const ui::PlatformEvent& event) {
     64   NOTREACHED();
     65   return true;
     66 }
     67 
     68 uint32_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