Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / views / test / ui_controls_factory_desktop_aurax11.cc
1 // Copyright 2013 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 <X11/keysym.h>
6 #include <X11/Xlib.h>
7
8 // X macro fail.
9 #if defined(RootWindow)
10 #undef RootWindow
11 #endif
12
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "ui/aura/client/screen_position_client.h"
16 #include "ui/aura/env.h"
17 #include "ui/aura/test/aura_test_utils.h"
18 #include "ui/aura/test/ui_controls_factory_aura.h"
19 #include "ui/aura/window_event_dispatcher.h"
20 #include "ui/base/test/ui_controls_aura.h"
21 #include "ui/base/x/x11_util.h"
22 #include "ui/compositor/dip_util.h"
23 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
24 #include "ui/events/test/platform_event_waiter.h"
25 #include "ui/gfx/x/x11_connection.h"
26 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
27
28 namespace views {
29 namespace test {
30 namespace {
31
32 using ui_controls::DOWN;
33 using ui_controls::LEFT;
34 using ui_controls::MIDDLE;
35 using ui_controls::MouseButton;
36 using ui_controls::RIGHT;
37 using ui_controls::UIControlsAura;
38 using ui_controls::UP;
39
40 // Mask of the buttons currently down.
41 unsigned button_down_mask = 0;
42
43 // Returns atom that indidates that the XEvent is marker event.
44 Atom MarkerEventAtom() {
45   return XInternAtom(gfx::GetXDisplay(), "marker_event", False);
46 }
47
48 // Returns true when the event is a marker event.
49 bool Matcher(const base::NativeEvent& event) {
50   return event->xany.type == ClientMessage &&
51       event->xclient.message_type == MarkerEventAtom();
52 }
53
54 class UIControlsDesktopX11 : public UIControlsAura {
55  public:
56   UIControlsDesktopX11()
57       : x_display_(gfx::GetXDisplay()),
58         x_root_window_(DefaultRootWindow(x_display_)),
59         x_window_(XCreateWindow(
60             x_display_, x_root_window_,
61             -100, -100, 10, 10,  // x, y, width, height
62             0,                   // border width
63             CopyFromParent,      // depth
64             InputOnly,
65             CopyFromParent,      // visual
66             0,
67             NULL)) {
68     XStoreName(x_display_, x_window_, "Chromium UIControlsDesktopX11 Window");
69   }
70
71   virtual ~UIControlsDesktopX11() {
72     XDestroyWindow(x_display_, x_window_);
73   }
74
75   virtual bool SendKeyPress(gfx::NativeWindow window,
76                             ui::KeyboardCode key,
77                             bool control,
78                             bool shift,
79                             bool alt,
80                             bool command) OVERRIDE {
81     DCHECK(!command);  // No command key on Aura
82     return SendKeyPressNotifyWhenDone(
83         window, key, control, shift, alt, command, base::Closure());
84   }
85
86   virtual bool SendKeyPressNotifyWhenDone(
87       gfx::NativeWindow window,
88       ui::KeyboardCode key,
89       bool control,
90       bool shift,
91       bool alt,
92       bool command,
93       const base::Closure& closure) OVERRIDE {
94     DCHECK(!command);  // No command key on Aura
95
96     aura::WindowTreeHost* host = window->GetHost();
97
98     XEvent xevent = {0};
99     xevent.xkey.type = KeyPress;
100     if (control) {
101       SetKeycodeAndSendThenMask(host, &xevent, XK_Control_L, ControlMask);
102     }
103     if (shift)
104       SetKeycodeAndSendThenMask(host, &xevent, XK_Shift_L, ShiftMask);
105     if (alt)
106       SetKeycodeAndSendThenMask(host, &xevent, XK_Alt_L, Mod1Mask);
107     xevent.xkey.keycode =
108         XKeysymToKeycode(x_display_,
109                          ui::XKeysymForWindowsKeyCode(key, shift));
110     host->PostNativeEvent(&xevent);
111
112     // Send key release events.
113     xevent.xkey.type = KeyRelease;
114     host->PostNativeEvent(&xevent);
115     if (alt)
116       UnmaskAndSetKeycodeThenSend(host, &xevent, Mod1Mask, XK_Alt_L);
117     if (shift)
118       UnmaskAndSetKeycodeThenSend(host, &xevent, ShiftMask, XK_Shift_L);
119     if (control) {
120       UnmaskAndSetKeycodeThenSend(host, &xevent, ControlMask, XK_Control_L);
121     }
122     DCHECK(!xevent.xkey.state);
123     RunClosureAfterAllPendingUIEvents(closure);
124     return true;
125   }
126
127   virtual bool SendMouseMove(long screen_x, long screen_y) OVERRIDE {
128     return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure());
129   }
130   virtual bool SendMouseMoveNotifyWhenDone(
131       long screen_x,
132       long screen_y,
133       const base::Closure& closure) OVERRIDE {
134     gfx::Point screen_location(screen_x, screen_y);
135     gfx::Point root_location = screen_location;
136     aura::Window* root_window = RootWindowForPoint(screen_location);
137
138     aura::client::ScreenPositionClient* screen_position_client =
139           aura::client::GetScreenPositionClient(root_window);
140     if (screen_position_client) {
141       screen_position_client->ConvertPointFromScreen(root_window,
142                                                      &root_location);
143     }
144
145     aura::WindowTreeHost* host = root_window->GetHost();
146     gfx::Point root_current_location =
147         aura::test::QueryLatestMousePositionRequestInHost(host);
148     host->ConvertPointFromHost(&root_current_location);
149
150     if (root_location != root_current_location && button_down_mask == 0) {
151       // Move the cursor because EnterNotify/LeaveNotify are generated with the
152       // current mouse position as a result of XGrabPointer()
153       root_window->MoveCursorTo(root_location);
154     } else {
155       XEvent xevent = {0};
156       XMotionEvent* xmotion = &xevent.xmotion;
157       xmotion->type = MotionNotify;
158       xmotion->x = root_location.x();
159       xmotion->y = root_location.y();
160       xmotion->state = button_down_mask;
161       xmotion->same_screen = True;
162       // RootWindow will take care of other necessary fields.
163       host->PostNativeEvent(&xevent);
164     }
165     RunClosureAfterAllPendingUIEvents(closure);
166     return true;
167   }
168   virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE {
169     return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
170   }
171   virtual bool SendMouseEventsNotifyWhenDone(
172       MouseButton type,
173       int state,
174       const base::Closure& closure) OVERRIDE {
175     XEvent xevent = {0};
176     XButtonEvent* xbutton = &xevent.xbutton;
177     gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
178     aura::Window* root_window = RootWindowForPoint(mouse_loc);
179     aura::client::ScreenPositionClient* screen_position_client =
180           aura::client::GetScreenPositionClient(root_window);
181     if (screen_position_client)
182       screen_position_client->ConvertPointFromScreen(root_window, &mouse_loc);
183     xbutton->x = mouse_loc.x();
184     xbutton->y = mouse_loc.y();
185     xbutton->same_screen = True;
186     switch (type) {
187       case LEFT:
188         xbutton->button = Button1;
189         xbutton->state = Button1Mask;
190         break;
191       case MIDDLE:
192         xbutton->button = Button2;
193         xbutton->state = Button2Mask;
194         break;
195       case RIGHT:
196         xbutton->button = Button3;
197         xbutton->state = Button3Mask;
198         break;
199     }
200     // RootWindow will take care of other necessary fields.
201     if (state & DOWN) {
202       xevent.xbutton.type = ButtonPress;
203       root_window->GetHost()->PostNativeEvent(&xevent);
204       button_down_mask |= xbutton->state;
205     }
206     if (state & UP) {
207       xevent.xbutton.type = ButtonRelease;
208       root_window->GetHost()->PostNativeEvent(&xevent);
209       button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state;
210     }
211     RunClosureAfterAllPendingUIEvents(closure);
212     return true;
213   }
214   virtual bool SendMouseClick(MouseButton type) OVERRIDE {
215     return SendMouseEvents(type, UP | DOWN);
216   }
217   virtual void RunClosureAfterAllPendingUIEvents(
218       const base::Closure& closure) OVERRIDE {
219     if (closure.is_null())
220       return;
221     static XEvent* marker_event = NULL;
222     if (!marker_event) {
223       marker_event = new XEvent();
224       marker_event->xclient.type = ClientMessage;
225       marker_event->xclient.display = x_display_;
226       marker_event->xclient.window = x_window_;
227       marker_event->xclient.format = 8;
228     }
229     marker_event->xclient.message_type = MarkerEventAtom();
230     XSendEvent(x_display_, x_window_, False, 0, marker_event);
231     ui::PlatformEventWaiter::Create(closure, base::Bind(&Matcher));
232   }
233  private:
234   aura::Window* RootWindowForPoint(const gfx::Point& point) {
235     // Most interactive_ui_tests run inside of the aura_test_helper
236     // environment. This means that we can't rely on gfx::Screen and several
237     // other things to work properly. Therefore we hack around this by
238     // iterating across the windows owned DesktopWindowTreeHostX11 since this
239     // doesn't rely on having a DesktopScreenX11.
240     std::vector<aura::Window*> windows =
241         DesktopWindowTreeHostX11::GetAllOpenWindows();
242     for (std::vector<aura::Window*>::const_iterator it = windows.begin();
243          it != windows.end(); ++it) {
244       if ((*it)->GetBoundsInScreen().Contains(point)) {
245         return (*it)->GetRootWindow();
246       }
247     }
248
249     NOTREACHED() << "Coulding find RW for " << point.ToString() << " among "
250                  << windows.size() << " RWs.";
251     return NULL;
252   }
253
254   void SetKeycodeAndSendThenMask(aura::WindowTreeHost* host,
255                                  XEvent* xevent,
256                                  KeySym keysym,
257                                  unsigned int mask) {
258     xevent->xkey.keycode = XKeysymToKeycode(x_display_, keysym);
259     host->PostNativeEvent(xevent);
260     xevent->xkey.state |= mask;
261   }
262
263   void UnmaskAndSetKeycodeThenSend(aura::WindowTreeHost* host,
264                                    XEvent* xevent,
265                                    unsigned int mask,
266                                    KeySym keysym) {
267     xevent->xkey.state ^= mask;
268     xevent->xkey.keycode = XKeysymToKeycode(x_display_, keysym);
269     host->PostNativeEvent(xevent);
270   }
271
272   // Our X11 state.
273   Display* x_display_;
274   ::Window x_root_window_;
275
276   // Input-only window used for events.
277   ::Window x_window_;
278
279   DISALLOW_COPY_AND_ASSIGN(UIControlsDesktopX11);
280 };
281
282 }  // namespace
283
284 UIControlsAura* CreateUIControlsDesktopAura() {
285   // The constructor of UIControlsDesktopX11 needs X11 connection to be
286   // initialized.
287   gfx::InitializeThreadedX11();
288   return new UIControlsDesktopX11();
289 }
290
291 }  // namespace test
292 }  // namespace views