blob: 8b0338a8eb73d595bb049ec250c9b0ab91853691 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/client/plugin/pepper_mouse_locker.h"
#include "base/logging.h"
#include "remoting/client/plugin/empty_cursor_filter.h"
#include "remoting/proto/control.pb.h"
namespace remoting {
PepperMouseLocker::PepperMouseLocker(
pp::Instance* instance,
const base::Callback<void(bool)>& enable_mouse_deltas,
protocol::CursorShapeStub* cursor_stub)
: pp::MouseLock(instance),
enable_mouse_deltas_(enable_mouse_deltas),
cursor_stub_(cursor_stub),
cursor_shape_(new protocol::CursorShapeInfo),
callback_factory_(this),
has_focus_(false),
mouse_lock_state_(MouseLockOff) {
*cursor_shape_ = EmptyCursorShape();
}
PepperMouseLocker::~PepperMouseLocker() {}
void PepperMouseLocker::DidChangeFocus(bool has_focus) {
has_focus_ = has_focus;
if (has_focus_)
RequestMouseLock();
}
void PepperMouseLocker::SetCursorShape(
const protocol::CursorShapeInfo& cursor_shape) {
*cursor_shape_ = cursor_shape;
if (IsCursorShapeEmpty(*cursor_shape_)) {
RequestMouseLock();
} else {
CancelMouseLock();
}
}
void PepperMouseLocker::MouseLockLost() {
DCHECK(mouse_lock_state_ == MouseLockOn ||
mouse_lock_state_ == MouseLockCancelling);
OnMouseLockOff();
}
void PepperMouseLocker::OnMouseLocked(int error) {
DCHECK(mouse_lock_state_ == MouseLockRequestPending ||
mouse_lock_state_ == MouseLockCancelling);
bool should_cancel = (mouse_lock_state_ == MouseLockCancelling);
// See if the operation succeeded.
if (error == PP_OK) {
mouse_lock_state_ = MouseLockOn;
} else {
OnMouseLockOff();
}
// Cancel as needed.
if (should_cancel)
CancelMouseLock();
}
void PepperMouseLocker::OnMouseLockOff() {
mouse_lock_state_ = MouseLockOff;
cursor_stub_->SetCursorShape(*cursor_shape_);
}
void PepperMouseLocker::RequestMouseLock() {
// Request mouse lock only if the plugin is focused, the host-supplied cursor
// is empty and no callback is pending.
if (!has_focus_)
return;
if (!IsCursorShapeEmpty(*cursor_shape_))
return;
if (mouse_lock_state_ != MouseLockOff)
return;
pp::CompletionCallback callback =
callback_factory_.NewCallback(&PepperMouseLocker::OnMouseLocked);
int result = pp::MouseLock::LockMouse(callback);
if (result != PP_OK_COMPLETIONPENDING) {
LOG(ERROR) << "Unexpected MouseLock result:" << result;
return;
}
mouse_lock_state_ = MouseLockRequestPending;
// Hide cursor to avoid it becoming a black square (see crbug.com/285809).
cursor_stub_->SetCursorShape(EmptyCursorShape());
}
void PepperMouseLocker::CancelMouseLock() {
switch (mouse_lock_state_) {
case MouseLockOff:
OnMouseLockOff();
break;
case MouseLockCancelling:
break;
case MouseLockRequestPending:
// The mouse lock request is pending. Delay UnlockMouse() call until
// the callback is called.
mouse_lock_state_ = MouseLockCancelling;
break;
case MouseLockOn:
pp::MouseLock::UnlockMouse();
// Note that mouse-lock has been cancelled. We will continue to receive
// locked events until MouseLockLost() is called back.
mouse_lock_state_ = MouseLockCancelling;
break;
default:
NOTREACHED();
}
}
} // namespace remoting