desktop_screen_x11.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_screen_x11.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <X11/extensions/Xrandr.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xlib.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It clashes with out RootWindow. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef RootWindow 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/x11/edid_parser_x11.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window_host.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/display.h" 1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/gfx/display_observer.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/native_widget_types.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/gfx/x/x11_types.h" 2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_screen.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// The delay to perform configuration after RRNotify. See the comment 2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// in |Dispatch()|. 2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int64 kConfigureDelayMs = 500; 3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<gfx::Display> GetFallbackDisplayList() { 3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ::XDisplay* display = gfx::GetXDisplay(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::Screen* screen = DefaultScreenOfDisplay(display); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = WidthOfScreen(screen); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height = HeightOfScreen(screen); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return std::vector<gfx::Display>( 3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1, gfx::Display(0, gfx::Rect(0, 0, width, height))); 3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} // namespace 4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace views { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DesktopScreenX11, public: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)DesktopScreenX11::DesktopScreenX11() 4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()), 5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) x_root_window_(DefaultRootWindow(xdisplay_)), 5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) has_xrandr_(false), 5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) xrandr_event_base_(0) { 5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // We only support 1.3+. There were library changes before this and we should 5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // use the new interface instead of the 1.2 one. 5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int randr_version_major = 0; 5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int randr_version_minor = 0; 5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) has_xrandr_ = XRRQueryVersion( 5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) xdisplay_, &randr_version_major, &randr_version_minor) && 5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) randr_version_major == 1 && 6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) randr_version_minor >= 3; 6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (has_xrandr_) { 6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int error_base_ignored = 0; 6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); 6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this); 6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRSelectInput(xdisplay_, 6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) x_root_window_, 6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) RRScreenChangeNotifyMask | RROutputChangeNotifyMask); 7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) displays_ = BuildDisplaysFromXRandRInfo(); 7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else { 7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) displays_ = GetFallbackDisplayList(); 7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DesktopScreenX11::~DesktopScreenX11() { 7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (has_xrandr_) 7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this); 8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DesktopScreenX11::ProcessDisplayChange( 8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const std::vector<gfx::Display>& incoming) { 8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::vector<gfx::Display>::const_iterator cur_it = displays_.begin(); 8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (; cur_it != displays_.end(); ++cur_it) { 8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bool found = false; 8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (std::vector<gfx::Display>::const_iterator incoming_it = 8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) incoming.begin(); incoming_it != incoming.end(); ++incoming_it) { 8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (cur_it->id() == incoming_it->id()) { 9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) found = true; 9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) break; 9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!found) { 9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_, 9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) OnDisplayRemoved(*cur_it)); 9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::vector<gfx::Display>::const_iterator incoming_it = incoming.begin(); 10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (; incoming_it != incoming.end(); ++incoming_it) { 10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bool found = false; 10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (std::vector<gfx::Display>::const_iterator cur_it = displays_.begin(); 10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) cur_it != displays_.end(); ++cur_it) { 10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (incoming_it->id() == cur_it->id()) { 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (incoming_it->bounds() != cur_it->bounds()) { 10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_, 10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) OnDisplayBoundsChanged(*incoming_it)); 11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) found = true; 11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) break; 11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!found) { 11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_, 11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) OnDisplayAdded(*incoming_it)); 12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) displays_ = incoming; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DesktopScreenX11, gfx::Screen implementation: 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DesktopScreenX11::IsDIPEnabled() { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Point DesktopScreenX11::GetCursorScreenPoint() { 13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XDisplay* display = gfx::GetXDisplay(); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::Window root, child; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int root_x, root_y, win_x, win_y; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int mask; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) XQueryPointer(display, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DefaultRootWindow(display), 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &root, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &child, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &root_x, 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &root_y, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &win_x, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &win_y, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &mask); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Point(root_x, root_y); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 152424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() { 15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return GetWindowAtScreenPoint(GetCursorScreenPoint()); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 156424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint( 157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const gfx::Point& point) { 15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // TODO(erg): Implement using the discussion at 15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // http://codereview.chromium.org/10279005/ 160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) NOTIMPLEMENTED(); 161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return NULL; 162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)int DesktopScreenX11::GetNumDisplays() const { 16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return displays_.size(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const { 16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return displays_; 170424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Display DesktopScreenX11::GetDisplayNearestWindow( 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeView window) const { 17468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // TODO(erg): This should theoretically be easy, but it isn't. At the time we 17568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // get called here, our aura::Window has not been Init()ed, because this 17668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // method is called to get the device scale factor as part of 17768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // RootWindow::Init(), before Window::Init(). This seems very confused; we're 17868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // trying to get a display nearest window even before we've allocated the 17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // root window. Once fixed, the correct implementation should probably be: 18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // 18168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // return GetDisplayMatching(window->GetBoundsInScreen()); 18268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // 18368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // But at least for now, we'll just fallback: 18468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return GetPrimaryDisplay(); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Display DesktopScreenX11::GetDisplayNearestPoint( 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Point& point) const { 18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (std::vector<gfx::Display>::const_iterator it = displays_.begin(); 19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) it != displays_.end(); ++it) { 19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (it->bounds().Contains(point)) 19268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return *it; 19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 19468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 19568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return GetPrimaryDisplay(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Display DesktopScreenX11::GetDisplayMatching( 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& match_rect) const { 20068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int max_area = 0; 20168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const gfx::Display* matching = NULL; 20268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (std::vector<gfx::Display>::const_iterator it = displays_.begin(); 20368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) it != displays_.end(); ++it) { 20468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect); 20568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int area = intersect.width() * intersect.height(); 20668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (area > max_area) { 20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) max_area = area; 20868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) matching = &*it; 20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Fallback to the primary display if there is no matching display. 21268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return matching ? *matching : GetPrimaryDisplay(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Display DesktopScreenX11::GetPrimaryDisplay() const { 21668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return displays_.front(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) { 22068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) observer_list_.AddObserver(observer); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 22268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) { 22468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) observer_list_.RemoveObserver(observer); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) { 22868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (event->type - xrandr_event_base_ == RRScreenChangeNotify) { 22968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Pass the event through to xlib. 23068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRUpdateConfiguration(event); 23168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else if (event->type - xrandr_event_base_ == RRNotify) { 23268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // There's some sort of observer dispatch going on here, but I don't think 23368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // it's the screen's? 23468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DLOG(ERROR) << "DesktopScreenX11::Dispatch() -> RRNotify"; 23568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 23668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (configure_timer_.get()) { 23768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) configure_timer_->Reset(); 23868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else { 23968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>()); 24068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) configure_timer_->Start( 24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) FROM_HERE, 24268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kConfigureDelayMs), 24368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this, 24468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) &DesktopScreenX11::ConfigureTimerFired); 24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 24868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return true; 24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// DesktopScreenX11, private: 25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 25468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)DesktopScreenX11::DesktopScreenX11( 25568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const std::vector<gfx::Display>& test_displays) 25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()), 25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) x_root_window_(DefaultRootWindow(xdisplay_)), 25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) has_xrandr_(false), 25968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) xrandr_event_base_(0), 26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) displays_(test_displays) { 26168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { 26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::vector<gfx::Display> displays; 26568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRScreenResources* resources = 26668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_); 26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!resources) { 26868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window."; 26968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return GetFallbackDisplayList(); 27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bool has_work_area = false; 27368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Rect work_area; 27468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::vector<int> value; 27568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) && 27668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) value.size() >= 4) { 27768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) work_area = gfx::Rect(value[0], value[1], value[2], value[3]); 27868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) has_work_area = true; 27968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 28068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 28168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int i = 0; i < resources->noutput; ++i) { 28268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) RROutput output_id = resources->outputs[i]; 28368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRROutputInfo* output_info = 28468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRGetOutputInfo(xdisplay_, resources, output_id); 28568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 28668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bool is_connected = (output_info->connection == RR_Connected); 28768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!is_connected) { 28868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRFreeOutputInfo(output_info); 28968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) continue; 29068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 29168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 29268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (output_info->crtc) { 29368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRCrtcInfo *crtc = XRRGetCrtcInfo(xdisplay_, 29468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) resources, 29568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) output_info->crtc); 29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 29768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int64 display_id = -1; 29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!base::GetDisplayId(output_id, i, &display_id)) { 29968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // It isn't ideal, but if we can't parse the EDID data, fallback on the 30068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // display number. 30168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) display_id = i; 30268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 30368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 30468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height); 30568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Display display(display_id, crtc_bounds); 30668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (has_work_area) { 30768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Rect intersection = crtc_bounds; 30868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) intersection.Intersect(work_area); 30968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) display.set_work_area(intersection); 31068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 31268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) displays.push_back(display); 31368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 31468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRFreeCrtcInfo(crtc); 31568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 31668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 31768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRFreeOutputInfo(output_info); 31868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 31968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 32068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XRRFreeScreenResources(resources); 32168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 32268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (displays.empty()) 32368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return GetFallbackDisplayList(); 32468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 32568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return displays; 32668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DesktopScreenX11::ConfigureTimerFired() { 32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::vector<gfx::Display> new_displays = BuildDisplaysFromXRandRInfo(); 33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ProcessDisplayChange(new_displays); 33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 33268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 33368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Screen* CreateDesktopScreen() { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new DesktopScreenX11; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace views 340