Home | History | Annotate | Download | only in desktop_aura
      1 // Copyright (c) 2012 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/widget/desktop_aura/desktop_root_window_host_x11.h"
      6 
      7 #include <X11/extensions/shape.h>
      8 #include <X11/extensions/XInput2.h>
      9 #include <X11/Xatom.h>
     10 #include <X11/Xregion.h>
     11 #include <X11/Xutil.h>
     12 
     13 #include "base/message_loop/message_pump_aurax11.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "third_party/skia/include/core/SkPath.h"
     17 #include "ui/aura/client/screen_position_client.h"
     18 #include "ui/aura/client/user_action_client.h"
     19 #include "ui/aura/focus_manager.h"
     20 #include "ui/aura/root_window.h"
     21 #include "ui/aura/window_property.h"
     22 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
     23 #include "ui/base/events/event_utils.h"
     24 #include "ui/base/touch/touch_factory_x11.h"
     25 #include "ui/base/x/x11_util.h"
     26 #include "ui/gfx/insets.h"
     27 #include "ui/gfx/path_x11.h"
     28 #include "ui/linux_ui/linux_ui.h"
     29 #include "ui/native_theme/native_theme.h"
     30 #include "ui/views/corewm/compound_event_filter.h"
     31 #include "ui/views/corewm/corewm_switches.h"
     32 #include "ui/views/corewm/cursor_manager.h"
     33 #include "ui/views/corewm/focus_controller.h"
     34 #include "ui/views/ime/input_method.h"
     35 #include "ui/views/widget/desktop_aura/desktop_activation_client.h"
     36 #include "ui/views/widget/desktop_aura/desktop_capture_client.h"
     37 #include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h"
     38 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
     39 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
     40 #include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
     41 #include "ui/views/widget/desktop_aura/desktop_layout_manager.h"
     42 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
     43 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
     44 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
     45 #include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
     46 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
     47 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
     48 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
     49 
     50 namespace views {
     51 
     52 DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
     53     NULL;
     54 std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
     55 
     56 DEFINE_WINDOW_PROPERTY_KEY(
     57     aura::Window*, kViewsWindowForRootWindow, NULL);
     58 
     59 DEFINE_WINDOW_PROPERTY_KEY(
     60     DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
     61 
     62 namespace {
     63 
     64 // Standard Linux mouse buttons for going back and forward.
     65 const int kBackMouseButton = 8;
     66 const int kForwardMouseButton = 9;
     67 
     68 // Constants that are part of EWMH.
     69 const int k_NET_WM_STATE_ADD = 1;
     70 const int k_NET_WM_STATE_REMOVE = 0;
     71 
     72 const char* kAtomsToCache[] = {
     73   "WM_DELETE_WINDOW",
     74   "WM_PROTOCOLS",
     75   "WM_S0",
     76   "_NET_WM_PID",
     77   "_NET_WM_PING",
     78   "_NET_WM_STATE",
     79   "_NET_WM_STATE_ABOVE",
     80   "_NET_WM_STATE_FULLSCREEN",
     81   "_NET_WM_STATE_HIDDEN",
     82   "_NET_WM_STATE_MAXIMIZED_HORZ",
     83   "_NET_WM_STATE_MAXIMIZED_VERT",
     84   "_NET_WM_STATE_SKIP_TASKBAR",
     85   "_NET_WM_WINDOW_OPACITY",
     86   "_NET_WM_WINDOW_TYPE",
     87   "_NET_WM_WINDOW_TYPE_MENU",
     88   "_NET_WM_WINDOW_TYPE_NORMAL",
     89   "_NET_WM_WINDOW_TYPE_TOOLTIP",
     90   "XdndActionAsk",
     91   "XdndActionCopy"
     92   "XdndActionLink",
     93   "XdndActionList",
     94   "XdndActionMove",
     95   "XdndActionPrivate",
     96   "XdndAware",
     97   "XdndDrop",
     98   "XdndEnter",
     99   "XdndFinished",
    100   "XdndLeave",
    101   "XdndPosition",
    102   "XdndProxy",  // Proxy windows?
    103   "XdndSelection",
    104   "XdndStatus",
    105   "XdndTypeList",
    106   NULL
    107 };
    108 
    109 }  // namespace
    110 
    111 ////////////////////////////////////////////////////////////////////////////////
    112 // DesktopRootWindowHostX11, public:
    113 
    114 DesktopRootWindowHostX11::DesktopRootWindowHostX11(
    115     internal::NativeWidgetDelegate* native_widget_delegate,
    116     DesktopNativeWidgetAura* desktop_native_widget_aura,
    117     const gfx::Rect& initial_bounds)
    118     : close_widget_factory_(this),
    119       xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
    120       xwindow_(0),
    121       x_root_window_(DefaultRootWindow(xdisplay_)),
    122       atom_cache_(xdisplay_, kAtomsToCache),
    123       window_mapped_(false),
    124       focus_when_shown_(false),
    125       current_cursor_(ui::kCursorNull),
    126       native_widget_delegate_(native_widget_delegate),
    127       desktop_native_widget_aura_(desktop_native_widget_aura) {
    128 }
    129 
    130 DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
    131   root_window_->ClearProperty(kHostForRootWindow);
    132   if (corewm::UseFocusControllerOnDesktop()) {
    133     aura::client::SetFocusClient(root_window_, NULL);
    134     aura::client::SetActivationClient(root_window_, NULL);
    135   }
    136 }
    137 
    138 // static
    139 aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
    140   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
    141   return root ? root->GetProperty(kViewsWindowForRootWindow) : NULL;
    142 }
    143 
    144 // static
    145 DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
    146   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
    147   return root ? root->GetProperty(kHostForRootWindow) : NULL;
    148 }
    149 
    150 // static
    151 std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
    152   std::vector<aura::Window*> windows(open_windows().size());
    153   std::transform(open_windows().begin(),
    154                  open_windows().end(),
    155                  windows.begin(),
    156                  GetContentWindowForXID);
    157   return windows;
    158 }
    159 
    160 void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
    161     bool active) {
    162   if (active)
    163     root_window_host_delegate_->OnHostActivated();
    164   native_widget_delegate_->OnNativeWidgetActivationChanged(active);
    165   // If we're not active we need to deactivate the corresponding aura::Window.
    166   // This way if a child widget is active it gets correctly deactivated (child
    167   // widgets don't get native desktop activation changes, only aura activation
    168   // changes).
    169   if (!active) {
    170     aura::client::ActivationClient* activation_client =
    171         aura::client::GetActivationClient(root_window_);
    172     if (activation_client) {
    173       aura::Window* active_window = activation_client->GetActiveWindow();
    174       if (active_window)
    175         activation_client->DeactivateWindow(active_window);
    176     }
    177   }
    178 
    179   native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
    180 }
    181 
    182 void DesktopRootWindowHostX11::AddObserver(
    183     views::DesktopRootWindowHostObserverX11* observer) {
    184   observer_list_.AddObserver(observer);
    185 }
    186 
    187 void DesktopRootWindowHostX11::RemoveObserver(
    188     views::DesktopRootWindowHostObserverX11* observer) {
    189   observer_list_.RemoveObserver(observer);
    190 }
    191 
    192 void DesktopRootWindowHostX11::CleanUpWindowList() {
    193   delete open_windows_;
    194   open_windows_ = NULL;
    195 }
    196 
    197 ////////////////////////////////////////////////////////////////////////////////
    198 // DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
    199 
    200 aura::RootWindow* DesktopRootWindowHostX11::Init(
    201     aura::Window* content_window,
    202     const Widget::InitParams& params) {
    203   content_window_ = content_window;
    204 
    205   // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
    206   // whether we should be proxying requests to another DRWHL.
    207 
    208   // In some situations, views tries to make a zero sized window, and that
    209   // makes us crash. Make sure we have valid sizes.
    210   Widget::InitParams sanitized_params = params;
    211   if (sanitized_params.bounds.width() == 0)
    212     sanitized_params.bounds.set_width(100);
    213   if (sanitized_params.bounds.height() == 0)
    214     sanitized_params.bounds.set_height(100);
    215 
    216   InitX11Window(sanitized_params);
    217   return InitRootWindow(sanitized_params);
    218 }
    219 
    220 void DesktopRootWindowHostX11::InitFocus(aura::Window* window) {
    221 }
    222 
    223 void DesktopRootWindowHostX11::Close() {
    224   // TODO(erg): Might need to do additional hiding tasks here.
    225 
    226   if (!close_widget_factory_.HasWeakPtrs()) {
    227     // And we delay the close so that if we are called from an ATL callback,
    228     // we don't destroy the window before the callback returned (as the caller
    229     // may delete ourselves on destroy and the ATL callback would still
    230     // dereference us when the callback returns).
    231     base::MessageLoop::current()->PostTask(
    232         FROM_HERE,
    233         base::Bind(&DesktopRootWindowHostX11::CloseNow,
    234                    close_widget_factory_.GetWeakPtr()));
    235   }
    236 }
    237 
    238 void DesktopRootWindowHostX11::CloseNow() {
    239   if (xwindow_ == None)
    240     return;
    241 
    242   native_widget_delegate_->OnNativeWidgetDestroying();
    243 
    244   // Remove the event listeners we've installed. We need to remove these
    245   // because otherwise we get assert during ~RootWindow().
    246   desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
    247       x11_window_event_filter_.get());
    248 
    249   open_windows().remove(xwindow_);
    250   // Actually free our native resources.
    251   base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_);
    252   XDestroyWindow(xdisplay_, xwindow_);
    253   xwindow_ = None;
    254 
    255   desktop_native_widget_aura_->OnHostClosed();
    256 }
    257 
    258 aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
    259   return this;
    260 }
    261 
    262 void DesktopRootWindowHostX11::ShowWindowWithState(
    263     ui::WindowShowState show_state) {
    264   if (show_state != ui::SHOW_STATE_DEFAULT &&
    265       show_state != ui::SHOW_STATE_NORMAL) {
    266     // Only forwarding to Show().
    267     NOTIMPLEMENTED();
    268   }
    269 
    270   Show();
    271 }
    272 
    273 void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
    274     const gfx::Rect& restored_bounds) {
    275   restored_bounds_ = restored_bounds;
    276   Maximize();
    277   Show();
    278 }
    279 
    280 bool DesktopRootWindowHostX11::IsVisible() const {
    281   return window_mapped_;
    282 }
    283 
    284 void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
    285   // TODO(erg):
    286   NOTIMPLEMENTED();
    287 }
    288 
    289 void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
    290   gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
    291 
    292   // If |window_|'s transient parent bounds are big enough to contain |size|,
    293   // use them instead.
    294   if (content_window_->transient_parent()) {
    295     gfx::Rect transient_parent_rect =
    296         content_window_->transient_parent()->GetBoundsInScreen();
    297     if (transient_parent_rect.height() >= size.height() &&
    298         transient_parent_rect.width() >= size.width()) {
    299       parent_bounds = transient_parent_rect;
    300     }
    301   }
    302 
    303   gfx::Rect window_bounds(
    304       parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
    305       parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
    306       size.width(),
    307       size.height());
    308   // Don't size the window bigger than the parent, otherwise the user may not be
    309   // able to close or move it.
    310   window_bounds.AdjustToFit(parent_bounds);
    311 
    312   SetBounds(window_bounds);
    313 }
    314 
    315 void DesktopRootWindowHostX11::GetWindowPlacement(
    316     gfx::Rect* bounds,
    317     ui::WindowShowState* show_state) const {
    318   *bounds = bounds_;
    319 
    320   // TODO(erg): This needs a better implementation. For now, we're just pass
    321   // back the normal state until we keep track of this.
    322   *show_state = ui::SHOW_STATE_NORMAL;
    323 }
    324 
    325 gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
    326   return bounds_;
    327 }
    328 
    329 gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
    330   // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
    331   // needed for View::ConvertPointToScreen() to work
    332   // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
    333   // asks windows what it thinks the client rect is.
    334   //
    335   // Attempts to calculate the rect by asking the NonClientFrameView what it
    336   // thought its GetBoundsForClientView() were broke combobox drop down
    337   // placement.
    338   return bounds_;
    339 }
    340 
    341 gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
    342   // We can't reliably track the restored bounds of a window, but we can get
    343   // the 90% case down. When *chrome* is the process that requests maximizing
    344   // or restoring bounds, we can record the current bounds before we request
    345   // maximization, and clear it when we detect a state change.
    346   if (!restored_bounds_.IsEmpty())
    347     return restored_bounds_;
    348 
    349   return GetWindowBoundsInScreen();
    350 }
    351 
    352 gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
    353   std::vector<int> value;
    354   if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
    355       value.size() >= 4) {
    356     return gfx::Rect(value[0], value[1], value[2], value[3]);
    357   }
    358 
    359   // Fetch the geometry of the root window.
    360   Window root;
    361   int x, y;
    362   unsigned int width, height;
    363   unsigned int border_width, depth;
    364   if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
    365                     &width, &height, &border_width, &depth)) {
    366     NOTIMPLEMENTED();
    367     return gfx::Rect(0, 0, 10, 10);
    368   }
    369 
    370   return gfx::Rect(x, y, width, height);
    371 }
    372 
    373 void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
    374   SkPath path;
    375   native_region->getBoundaryPath(&path);
    376   Region region = gfx::CreateRegionFromSkPath(path);
    377   XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, region, false);
    378   XDestroyRegion(region);
    379 }
    380 
    381 void DesktopRootWindowHostX11::Activate() {
    382   X11DesktopHandler::get()->ActivateWindow(xwindow_);
    383 }
    384 
    385 void DesktopRootWindowHostX11::Deactivate() {
    386   // Deactivating a window means activating nothing.
    387   X11DesktopHandler::get()->ActivateWindow(None);
    388 }
    389 
    390 bool DesktopRootWindowHostX11::IsActive() const {
    391   return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
    392 }
    393 
    394 void DesktopRootWindowHostX11::Maximize() {
    395   // When we're the process requesting the maximizing, we can accurately keep
    396   // track of our restored bounds instead of relying on the heuristics that are
    397   // in the PropertyNotify and ConfigureNotify handlers.
    398   restored_bounds_ = bounds_;
    399 
    400   SetWMSpecState(true,
    401                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
    402                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
    403 }
    404 
    405 void DesktopRootWindowHostX11::Minimize() {
    406   XIconifyWindow(xdisplay_, xwindow_, 0);
    407 }
    408 
    409 void DesktopRootWindowHostX11::Restore() {
    410   SetWMSpecState(false,
    411                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
    412                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
    413 }
    414 
    415 bool DesktopRootWindowHostX11::IsMaximized() const {
    416   return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") ||
    417           HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
    418 }
    419 
    420 bool DesktopRootWindowHostX11::IsMinimized() const {
    421   return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
    422 }
    423 
    424 
    425 bool DesktopRootWindowHostX11::HasCapture() const {
    426   return g_current_capture == this;
    427 }
    428 
    429 void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
    430   SetWMSpecState(always_on_top,
    431                  atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
    432                  None);
    433 }
    434 
    435 void DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
    436   XStoreName(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str());
    437 }
    438 
    439 void DesktopRootWindowHostX11::ClearNativeFocus() {
    440   // This method is weird and misnamed. Instead of clearing the native focus,
    441   // it sets the focus to our |content_window_|, which will trigger a cascade
    442   // of focus changes into views.
    443   if (content_window_ && aura::client::GetFocusClient(content_window_) &&
    444       content_window_->Contains(
    445           aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
    446     aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
    447   }
    448 }
    449 
    450 Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
    451     const gfx::Vector2d& drag_offset,
    452     Widget::MoveLoopSource source) {
    453   SetCapture();
    454 
    455   aura::client::WindowMoveSource window_move_source =
    456       source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
    457       aura::client::WINDOW_MOVE_SOURCE_MOUSE :
    458       aura::client::WINDOW_MOVE_SOURCE_TOUCH;
    459   if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
    460       window_move_source) == aura::client::MOVE_SUCCESSFUL)
    461     return Widget::MOVE_LOOP_SUCCESSFUL;
    462 
    463   return Widget::MOVE_LOOP_CANCELED;
    464 }
    465 
    466 void DesktopRootWindowHostX11::EndMoveLoop() {
    467   x11_window_move_client_->EndMoveLoop();
    468 }
    469 
    470 void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
    471     bool value) {
    472   // Much like the previous NativeWidgetGtk, we don't have anything to do here.
    473 }
    474 
    475 bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
    476   return false;
    477 }
    478 
    479 void DesktopRootWindowHostX11::FrameTypeChanged() {
    480   // Replace the frame and layout the contents. Even though we don't have a
    481   // swapable glass frame like on Windows, we still replace the frame because
    482   // the button assets don't update otherwise.
    483   native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(true);
    484 }
    485 
    486 NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
    487   return NULL;
    488 }
    489 
    490 void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
    491   SetWMSpecState(fullscreen,
    492                  atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
    493                  None);
    494 }
    495 
    496 bool DesktopRootWindowHostX11::IsFullscreen() const {
    497   return HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
    498 }
    499 
    500 void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
    501   // X server opacity is in terms of 32 bit unsigned int space, and counts from
    502   // the opposite direction.
    503   unsigned int cardinality = opacity * 0x1010101;
    504 
    505   if (cardinality == 0xffffffff) {
    506     XDeleteProperty(xdisplay_, xwindow_,
    507                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
    508   } else {
    509     XChangeProperty(xdisplay_, xwindow_,
    510                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
    511                     XA_CARDINAL, 32,
    512                     PropModeReplace,
    513                     reinterpret_cast<unsigned char*>(&cardinality), 1);
    514   }
    515 }
    516 
    517 void DesktopRootWindowHostX11::SetWindowIcons(
    518     const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
    519   // TODO(erg):
    520   NOTIMPLEMENTED();
    521 }
    522 
    523 void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
    524   // TODO(erg):
    525   NOTIMPLEMENTED();
    526 }
    527 
    528 void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
    529   // TODO(erg):
    530   NOTIMPLEMENTED();
    531 }
    532 
    533 void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
    534   native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
    535 }
    536 
    537 void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
    538   if (xwindow_)
    539     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
    540 }
    541 
    542 void DesktopRootWindowHostX11::SetInactiveRenderingDisabled(
    543     bool disable_inactive) {
    544 }
    545 
    546 ////////////////////////////////////////////////////////////////////////////////
    547 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
    548 
    549 void DesktopRootWindowHostX11::SetDelegate(
    550     aura::RootWindowHostDelegate* delegate) {
    551   root_window_host_delegate_ = delegate;
    552 }
    553 
    554 aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
    555   return root_window_;
    556 }
    557 
    558 gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
    559   return xwindow_;
    560 }
    561 
    562 void DesktopRootWindowHostX11::Show() {
    563   if (!window_mapped_) {
    564     // Before we map the window, set size hints. Otherwise, some window managers
    565     // will ignore toplevel XMoveWindow commands.
    566     XSizeHints size_hints;
    567     size_hints.flags = PPosition;
    568     size_hints.x = bounds_.x();
    569     size_hints.y = bounds_.y();
    570     XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
    571 
    572     XMapWindow(xdisplay_, xwindow_);
    573 
    574     // We now block until our window is mapped. Some X11 APIs will crash and
    575     // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
    576     // asynchronous.
    577     base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_);
    578     window_mapped_ = true;
    579   }
    580 }
    581 
    582 void DesktopRootWindowHostX11::Hide() {
    583   if (window_mapped_) {
    584     XWithdrawWindow(xdisplay_, xwindow_, 0);
    585     window_mapped_ = false;
    586   }
    587 }
    588 
    589 void DesktopRootWindowHostX11::ToggleFullScreen() {
    590   NOTIMPLEMENTED();
    591 }
    592 
    593 gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
    594   return bounds_;
    595 }
    596 
    597 void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
    598   bool origin_changed = bounds_.origin() != bounds.origin();
    599   bool size_changed = bounds_.size() != bounds.size();
    600   XWindowChanges changes = {0};
    601   unsigned value_mask = 0;
    602 
    603   if (size_changed) {
    604     // X11 will send an XError at our process if have a 0 sized window.
    605     DCHECK_GT(bounds.width(), 0);
    606     DCHECK_GT(bounds.height(), 0);
    607 
    608     changes.width = bounds.width();
    609     changes.height = bounds.height();
    610     value_mask |= CWHeight | CWWidth;
    611   }
    612 
    613   if (origin_changed) {
    614     changes.x = bounds.x();
    615     changes.y = bounds.y();
    616     value_mask |= CWX | CWY;
    617   }
    618   if (value_mask)
    619     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
    620 
    621   // Assume that the resize will go through as requested, which should be the
    622   // case if we're running without a window manager.  If there's a window
    623   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
    624   // (possibly synthetic) ConfigureNotify about the actual size and correct
    625   // |bounds_| later.
    626   bounds_ = bounds;
    627 
    628   if (origin_changed)
    629     native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
    630   if (size_changed)
    631     root_window_host_delegate_->OnHostResized(bounds.size());
    632   else
    633     root_window_host_delegate_->OnHostPaint(gfx::Rect(bounds.size()));
    634 }
    635 
    636 gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
    637   return gfx::Insets();
    638 }
    639 
    640 void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
    641 }
    642 
    643 gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
    644   return bounds_.origin();
    645 }
    646 
    647 void DesktopRootWindowHostX11::SetCapture() {
    648   // This is vaguely based on the old NativeWidgetGtk implementation.
    649   //
    650   // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
    651   // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
    652   // a grab that wasn't the X11 pointer grab, but was instead a manual
    653   // redirection of the event. (You need to drop into GDK if you want to
    654   // perform a raw X11 grab).
    655 
    656   if (g_current_capture)
    657     g_current_capture->OnCaptureReleased();
    658 
    659   g_current_capture = this;
    660 
    661   // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
    662   // pointer grab when our NativeWidget is of type Menu. However, things work
    663   // without it. Clicking inside a chrome window causes a release capture, and
    664   // clicking outside causes an activation change. Since previous attempts at
    665   // using XPointerGrab() to implement this have locked my X server, I'm going
    666   // to skip this for now.
    667 }
    668 
    669 void DesktopRootWindowHostX11::ReleaseCapture() {
    670   if (g_current_capture)
    671     g_current_capture->OnCaptureReleased();
    672 }
    673 
    674 void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
    675   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
    676 }
    677 
    678 bool DesktopRootWindowHostX11::QueryMouseLocation(
    679     gfx::Point* location_return) {
    680   aura::client::CursorClient* cursor_client =
    681       aura::client::GetCursorClient(GetRootWindow());
    682   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
    683     *location_return = gfx::Point(0, 0);
    684     return false;
    685   }
    686 
    687   ::Window root_return, child_return;
    688   int root_x_return, root_y_return, win_x_return, win_y_return;
    689   unsigned int mask_return;
    690   XQueryPointer(xdisplay_,
    691                 xwindow_,
    692                 &root_return,
    693                 &child_return,
    694                 &root_x_return, &root_y_return,
    695                 &win_x_return, &win_y_return,
    696                 &mask_return);
    697   *location_return = gfx::Point(
    698       std::max(0, std::min(bounds_.width(), win_x_return)),
    699       std::max(0, std::min(bounds_.height(), win_y_return)));
    700   return (win_x_return >= 0 && win_x_return < bounds_.width() &&
    701           win_y_return >= 0 && win_y_return < bounds_.height());
    702 }
    703 
    704 bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
    705   NOTIMPLEMENTED();
    706   return false;
    707 }
    708 
    709 void DesktopRootWindowHostX11::UnConfineCursor() {
    710   NOTIMPLEMENTED();
    711 }
    712 
    713 void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
    714   // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
    715   // the same tap-to-click disabling here that chromeos does.
    716 }
    717 
    718 void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
    719   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
    720                bounds_.x() + location.x(), bounds_.y() + location.y());
    721 }
    722 
    723 void DesktopRootWindowHostX11::SetFocusWhenShown(bool focus_when_shown) {
    724   static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
    725   focus_when_shown_ = focus_when_shown;
    726   if (IsWindowManagerPresent() && !focus_when_shown_) {
    727     ui::SetIntProperty(xwindow_,
    728                        k_NET_WM_USER_TIME,
    729                        k_NET_WM_USER_TIME,
    730                        0);
    731   }
    732 }
    733 
    734 bool DesktopRootWindowHostX11::CopyAreaToSkCanvas(
    735     const gfx::Rect& source_bounds,
    736     const gfx::Point& dest_offset,
    737     SkCanvas* canvas) {
    738   NOTIMPLEMENTED();
    739   return false;
    740 }
    741 
    742 void DesktopRootWindowHostX11::PostNativeEvent(
    743     const base::NativeEvent& native_event) {
    744   DCHECK(xwindow_);
    745   DCHECK(xdisplay_);
    746   XEvent xevent = *native_event;
    747   xevent.xany.display = xdisplay_;
    748   xevent.xany.window = xwindow_;
    749 
    750   switch (xevent.type) {
    751     case EnterNotify:
    752     case LeaveNotify:
    753     case MotionNotify:
    754     case KeyPress:
    755     case KeyRelease:
    756     case ButtonPress:
    757     case ButtonRelease: {
    758       // The fields used below are in the same place for all of events
    759       // above. Using xmotion from XEvent's unions to avoid repeating
    760       // the code.
    761       xevent.xmotion.root = x_root_window_;
    762       xevent.xmotion.time = CurrentTime;
    763 
    764       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
    765       root_window_->ConvertPointToNativeScreen(&point);
    766       xevent.xmotion.x_root = point.x();
    767       xevent.xmotion.y_root = point.y();
    768     }
    769     default:
    770       break;
    771   }
    772   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
    773 }
    774 
    775 void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
    776     float device_scale_factor) {
    777 }
    778 
    779 void DesktopRootWindowHostX11::PrepareForShutdown() {
    780 }
    781 
    782 ////////////////////////////////////////////////////////////////////////////////
    783 // DesktopRootWindowHostX11, private:
    784 
    785 void DesktopRootWindowHostX11::InitX11Window(
    786     const Widget::InitParams& params) {
    787   unsigned long attribute_mask = CWBackPixmap;
    788   XSetWindowAttributes swa;
    789   memset(&swa, 0, sizeof(swa));
    790   swa.background_pixmap = None;
    791 
    792   ::Atom window_type;
    793   switch (params.type) {
    794     case Widget::InitParams::TYPE_MENU:
    795       swa.override_redirect = True;
    796       attribute_mask |= CWOverrideRedirect;
    797       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
    798       break;
    799     case Widget::InitParams::TYPE_TOOLTIP:
    800       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
    801       break;
    802     default:
    803       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
    804       break;
    805   }
    806 
    807   xwindow_ = XCreateWindow(
    808       xdisplay_, x_root_window_,
    809       params.bounds.x(), params.bounds.y(),
    810       params.bounds.width(), params.bounds.height(),
    811       0,               // border width
    812       CopyFromParent,  // depth
    813       InputOutput,
    814       CopyFromParent,  // visual
    815       attribute_mask,
    816       &swa);
    817   base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);
    818 
    819   // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
    820 
    821   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
    822                     KeyPressMask | KeyReleaseMask |
    823                     EnterWindowMask | LeaveWindowMask |
    824                     ExposureMask | VisibilityChangeMask |
    825                     StructureNotifyMask | PropertyChangeMask |
    826                     PointerMotionMask;
    827   XSelectInput(xdisplay_, xwindow_, event_mask);
    828   XFlush(xdisplay_);
    829 
    830   if (base::MessagePumpForUI::HasXInput2())
    831     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
    832 
    833   // TODO(erg): We currently only request window deletion events. We also
    834   // should listen for activation events and anything else that GTK+ listens
    835   // for, and do something useful.
    836   ::Atom protocols[2];
    837   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
    838   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
    839   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
    840 
    841   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
    842   // the desktop environment.
    843   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
    844 
    845   // Likewise, the X server needs to know this window's pid so it knows which
    846   // program to kill if the window hangs.
    847   pid_t pid = getpid();
    848   XChangeProperty(xdisplay_,
    849                   xwindow_,
    850                   atom_cache_.GetAtom("_NET_WM_PID"),
    851                   XA_CARDINAL,
    852                   32,
    853                   PropModeReplace,
    854                   reinterpret_cast<unsigned char*>(&pid), 1);
    855 
    856   XChangeProperty(xdisplay_,
    857                   xwindow_,
    858                   atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
    859                   XA_ATOM,
    860                   32,
    861                   PropModeReplace,
    862                   reinterpret_cast<unsigned char*>(&window_type), 1);
    863 
    864   // Remove popup windows from taskbar.
    865   if (params.type == Widget::InitParams::TYPE_POPUP ||
    866       params.type == Widget::InitParams::TYPE_BUBBLE) {
    867     Atom atom = atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR");
    868 
    869     // Setting _NET_WM_STATE by sending a message to the root_window (with
    870     // SetWMSpecState) has no effect here since the window has not yet been
    871     // mapped. So we manually change the state.
    872     XChangeProperty (xdisplay_,
    873                      xwindow_,
    874                      atom_cache_.GetAtom("_NET_WM_STATE"),
    875                      XA_ATOM,
    876                      32,
    877                      PropModeAppend,
    878                      reinterpret_cast<unsigned char*>(&atom), 1);
    879   }
    880 }
    881 
    882 // TODO(erg): This method should basically be everything I need form
    883 // RootWindowHostX11::RootWindowHostX11().
    884 aura::RootWindow* DesktopRootWindowHostX11::InitRootWindow(
    885     const Widget::InitParams& params) {
    886   bounds_ = params.bounds;
    887 
    888   aura::RootWindow::CreateParams rw_params(bounds_);
    889   rw_params.host = this;
    890   root_window_ = new aura::RootWindow(rw_params);
    891   root_window_->Init();
    892   root_window_->AddChild(content_window_);
    893   root_window_->SetLayoutManager(new DesktopLayoutManager(root_window_));
    894   root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
    895   root_window_->SetProperty(kHostForRootWindow, this);
    896   root_window_host_delegate_ = root_window_;
    897 
    898   // If we're given a parent, we need to mark ourselves as transient to another
    899   // window. Otherwise activation gets screwy.
    900   gfx::NativeView parent = params.parent;
    901   if (!params.child && params.parent)
    902     parent->AddTransientChild(content_window_);
    903 
    904   native_widget_delegate_->OnNativeWidgetCreated(true);
    905 
    906   capture_client_.reset(new views::DesktopCaptureClient(root_window_));
    907   aura::client::SetCaptureClient(root_window_, capture_client_.get());
    908 
    909   // Ensure that the X11DesktopHandler exists so that it dispatches activation
    910   // messages to us.
    911   X11DesktopHandler::get();
    912 
    913   if (corewm::UseFocusControllerOnDesktop()) {
    914     corewm::FocusController* focus_controller =
    915         new corewm::FocusController(new DesktopFocusRules);
    916     focus_client_.reset(focus_controller);
    917     aura::client::SetFocusClient(root_window_, focus_controller);
    918     aura::client::SetActivationClient(root_window_, focus_controller);
    919     root_window_->AddPreTargetHandler(focus_controller);
    920   } else {
    921     focus_client_.reset(new aura::FocusManager);
    922     aura::client::SetFocusClient(root_window_, focus_client_.get());
    923     activation_client_.reset(new DesktopActivationClient(root_window_));
    924   }
    925 
    926   dispatcher_client_.reset(new DesktopDispatcherClient);
    927   aura::client::SetDispatcherClient(root_window_,
    928                                     dispatcher_client_.get());
    929 
    930   views::DesktopNativeCursorManager* desktop_native_cursor_manager =
    931       new views::DesktopNativeCursorManager(
    932           root_window_,
    933           scoped_ptr<DesktopCursorLoaderUpdater>(
    934               new DesktopCursorLoaderUpdaterAuraX11));
    935   cursor_client_.reset(
    936       new views::corewm::CursorManager(
    937           scoped_ptr<corewm::NativeCursorManager>(
    938               desktop_native_cursor_manager)));
    939   aura::client::SetCursorClient(root_window_,
    940                                 cursor_client_.get());
    941 
    942   position_client_.reset(new DesktopScreenPositionClient);
    943   aura::client::SetScreenPositionClient(root_window_,
    944                                         position_client_.get());
    945 
    946   desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_);
    947 
    948   drag_drop_client_.reset(new DesktopDragDropClientAuraX11(
    949       root_window_, desktop_native_cursor_manager, xdisplay_, xwindow_));
    950   aura::client::SetDragDropClient(root_window_, drag_drop_client_.get());
    951 
    952   // TODO(erg): Unify this code once the other consumer goes away.
    953   x11_window_event_filter_.reset(
    954       new X11WindowEventFilter(root_window_, activation_client_.get()));
    955   x11_window_event_filter_->SetUseHostWindowBorders(false);
    956   desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
    957       x11_window_event_filter_.get());
    958 
    959   x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
    960   aura::client::SetWindowMoveClient(root_window_,
    961                                     x11_window_move_client_.get());
    962 
    963   focus_client_->FocusWindow(content_window_);
    964   return root_window_;
    965 }
    966 
    967 bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
    968   // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
    969   // of WM_Sn selections (where n is a screen number).
    970   return XGetSelectionOwner(
    971       xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
    972 }
    973 
    974 void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
    975                                                 ::Atom state1,
    976                                                 ::Atom state2) {
    977   XEvent xclient;
    978   memset(&xclient, 0, sizeof(xclient));
    979   xclient.type = ClientMessage;
    980   xclient.xclient.window = xwindow_;
    981   xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
    982   xclient.xclient.format = 32;
    983   xclient.xclient.data.l[0] =
    984       enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
    985   xclient.xclient.data.l[1] = state1;
    986   xclient.xclient.data.l[2] = state2;
    987   xclient.xclient.data.l[3] = 1;
    988   xclient.xclient.data.l[4] = 0;
    989 
    990   XSendEvent(xdisplay_, x_root_window_, False,
    991              SubstructureRedirectMask | SubstructureNotifyMask,
    992              &xclient);
    993 }
    994 
    995 bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
    996   return window_properties_.find(atom_cache_.GetAtom(property)) !=
    997       window_properties_.end();
    998 }
    999 
   1000 void DesktopRootWindowHostX11::OnCaptureReleased() {
   1001   native_widget_delegate_->OnMouseCaptureLost();
   1002   g_current_capture = NULL;
   1003 }
   1004 
   1005 void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
   1006   if (!g_current_capture || g_current_capture == this) {
   1007     root_window_host_delegate_->OnHostMouseEvent(event);
   1008   } else {
   1009     // Another DesktopRootWindowHostX11 has installed itself as
   1010     // capture. Translate the event's location and dispatch to the other.
   1011     event->ConvertLocationToTarget(root_window_,
   1012                                    g_current_capture->root_window_);
   1013     g_current_capture->root_window_host_delegate_->OnHostMouseEvent(event);
   1014   }
   1015 }
   1016 
   1017 std::list<XID>& DesktopRootWindowHostX11::open_windows() {
   1018   if (!open_windows_)
   1019     open_windows_ = new std::list<XID>();
   1020   return *open_windows_;
   1021 }
   1022 
   1023 ////////////////////////////////////////////////////////////////////////////////
   1024 // DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
   1025 
   1026 bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
   1027   XEvent* xev = event;
   1028 
   1029   // May want to factor CheckXEventForConsistency(xev); into a common location
   1030   // since it is called here.
   1031   switch (xev->type) {
   1032     case EnterNotify:
   1033     case LeaveNotify: {
   1034       ui::MouseEvent mouse_event(xev);
   1035       DispatchMouseEvent(&mouse_event);
   1036       break;
   1037     }
   1038     case Expose: {
   1039       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
   1040                             xev->xexpose.width, xev->xexpose.height);
   1041       root_window_host_delegate_->OnHostPaint(damage_rect);
   1042       break;
   1043     }
   1044     case KeyPress: {
   1045       ui::KeyEvent keydown_event(xev, false);
   1046       root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
   1047       break;
   1048     }
   1049     case KeyRelease: {
   1050       ui::KeyEvent keyup_event(xev, false);
   1051       root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
   1052       break;
   1053     }
   1054     case ButtonPress: {
   1055       if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
   1056           static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
   1057         aura::client::UserActionClient* gesture_client =
   1058             aura::client::GetUserActionClient(root_window_);
   1059         if (gesture_client) {
   1060           gesture_client->OnUserAction(
   1061               static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
   1062               aura::client::UserActionClient::BACK :
   1063               aura::client::UserActionClient::FORWARD);
   1064         }
   1065         break;
   1066       }
   1067     }  // fallthrough
   1068     case ButtonRelease: {
   1069       ui::MouseEvent mouseev(xev);
   1070       DispatchMouseEvent(&mouseev);
   1071       break;
   1072     }
   1073     case FocusOut:
   1074       if (xev->xfocus.mode != NotifyGrab) {
   1075         ReleaseCapture();
   1076         root_window_host_delegate_->OnHostLostWindowCapture();
   1077       } else {
   1078         root_window_host_delegate_->OnHostLostMouseGrab();
   1079       }
   1080       break;
   1081     case ConfigureNotify: {
   1082       DCHECK_EQ(xwindow_, xev->xconfigure.window);
   1083       DCHECK_EQ(xwindow_, xev->xconfigure.event);
   1084       // It's possible that the X window may be resized by some other means than
   1085       // from within aura (e.g. the X window manager can change the size). Make
   1086       // sure the root window size is maintained properly.
   1087       int translated_x = xev->xconfigure.x;
   1088       int translated_y = xev->xconfigure.y;
   1089       if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
   1090         Window unused;
   1091         XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
   1092             0, 0, &translated_x, &translated_y, &unused);
   1093       }
   1094       gfx::Rect bounds(translated_x, translated_y,
   1095                        xev->xconfigure.width, xev->xconfigure.height);
   1096       bool size_changed = bounds_.size() != bounds.size();
   1097       bool origin_changed = bounds_.origin() != bounds.origin();
   1098       previous_bounds_ = bounds_;
   1099       bounds_ = bounds;
   1100       if (size_changed)
   1101         root_window_host_delegate_->OnHostResized(bounds.size());
   1102       if (origin_changed)
   1103         root_window_host_delegate_->OnHostMoved(bounds_.origin());
   1104       break;
   1105     }
   1106     case GenericEvent: {
   1107       ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
   1108       if (!factory->ShouldProcessXI2Event(xev))
   1109         break;
   1110 
   1111       ui::EventType type = ui::EventTypeFromNative(xev);
   1112       XEvent last_event;
   1113       int num_coalesced = 0;
   1114 
   1115       switch (type) {
   1116         // case ui::ET_TOUCH_MOVED:
   1117         //   num_coalesced = CoalescePendingMotionEvents(xev, &last_event);
   1118         //   if (num_coalesced > 0)
   1119         //     xev = &last_event;
   1120         //   // fallthrough
   1121         // case ui::ET_TOUCH_PRESSED:
   1122         // case ui::ET_TOUCH_RELEASED: {
   1123         //   ui::TouchEvent touchev(xev);
   1124         //   root_window_host_delegate_->OnHostTouchEvent(&touchev);
   1125         //   break;
   1126         // }
   1127         case ui::ET_MOUSE_MOVED:
   1128         case ui::ET_MOUSE_DRAGGED:
   1129         case ui::ET_MOUSE_PRESSED:
   1130         case ui::ET_MOUSE_RELEASED:
   1131         case ui::ET_MOUSE_ENTERED:
   1132         case ui::ET_MOUSE_EXITED: {
   1133           if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
   1134             // If this is a motion event, we want to coalesce all pending motion
   1135             // events that are at the top of the queue.
   1136             num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
   1137             if (num_coalesced > 0)
   1138               xev = &last_event;
   1139           } else if (type == ui::ET_MOUSE_PRESSED) {
   1140             XIDeviceEvent* xievent =
   1141                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
   1142             int button = xievent->detail;
   1143             if (button == kBackMouseButton || button == kForwardMouseButton) {
   1144               aura::client::UserActionClient* gesture_client =
   1145                   aura::client::GetUserActionClient(
   1146                       root_window_host_delegate_->AsRootWindow());
   1147               if (gesture_client) {
   1148                 bool reverse_direction =
   1149                     ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
   1150                 gesture_client->OnUserAction(
   1151                     (button == kBackMouseButton && !reverse_direction) ||
   1152                     (button == kForwardMouseButton && reverse_direction) ?
   1153                     aura::client::UserActionClient::BACK :
   1154                     aura::client::UserActionClient::FORWARD);
   1155               }
   1156               break;
   1157             }
   1158           } else if (type == ui::ET_MOUSE_RELEASED) {
   1159             XIDeviceEvent* xievent =
   1160                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
   1161             int button = xievent->detail;
   1162             if (button == kBackMouseButton || button == kForwardMouseButton) {
   1163               // We've already passed the back/forward mouse down to the user
   1164               // action client; we want to swallow the corresponding release.
   1165               break;
   1166             }
   1167           }
   1168           ui::MouseEvent mouseev(xev);
   1169           DispatchMouseEvent(&mouseev);
   1170           break;
   1171         }
   1172         case ui::ET_MOUSEWHEEL: {
   1173           ui::MouseWheelEvent mouseev(xev);
   1174           DispatchMouseEvent(&mouseev);
   1175           break;
   1176         }
   1177         case ui::ET_SCROLL_FLING_START:
   1178         case ui::ET_SCROLL_FLING_CANCEL:
   1179         case ui::ET_SCROLL: {
   1180           ui::ScrollEvent scrollev(xev);
   1181           root_window_host_delegate_->OnHostScrollEvent(&scrollev);
   1182           break;
   1183         }
   1184         case ui::ET_UNKNOWN:
   1185           break;
   1186         default:
   1187           NOTREACHED();
   1188       }
   1189 
   1190       // If we coalesced an event we need to free its cookie.
   1191       if (num_coalesced > 0)
   1192         XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
   1193       break;
   1194     }
   1195     case MapNotify: {
   1196       // If there's no window manager running, we need to assign the X input
   1197       // focus to our host window.
   1198       if (!IsWindowManagerPresent() && focus_when_shown_)
   1199         XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
   1200 
   1201       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
   1202                         observer_list_,
   1203                         OnWindowMapped(xwindow_));
   1204       break;
   1205     }
   1206     case UnmapNotify: {
   1207       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
   1208                         observer_list_,
   1209                         OnWindowUnmapped(xwindow_));
   1210       break;
   1211     }
   1212     case ClientMessage: {
   1213       Atom message_type = xev->xclient.message_type;
   1214       if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
   1215         Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
   1216         if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
   1217           // We have received a close message from the window manager.
   1218           root_window_->OnRootWindowHostCloseRequested();
   1219         } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
   1220           XEvent reply_event = *xev;
   1221           reply_event.xclient.window = x_root_window_;
   1222 
   1223           XSendEvent(xdisplay_,
   1224                      reply_event.xclient.window,
   1225                      False,
   1226                      SubstructureRedirectMask | SubstructureNotifyMask,
   1227                      &reply_event);
   1228         }
   1229       } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
   1230         drag_drop_client_->OnXdndEnter(xev->xclient);
   1231       } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
   1232         drag_drop_client_->OnXdndLeave(xev->xclient);
   1233       } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
   1234         drag_drop_client_->OnXdndPosition(xev->xclient);
   1235       } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
   1236         drag_drop_client_->OnXdndStatus(xev->xclient);
   1237       } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
   1238         drag_drop_client_->OnXdndFinished(xev->xclient);
   1239       } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
   1240         drag_drop_client_->OnXdndDrop(xev->xclient);
   1241       }
   1242       break;
   1243     }
   1244     case MappingNotify: {
   1245       switch (xev->xmapping.request) {
   1246         case MappingModifier:
   1247         case MappingKeyboard:
   1248           XRefreshKeyboardMapping(&xev->xmapping);
   1249           root_window_->OnKeyboardMappingChanged();
   1250           break;
   1251         case MappingPointer:
   1252           ui::UpdateButtonMap();
   1253           break;
   1254         default:
   1255           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
   1256           break;
   1257       }
   1258       break;
   1259     }
   1260     case MotionNotify: {
   1261       // Discard all but the most recent motion event that targets the same
   1262       // window with unchanged state.
   1263       XEvent last_event;
   1264       while (XPending(xev->xany.display)) {
   1265         XEvent next_event;
   1266         XPeekEvent(xev->xany.display, &next_event);
   1267         if (next_event.type == MotionNotify &&
   1268             next_event.xmotion.window == xev->xmotion.window &&
   1269             next_event.xmotion.subwindow == xev->xmotion.subwindow &&
   1270             next_event.xmotion.state == xev->xmotion.state) {
   1271           XNextEvent(xev->xany.display, &last_event);
   1272           xev = &last_event;
   1273         } else {
   1274           break;
   1275         }
   1276       }
   1277 
   1278       ui::MouseEvent mouseev(xev);
   1279       DispatchMouseEvent(&mouseev);
   1280       break;
   1281     }
   1282     case PropertyNotify: {
   1283       // Get our new window property state if the WM has told us its changed.
   1284       ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
   1285 
   1286       std::vector< ::Atom> atom_list;
   1287       if (xev->xproperty.atom == state &&
   1288           ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
   1289         window_properties_.clear();
   1290         std::copy(atom_list.begin(), atom_list.end(),
   1291                   inserter(window_properties_, window_properties_.begin()));
   1292 
   1293         if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
   1294           // If we have restored bounds, but WM_STATE no longer claims to be
   1295           // maximized, we should clear our restored bounds.
   1296           restored_bounds_ = gfx::Rect();
   1297         } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
   1298           // The request that we become maximized originated from a different
   1299           // process. |bounds_| already contains our maximized bounds. Do a
   1300           // best effort attempt to get restored bounds by setting it to our
   1301           // previously set bounds (and if we get this wrong, we aren't any
   1302           // worse off since we'd otherwise be returning our maximized bounds).
   1303           restored_bounds_ = previous_bounds_;
   1304         }
   1305 
   1306         // Now that we have different window properties, we may need to
   1307         // relayout the window. (The windows code doesn't need this because
   1308         // their window change is synchronous.)
   1309         //
   1310         // TODO(erg): While this does work, there's a quick flash showing the
   1311         // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
   1312         // those parts of the UI because we receive the sizing event from the
   1313         // window manager before we receive the event that changes the
   1314         // fullscreen state. Unsure what to do about that.
   1315         Widget* widget = native_widget_delegate_->AsWidget();
   1316         NonClientView* non_client_view = widget->non_client_view();
   1317         // non_client_view may be NULL, especially during creation.
   1318         if (non_client_view) {
   1319           non_client_view->client_view()->InvalidateLayout();
   1320           non_client_view->InvalidateLayout();
   1321         }
   1322         widget->GetRootView()->Layout();
   1323       }
   1324       break;
   1325     }
   1326     case SelectionNotify: {
   1327       drag_drop_client_->OnSelectionNotify(xev->xselection);
   1328       break;
   1329     }
   1330   }
   1331   return true;
   1332 }
   1333 
   1334 ////////////////////////////////////////////////////////////////////////////////
   1335 // DesktopRootWindowHost, public:
   1336 
   1337 // static
   1338 DesktopRootWindowHost* DesktopRootWindowHost::Create(
   1339     internal::NativeWidgetDelegate* native_widget_delegate,
   1340     DesktopNativeWidgetAura* desktop_native_widget_aura,
   1341     const gfx::Rect& initial_bounds) {
   1342   return new DesktopRootWindowHostX11(native_widget_delegate,
   1343                                         desktop_native_widget_aura,
   1344                                         initial_bounds);
   1345 }
   1346 
   1347 // static
   1348 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
   1349   const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
   1350   if (linux_ui) {
   1351     ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
   1352     if (native_theme)
   1353       return native_theme;
   1354   }
   1355 
   1356   return ui::NativeTheme::instance();
   1357 }
   1358 
   1359 }  // namespace views
   1360