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 "content/renderer/mouse_lock_dispatcher.h"
6
7#include "base/logging.h"
8#include "third_party/WebKit/public/web/WebInputEvent.h"
9
10namespace content {
11
12MouseLockDispatcher::MouseLockDispatcher() : mouse_locked_(false),
13                                             pending_lock_request_(false),
14                                             pending_unlock_request_(false),
15                                             unlocked_by_target_(false),
16                                             target_(NULL) {
17}
18
19MouseLockDispatcher::~MouseLockDispatcher() {
20}
21
22bool MouseLockDispatcher::LockMouse(LockTarget* target) {
23  if (MouseLockedOrPendingAction())
24    return false;
25
26  pending_lock_request_ = true;
27  target_ = target;
28
29  SendLockMouseRequest(unlocked_by_target_);
30  unlocked_by_target_ = false;
31  return true;
32}
33
34void MouseLockDispatcher::UnlockMouse(LockTarget* target) {
35  if (target && target == target_ && !pending_unlock_request_) {
36    pending_unlock_request_ = true;
37
38    // When a target application voluntarily unlocks the mouse we permit
39    // relocking the mouse silently and with no user gesture requirement.
40    // Check that the lock request is not currently pending and not yet
41    // accepted by the browser process before setting |unlocked_by_target_|.
42    if (!pending_lock_request_)
43      unlocked_by_target_ = true;
44
45    SendUnlockMouseRequest();
46  }
47}
48
49void MouseLockDispatcher::OnLockTargetDestroyed(LockTarget* target) {
50  if (target == target_) {
51    UnlockMouse(target);
52    target_ = NULL;
53  }
54}
55
56bool MouseLockDispatcher::IsMouseLockedTo(LockTarget* target) {
57  return mouse_locked_ && target_ == target;
58}
59
60bool MouseLockDispatcher::WillHandleMouseEvent(
61    const blink::WebMouseEvent& event) {
62  if (mouse_locked_ && target_)
63    return target_->HandleMouseLockedInputEvent(event);
64  return false;
65}
66
67void MouseLockDispatcher::OnLockMouseACK(bool succeeded) {
68  DCHECK(!mouse_locked_ && pending_lock_request_);
69
70  mouse_locked_ = succeeded;
71  pending_lock_request_ = false;
72  if (pending_unlock_request_ && !succeeded) {
73    // We have sent an unlock request after the lock request. However, since
74    // the lock request has failed, the unlock request will be ignored by the
75    // browser side and there won't be any response to it.
76    pending_unlock_request_ = false;
77  }
78
79  LockTarget* last_target = target_;
80  if (!succeeded)
81    target_ = NULL;
82
83  // Callbacks made after all state modification to prevent reentrant errors
84  // such as OnLockMouseACK() synchronously calling LockMouse().
85
86  if (last_target)
87    last_target->OnLockMouseACK(succeeded);
88}
89
90void MouseLockDispatcher::OnMouseLockLost() {
91  DCHECK(mouse_locked_ && !pending_lock_request_);
92
93  mouse_locked_ = false;
94  pending_unlock_request_ = false;
95
96  LockTarget* last_target = target_;
97  target_ = NULL;
98
99  // Callbacks made after all state modification to prevent reentrant errors
100  // such as OnMouseLockLost() synchronously calling LockMouse().
101
102  if (last_target)
103    last_target->OnMouseLockLost();
104}
105
106}  // namespace content
107