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