Home | History | Annotate | Download | only in automation
      1 // Copyright (c) 2011 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 "chrome/browser/automation/automation_provider.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/automation/automation_browser_tracker.h"
     11 #include "chrome/browser/automation/automation_window_tracker.h"
     12 #include "chrome/browser/automation/ui_controls.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
     15 #include "chrome/browser/ui/gtk/gtk_util.h"
     16 #include "chrome/browser/ui/gtk/view_id_util.h"
     17 #include "chrome/common/automation_messages.h"
     18 #include "ui/gfx/point.h"
     19 #include "ui/gfx/rect.h"
     20 
     21 void AutomationProvider::PrintAsync(int tab_handle) {
     22   NOTIMPLEMENTED();
     23 }
     24 
     25 // This task sends a WindowDragResponse message with the appropriate
     26 // routing ID to the automation proxy.  This is implemented as a task so that
     27 // we know that the mouse events (and any tasks that they spawn on the message
     28 // loop) have been processed by the time this is sent.
     29 class WindowDragResponseTask : public Task {
     30  public:
     31   WindowDragResponseTask(AutomationProvider* provider,
     32                          IPC::Message* reply_message)
     33       : provider_(provider),
     34         reply_message_(reply_message) {
     35     DCHECK(provider_);
     36     DCHECK(reply_message_);
     37   }
     38 
     39   virtual ~WindowDragResponseTask() {
     40   }
     41 
     42   virtual void Run() {
     43     AutomationMsg_WindowDrag::WriteReplyParams(reply_message_, true);
     44     provider_->Send(reply_message_);
     45   }
     46 
     47  private:
     48   AutomationProvider* provider_;
     49   IPC::Message* reply_message_;
     50 
     51   DISALLOW_COPY_AND_ASSIGN(WindowDragResponseTask);
     52 };
     53 
     54 // A task that just runs a SendMouseEvent and performs another task when done.
     55 class MouseEventTask : public Task {
     56  public:
     57   MouseEventTask(Task* next_task, ui_controls::MouseButtonState state)
     58       : next_task_(next_task),
     59         state_(state) {}
     60 
     61   virtual ~MouseEventTask() {
     62   }
     63 
     64   virtual void Run() {
     65     ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, state_,
     66                                                next_task_);
     67   }
     68 
     69  private:
     70   // The task to execute when we are done.
     71   Task* next_task_;
     72 
     73   // Mouse press or mouse release.
     74   ui_controls::MouseButtonState state_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(MouseEventTask);
     77 };
     78 
     79 // A task that just runs a SendMouseMove and performs another task when done.
     80 class MouseMoveTask : public Task {
     81  public:
     82   MouseMoveTask(Task* next_task, int absolute_x, int absolute_y)
     83       : next_task_(next_task),
     84         x_(absolute_x),
     85         y_(absolute_y) {
     86   }
     87 
     88   virtual ~MouseMoveTask() {
     89   }
     90 
     91   virtual void Run() {
     92     ui_controls::SendMouseMoveNotifyWhenDone(x_, y_, next_task_);
     93   }
     94 
     95  private:
     96   // The task to execute when we are done.
     97   Task* next_task_;
     98 
     99   // Coordinates of the press.
    100   int x_;
    101   int y_;
    102 
    103   DISALLOW_COPY_AND_ASSIGN(MouseMoveTask);
    104 };
    105 
    106 void AutomationProvider::WindowSimulateDrag(
    107     int handle,
    108     const std::vector<gfx::Point>& drag_path,
    109     int flags,
    110     bool press_escape_en_route,
    111     IPC::Message* reply_message) {
    112   // TODO(estade): don't ignore |flags| or |escape_en_route|.
    113   gfx::NativeWindow window =
    114       browser_tracker_->GetResource(handle)->window()->GetNativeHandle();
    115   if (window && (drag_path.size() > 1)) {
    116     int x, y;
    117     gdk_window_get_position(GTK_WIDGET(window)->window, &x, &y);
    118 
    119     // Create a nested stack of tasks to run.
    120     Task* next_task = new WindowDragResponseTask(this, reply_message);
    121     next_task = new MouseEventTask(next_task, ui_controls::UP);
    122     next_task = new MouseEventTask(next_task, ui_controls::UP);
    123     for (size_t i = drag_path.size() - 1; i > 0; --i) {
    124       // Smooth out the mouse movements by adding intermediate points. This
    125       // better simulates a real user drag.
    126       int dest_x = drag_path[i].x() + x;
    127       int dest_y = drag_path[i].y() + y;
    128       int half_step_x = (dest_x + drag_path[i - 1].x() + x) / 2;
    129       int half_step_y = (dest_y + drag_path[i - 1].y() + y) / 2;
    130 
    131       next_task = new MouseMoveTask(next_task, dest_x, dest_y);
    132       next_task = new MouseMoveTask(next_task, half_step_x, half_step_y);
    133     }
    134     next_task = new MouseEventTask(next_task, ui_controls::DOWN);
    135 
    136     ui_controls::SendMouseMoveNotifyWhenDone(x + drag_path[0].x(),
    137                                              y + drag_path[0].y(),
    138                                              next_task);
    139   } else {
    140     AutomationMsg_WindowDrag::WriteReplyParams(reply_message, false);
    141     Send(reply_message);
    142   }
    143 }
    144