190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <X11/Xlib.h>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/bind.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/message_loop/message_loop.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/run_loop.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/aura/client/capture_client.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/aura/env.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/window.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/aura/window_tree_host.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/x/x11_util.h"
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/events/event_utils.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/keycodes/keyboard_code_conversion_x.h"
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/events/platform/scoped_event_dispatcher.h"
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/platform/x11/x11_event_source.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace views {
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : delegate_(delegate),
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      in_move_loop_(false),
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      initial_cursor_(ui::kCursorNull),
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      should_reset_mouse_flags_(false),
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      grab_input_window_(None),
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      grabbed_pointer_(false),
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      canceled_(false),
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      weak_factory_(this) {
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  last_xmotion_.type = LASTEvent;
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid X11WholeScreenMoveLoop::DispatchMouseMovement() {
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!weak_factory_.HasWeakPtrs())
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  weak_factory_.InvalidateWeakPtrs();
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_EQ(MotionNotify, last_xmotion_.type);
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  delegate_->OnMouseMovement(&last_xmotion_);
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  last_xmotion_.type = LASTEvent;
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch////////////////////////////////////////////////////////////////////////////////
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation:
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return in_move_loop_;
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochuint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This method processes all events while the move loop is active.
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!in_move_loop_)
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return ui::POST_DISPATCH_PERFORM_DEFAULT;
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  XEvent* xev = event;
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (xev->type) {
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case MotionNotify: {
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      last_xmotion_ = xev->xmotion;
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (!weak_factory_.HasWeakPtrs()) {
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Post a task to dispatch mouse movement event when control returns to
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // the message loop. This allows smoother dragging since the events are
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // dispatched without waiting for the drag widget updates.
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::MessageLoopForUI::current()->PostTask(
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            FROM_HERE,
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement,
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       weak_factory_.GetWeakPtr()));
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return ui::POST_DISPATCH_NONE;
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case ButtonRelease: {
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (xev->xbutton.button == Button1) {
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // Assume that drags are being done with the left mouse button. Only
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // break the drag if the left mouse button was released.
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        DispatchMouseMovement();
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        delegate_->OnMouseReleased();
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (!grabbed_pointer_) {
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // If the source widget had capture prior to the move loop starting,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // it may be relying on views::Widget getting the mouse release and
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // releasing capture in Widget::OnMouseEvent().
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          return ui::POST_DISPATCH_PERFORM_DEFAULT;
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return ui::POST_DISPATCH_NONE;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case KeyPress: {
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) {
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        canceled_ = true;
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        EndMoveLoop();
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        return ui::POST_DISPATCH_NONE;
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      }
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case GenericEvent: {
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ui::EventType type = ui::EventTypeFromNative(xev);
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      switch (type) {
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        case ui::ET_MOUSE_MOVED:
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        case ui::ET_MOUSE_DRAGGED:
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        case ui::ET_MOUSE_RELEASED: {
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          XEvent xevent = {0};
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          if (type == ui::ET_MOUSE_RELEASED) {
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            xevent.type = ButtonRelease;
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            xevent.xbutton.button = ui::EventButtonFromNative(xev);
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          } else {
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            xevent.type = MotionNotify;
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          }
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xany.display = xev->xgeneric.display;
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xany.window = grab_input_window_;
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          // The fields used below are in the same place for all of events
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          // above. Using xmotion from XEvent's unions to avoid repeating
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          // the code.
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xmotion.root = DefaultRootWindow(xev->xgeneric.display);
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xmotion.time = ui::EventTimeFromNative(xev).InMilliseconds();
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          gfx::Point point(ui::EventSystemLocationFromNative(xev));
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xmotion.x_root = point.x();
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          xevent.xmotion.y_root = point.y();
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          return DispatchEvent(&xevent);
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        }
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        default:
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          break;
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return ui::POST_DISPATCH_PERFORM_DEFAULT;
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                         gfx::NativeCursor cursor) {
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!in_move_loop_);  // Can only handle one nested loop at a time.
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Query the mouse cursor prior to the move loop starting so that it can be
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // restored when the move loop finishes.
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  initial_cursor_ = source->GetHost()->last_cursor();
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay());
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Only grab mouse capture of |grab_input_window_| if |source| does not have
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // capture.
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // - The caller may intend to transfer capture to a different aura::Window
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //   when the move loop ends and not release capture.
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // - Releasing capture and X window destruction are both asynchronous. We drop
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //   events targeted at |grab_input_window_| in the time between the move
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //   loop ends and |grab_input_window_| loses capture.
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  grabbed_pointer_ = false;
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!source->HasCapture()) {
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    aura::client::CaptureClient* capture_client =
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        aura::client::GetCaptureClient(source->GetRootWindow());
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CHECK(capture_client->GetGlobalCaptureWindow() == NULL);
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    grabbed_pointer_ = GrabPointer(cursor);
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!grabbed_pointer_) {
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return false;
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!GrabKeyboard()) {
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      nested_dispatcher_.Pass();
1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  nested_dispatcher_ =
1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this);
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We are handling a mouse drag outside of the aura::Window system. We must
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // manually make aura think that the mouse button is pressed so that we don't
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // draw extraneous tooltips.
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  aura::Env* env = aura::Env::GetInstance();
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!env->IsMouseButtonDown()) {
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    should_reset_mouse_flags_ = true;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  in_move_loop_ = true;
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  canceled_ = false;
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::RunLoop run_loop;
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  quit_closure_ = run_loop.QuitClosure();
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  run_loop.Run();
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  nested_dispatcher_ = old_dispatcher.Pass();
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return !canceled_;
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (in_move_loop_) {
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We cannot call GrabPointer() because we do not want to change the
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // "owner_events" property of the active pointer grab.
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    XChangeActivePointerGrab(
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        gfx::GetXDisplay(),
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        cursor.platform(),
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        CurrentTime);
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void X11WholeScreenMoveLoop::EndMoveLoop() {
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!in_move_loop_)
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Prevent DispatchMouseMovement from dispatching any posted motion event.
210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  weak_factory_.InvalidateWeakPtrs();
211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  last_xmotion_.type = LASTEvent;
212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // We undo our emulated mouse click from RunMoveLoop();
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (should_reset_mouse_flags_) {
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Env::GetInstance()->set_mouse_button_flags(0);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    should_reset_mouse_flags_ = false;
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // TODO(erg): Is this ungrab the cause of having to click to give input focus
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // on drawn out windows? Not ungrabbing here screws the X server until I kill
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the chrome process.
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Ungrab before we let go of the window.
22468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display = gfx::GetXDisplay();
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (grabbed_pointer_)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    XUngrabPointer(display, CurrentTime);
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UpdateCursor(initial_cursor_);
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  XUngrabKeyboard(display, CurrentTime);
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Restore the previous dispatcher.
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  nested_dispatcher_.reset();
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  delegate_->OnMoveLoopEnded();
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  XDestroyWindow(display, grab_input_window_);
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  grab_input_window_ = None;
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  in_move_loop_ = false;
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  quit_closure_.Run();
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
24368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display = gfx::GetXDisplay();
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  XGrabServer(display);
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Pass "owner_events" as false so that X sends all mouse events to
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |grab_input_window_|.
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int ret = XGrabPointer(
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      display,
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      grab_input_window_,
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      False,  // owner_events
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      GrabModeAsync,
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      GrabModeAsync,
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      None,
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      cursor.platform(),
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      CurrentTime);
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (ret != GrabSuccess) {
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DLOG(ERROR) << "Grabbing pointer for dragging failed: "
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                << ui::GetX11ErrorString(display, ret);
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  XUngrabServer(display);
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  XFlush(display);
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return ret == GrabSuccess;
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool X11WholeScreenMoveLoop::GrabKeyboard() {
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  XDisplay* display = gfx::GetXDisplay();
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int ret = XGrabKeyboard(display,
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          grab_input_window_,
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          False,
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          GrabModeAsync,
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          GrabModeAsync,
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          CurrentTime);
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (ret != GrabSuccess) {
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DLOG(ERROR) << "Grabbing keyboard for dragging failed: "
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                << ui::GetX11ErrorString(display, ret);
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  XSetWindowAttributes swa;
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(&swa, 0, sizeof(swa));
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   KeyPressMask | KeyReleaseMask | StructureNotifyMask;
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  swa.override_redirect = True;
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Window window = XCreateWindow(display,
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                DefaultRootWindow(display),
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                -100, -100, 10, 10,
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                0, CopyFromParent, InputOnly, CopyFromParent,
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                attribute_mask, &swa);
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  XMapRaised(display, window);
296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window);
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return window;
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace views
301