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.
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"
11 #include <X11/extensions/Xrandr.h>
16 const int NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs
= 7000;
18 NativeDisplayEventDispatcherX11::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();
27 NativeDisplayEventDispatcherX11::~NativeDisplayEventDispatcherX11() {}
29 bool NativeDisplayEventDispatcherX11::CanDispatchEvent(
30 const PlatformEvent
& event
) {
31 return (event
->type
- xrandr_event_base_
== RRScreenChangeNotify
) ||
32 (event
->type
- xrandr_event_base_
== RRNotify
);
35 uint32_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
;
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
;
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");
63 bool check_cache
= (tick_clock_
->NowTicks() - startup_time_
)
64 .InMilliseconds() <= kUseCacheAfterStartupMs
;
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();
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 RRMode mode_id
= x11_mode
? x11_mode
->mode_id() : None
;
80 // Update if we failed to fetch the external display's ID before.
81 // Internal display's EDID should always be available.
82 bool display_id_needs_update
=
83 x11_output
->type() != ui::DISPLAY_CONNECTION_TYPE_INTERNAL
&&
84 !x11_output
->display_id();
86 if (x11_output
->output() == output_change_event
->output
) {
87 if (connected
&& x11_output
->crtc() == output_change_event
->crtc
&&
88 mode_id
== output_change_event
->mode
&&
89 !display_id_needs_update
) {
90 VLOG(1) << "Ignoring event describing already-cached state";
91 return POST_DISPATCH_PERFORM_DEFAULT
;
93 found_changed_output
= true;
98 if (!connected
&& !found_changed_output
) {
99 VLOG(1) << "Ignoring event describing already-disconnected output";
100 return ui::POST_DISPATCH_PERFORM_DEFAULT
;
104 delegate_
->NotifyDisplayObservers();
106 return ui::POST_DISPATCH_PERFORM_DEFAULT
;
109 void NativeDisplayEventDispatcherX11::SetTickClockForTest(
110 scoped_ptr
<base::TickClock
> tick_clock
) {
111 tick_clock_
= tick_clock
.Pass();
112 startup_time_
= tick_clock_
->NowTicks();