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