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 "base/time/default_tick_clock.h" 6#include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h" 7#include "ui/display/chromeos/x11/display_mode_x11.h" 8#include "ui/display/chromeos/x11/display_snapshot_x11.h" 9#include "ui/events/platform/platform_event_source.h" 10 11#include <X11/extensions/Xrandr.h> 12 13namespace ui { 14 15// static 16const int NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs = 7000; 17 18NativeDisplayEventDispatcherX11::NativeDisplayEventDispatcherX11( 19 NativeDisplayDelegateX11::HelperDelegate* delegate, 20 int xrandr_event_base) 21 : delegate_(delegate), 22 xrandr_event_base_(xrandr_event_base), 23 tick_clock_(new base::DefaultTickClock) { 24 startup_time_ = tick_clock_->NowTicks(); 25} 26 27NativeDisplayEventDispatcherX11::~NativeDisplayEventDispatcherX11() {} 28 29bool NativeDisplayEventDispatcherX11::CanDispatchEvent( 30 const PlatformEvent& event) { 31 return (event->type - xrandr_event_base_ == RRScreenChangeNotify) || 32 (event->type - xrandr_event_base_ == RRNotify); 33} 34 35uint32_t NativeDisplayEventDispatcherX11::DispatchEvent( 36 const PlatformEvent& event) { 37 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) { 38 VLOG(1) << "Received RRScreenChangeNotify event"; 39 delegate_->UpdateXRandRConfiguration(event); 40 return ui::POST_DISPATCH_PERFORM_DEFAULT; 41 } 42 43 // Bail out early for everything except RRNotify_OutputChange events 44 // about an output getting connected or disconnected. 45 if (event->type - xrandr_event_base_ != RRNotify) 46 return ui::POST_DISPATCH_PERFORM_DEFAULT; 47 const XRRNotifyEvent* notify_event = reinterpret_cast<XRRNotifyEvent*>(event); 48 if (notify_event->subtype != RRNotify_OutputChange) 49 return ui::POST_DISPATCH_PERFORM_DEFAULT; 50 const XRROutputChangeNotifyEvent* output_change_event = 51 reinterpret_cast<XRROutputChangeNotifyEvent*>(event); 52 const int action = output_change_event->connection; 53 if (action != RR_Connected && action != RR_Disconnected) 54 return ui::POST_DISPATCH_PERFORM_DEFAULT; 55 56 const bool connected = (action == RR_Connected); 57 VLOG(1) << "Received RRNotify_OutputChange event:" 58 << " output=" << output_change_event->output 59 << " crtc=" << output_change_event->crtc 60 << " mode=" << output_change_event->mode 61 << " action=" << (connected ? "connected" : "disconnected"); 62 63 bool check_cache = (tick_clock_->NowTicks() - startup_time_) 64 .InMilliseconds() <= kUseCacheAfterStartupMs; 65 66 if (check_cache) { 67 bool found_changed_output = false; 68 const std::vector<DisplaySnapshot*>& cached_outputs = 69 delegate_->GetCachedDisplays(); 70 for (std::vector<DisplaySnapshot*>::const_iterator it = 71 cached_outputs.begin(); 72 it != cached_outputs.end(); 73 ++it) { 74 const DisplaySnapshotX11* x11_output = 75 static_cast<const DisplaySnapshotX11*>(*it); 76 const DisplayModeX11* x11_mode = 77 static_cast<const DisplayModeX11*>(x11_output->current_mode()); 78 79 if (x11_output->output() == output_change_event->output) { 80 if (connected && x11_output->crtc() == output_change_event->crtc && 81 x11_mode->mode_id() == output_change_event->mode) { 82 VLOG(1) << "Ignoring event describing already-cached state"; 83 return POST_DISPATCH_PERFORM_DEFAULT; 84 } 85 found_changed_output = true; 86 break; 87 } 88 } 89 90 if (!connected && !found_changed_output) { 91 VLOG(1) << "Ignoring event describing already-disconnected output"; 92 return ui::POST_DISPATCH_PERFORM_DEFAULT; 93 } 94 } 95 96 delegate_->NotifyDisplayObservers(); 97 98 return ui::POST_DISPATCH_PERFORM_DEFAULT; 99} 100 101void NativeDisplayEventDispatcherX11::SetTickClockForTest( 102 scoped_ptr<base::TickClock> tick_clock) { 103 tick_clock_ = tick_clock.Pass(); 104 startup_time_ = tick_clock_->NowTicks(); 105} 106 107} // namespace ui 108