summaryrefslogtreecommitdiffstats
path: root/chrome/browser/automation/automation_provider_gtk.cc
blob: 223a22ae69e83fa4c2ebee44d820681bfdae616b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright (c) 2012 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 "chrome/browser/automation/automation_provider.h"

#include <gtk/gtk.h>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/view_id_util.h"
#include "chrome/common/automation_messages.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/ui_controls/ui_controls.h"

namespace {

// This function sends a WindowDragResponse message with the appropriate routing
// ID to the automation proxy.
void SendWindowDragResponse(AutomationProvider* provider,
                        IPC::Message* reply_message) {
  AutomationMsg_WindowDrag::WriteReplyParams(reply_message, true);
  provider->Send(reply_message);
}

}  // namespace

void AutomationProvider::PrintAsync(int tab_handle) {
  NOTIMPLEMENTED();
}

void AutomationProvider::WindowSimulateDrag(
    int handle,
    const std::vector<gfx::Point>& drag_path,
    int flags,
    bool press_escape_en_route,
    IPC::Message* reply_message) {
  // TODO(estade): don't ignore |flags| or |escape_en_route|.
  gfx::NativeWindow window =
      browser_tracker_->GetResource(handle)->window()->GetNativeWindow();
  if (window && (drag_path.size() > 1)) {
    int x, y;
    gdk_window_get_position(gtk_widget_get_window(GTK_WIDGET(window)), &x, &y);

    // Create a nested stack of tasks to run.
    base::Closure drag_response_cb = base::Bind(
        &SendWindowDragResponse, make_scoped_refptr(this), reply_message);
    base::Closure move_chain_cb = base::Bind(
        base::IgnoreResult(&ui_controls::SendMouseEventsNotifyWhenDone),
        ui_controls::LEFT, ui_controls::UP, drag_response_cb);
    move_chain_cb = base::Bind(
        base::IgnoreResult(&ui_controls::SendMouseEventsNotifyWhenDone),
        ui_controls::LEFT, ui_controls::UP, move_chain_cb);
    for (size_t i = drag_path.size() - 1; i > 0; --i) {
      // Smooth out the mouse movements by adding intermediate points. This
      // better simulates a real user drag.
      int dest_x = drag_path[i].x() + x;
      int dest_y = drag_path[i].y() + y;
      int half_step_x = (dest_x + drag_path[i - 1].x() + x) / 2;
      int half_step_y = (dest_y + drag_path[i - 1].y() + y) / 2;

      move_chain_cb = base::Bind(
          base::IgnoreResult(&ui_controls::SendMouseMoveNotifyWhenDone),
          dest_x, dest_y, move_chain_cb);
      move_chain_cb = base::Bind(
          base::IgnoreResult(&ui_controls::SendMouseMoveNotifyWhenDone),
          half_step_x, half_step_y, move_chain_cb);
    }
    move_chain_cb = base::Bind(
        base::IgnoreResult(&ui_controls::SendMouseEventsNotifyWhenDone),
        ui_controls::LEFT, ui_controls::DOWN, move_chain_cb);

    ui_controls::SendMouseMoveNotifyWhenDone(x + drag_path[0].x(),
                                          y + drag_path[0].y(),
                                          move_chain_cb);
  } else {
    AutomationMsg_WindowDrag::WriteReplyParams(reply_message, false);
    Send(reply_message);
  }
}