OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/aura/desktop_host.h" | 5 #include "ui/aura/desktop_host.h" |
6 | 6 |
7 #include <X11/cursorfont.h> | 7 #include <X11/cursorfont.h> |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 | 9 |
10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. | 10 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. |
11 #undef RootWindow | 11 #undef RootWindow |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 | 14 |
15 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
16 #include "base/message_pump_x.h" | 16 #include "base/message_pump_x.h" |
17 #include "ui/aura/cursor.h" | 17 #include "ui/aura/cursor.h" |
18 #include "ui/aura/desktop.h" | 18 #include "ui/aura/desktop.h" |
19 #include "ui/aura/event.h" | 19 #include "ui/aura/event.h" |
| 20 #include "ui/base/ime/input_method_delegate.h" |
20 #include "ui/base/keycodes/keyboard_codes.h" | 21 #include "ui/base/keycodes/keyboard_codes.h" |
21 #include "ui/base/touch/touch_factory.h" | 22 #include "ui/base/touch/touch_factory.h" |
22 #include "ui/base/x/x11_util.h" | 23 #include "ui/base/x/x11_util.h" |
23 #include "ui/gfx/compositor/layer.h" | 24 #include "ui/gfx/compositor/layer.h" |
24 | 25 |
25 #include <X11/cursorfont.h> | 26 #include <X11/cursorfont.h> |
26 #include <X11/extensions/XInput2.h> | 27 #include <X11/extensions/XInput2.h> |
27 #include <X11/Xlib.h> | 28 #include <X11/Xlib.h> |
28 | 29 |
| 30 #if defined(HAVE_IBUS) |
| 31 #include "ui/base/ime/input_method_ibus_aura.h" |
| 32 #else |
| 33 #include "ui/base/ime/mock_input_method.h" |
| 34 #endif |
| 35 |
29 using std::max; | 36 using std::max; |
30 using std::min; | 37 using std::min; |
31 | 38 |
32 namespace aura { | 39 namespace aura { |
33 | 40 |
34 namespace { | 41 namespace { |
35 | 42 |
36 // Returns X font cursor shape from an Aura cursor. | 43 // Returns X font cursor shape from an Aura cursor. |
37 int CursorShapeFromNative(gfx::NativeCursor native_cursor) { | 44 int CursorShapeFromNative(gfx::NativeCursor native_cursor) { |
38 switch (native_cursor) { | 45 switch (native_cursor) { |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 } else { | 181 } else { |
175 // This isn't an event we want so free its cookie data. | 182 // This isn't an event we want so free its cookie data. |
176 XFreeEventData(display, &next_event.xcookie); | 183 XFreeEventData(display, &next_event.xcookie); |
177 } | 184 } |
178 } | 185 } |
179 break; | 186 break; |
180 } | 187 } |
181 return num_coalesed; | 188 return num_coalesed; |
182 } | 189 } |
183 | 190 |
184 // We emulate Windows' WM_KEYDOWN and WM_CHAR messages. WM_CHAR events are only | 191 class DesktopHostLinux : public DesktopHost, |
185 // generated for certain keys; see | 192 public ui::internal::InputMethodDelegate { |
186 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646268.aspx. | |
187 bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) { | |
188 if ((keycode >= ui::VKEY_0 && keycode <= ui::VKEY_9) || | |
189 (keycode >= ui::VKEY_A && keycode <= ui::VKEY_Z) || | |
190 (keycode >= ui::VKEY_NUMPAD0 && keycode <= ui::VKEY_NUMPAD9)) { | |
191 return true; | |
192 } | |
193 | |
194 switch (keycode) { | |
195 case ui::VKEY_BACK: | |
196 case ui::VKEY_RETURN: | |
197 case ui::VKEY_ESCAPE: | |
198 case ui::VKEY_SPACE: | |
199 case ui::VKEY_TAB: | |
200 // In addition to the keys listed at MSDN, we include other | |
201 // graphic-character and numpad keys. | |
202 case ui::VKEY_MULTIPLY: | |
203 case ui::VKEY_ADD: | |
204 case ui::VKEY_SUBTRACT: | |
205 case ui::VKEY_DECIMAL: | |
206 case ui::VKEY_DIVIDE: | |
207 case ui::VKEY_OEM_1: | |
208 case ui::VKEY_OEM_2: | |
209 case ui::VKEY_OEM_3: | |
210 case ui::VKEY_OEM_4: | |
211 case ui::VKEY_OEM_5: | |
212 case ui::VKEY_OEM_6: | |
213 case ui::VKEY_OEM_7: | |
214 case ui::VKEY_OEM_102: | |
215 case ui::VKEY_OEM_PLUS: | |
216 case ui::VKEY_OEM_COMMA: | |
217 case ui::VKEY_OEM_MINUS: | |
218 case ui::VKEY_OEM_PERIOD: | |
219 return true; | |
220 default: | |
221 return false; | |
222 } | |
223 } | |
224 | |
225 class DesktopHostLinux : public DesktopHost { | |
226 public: | 193 public: |
227 explicit DesktopHostLinux(const gfx::Rect& bounds); | 194 explicit DesktopHostLinux(const gfx::Rect& bounds); |
228 virtual ~DesktopHostLinux(); | 195 virtual ~DesktopHostLinux(); |
229 | 196 |
230 private: | 197 private: |
231 // base::MessageLoop::Dispatcher Override. | 198 // base::MessageLoop::Dispatcher Override. |
232 virtual DispatchStatus Dispatch(XEvent* xev) OVERRIDE; | 199 virtual DispatchStatus Dispatch(XEvent* xev) OVERRIDE; |
233 | 200 |
234 // DesktopHost Overrides. | 201 // DesktopHost Overrides. |
235 virtual void SetDesktop(Desktop* desktop) OVERRIDE; | 202 virtual void SetDesktop(Desktop* desktop) OVERRIDE; |
236 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; | 203 virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; |
237 virtual void Show() OVERRIDE; | 204 virtual void Show() OVERRIDE; |
238 virtual void ToggleFullScreen() OVERRIDE; | 205 virtual void ToggleFullScreen() OVERRIDE; |
239 virtual gfx::Size GetSize() const OVERRIDE; | 206 virtual gfx::Size GetSize() const OVERRIDE; |
240 virtual void SetSize(const gfx::Size& size) OVERRIDE; | 207 virtual void SetSize(const gfx::Size& size) OVERRIDE; |
241 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; | 208 virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; |
242 virtual gfx::Point QueryMouseLocation() OVERRIDE; | 209 virtual gfx::Point QueryMouseLocation() OVERRIDE; |
| 210 virtual ui::InputMethod* GetInputMethod() OVERRIDE; |
| 211 |
| 212 // ui::internal::InputMethodDelegate Override. |
| 213 virtual void DispatchKeyEventPostIME(Event* event) OVERRIDE; |
243 | 214 |
244 // Returns true if there's an X window manager present... in most cases. Some | 215 // Returns true if there's an X window manager present... in most cases. Some |
245 // window managers (notably, ion3) don't implement enough of ICCCM for us to | 216 // window managers (notably, ion3) don't implement enough of ICCCM for us to |
246 // detect that they're there. | 217 // detect that they're there. |
247 bool IsWindowManagerPresent(); | 218 bool IsWindowManagerPresent(); |
248 | 219 |
249 Desktop* desktop_; | 220 Desktop* desktop_; |
250 | 221 |
251 // The display and the native X window hosting the desktop. | 222 // The display and the native X window hosting the desktop. |
252 Display* xdisplay_; | 223 Display* xdisplay_; |
253 ::Window xwindow_; | 224 ::Window xwindow_; |
254 | 225 |
| 226 // The input method for the desktop. |
| 227 #if defined(HAVE_IBUS) |
| 228 ui::InputMethodIBusAura input_method_; |
| 229 #else |
| 230 ui::MockInputMethod input_method_; |
| 231 #endif |
| 232 |
255 // Current Aura cursor. | 233 // Current Aura cursor. |
256 gfx::NativeCursor current_cursor_; | 234 gfx::NativeCursor current_cursor_; |
257 | 235 |
258 // The size of |xwindow_|. | 236 // The size of |xwindow_|. |
259 gfx::Size size_; | 237 gfx::Size size_; |
260 | 238 |
261 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); | 239 DISALLOW_COPY_AND_ASSIGN(DesktopHostLinux); |
262 }; | 240 }; |
263 | 241 |
264 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) | 242 DesktopHostLinux::DesktopHostLinux(const gfx::Rect& bounds) |
265 : desktop_(NULL), | 243 : desktop_(NULL), |
266 xdisplay_(base::MessagePumpX::GetDefaultXDisplay()), | 244 xdisplay_(base::MessagePumpX::GetDefaultXDisplay()), |
267 xwindow_(0), | 245 xwindow_(0), |
| 246 ALLOW_THIS_IN_INITIALIZER_LIST(input_method_(this)), |
268 current_cursor_(aura::kCursorNull), | 247 current_cursor_(aura::kCursorNull), |
269 size_(bounds.size()) { | 248 size_(bounds.size()) { |
270 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), | 249 xwindow_ = XCreateSimpleWindow(xdisplay_, DefaultRootWindow(xdisplay_), |
271 bounds.x(), bounds.y(), | 250 bounds.x(), bounds.y(), |
272 bounds.width(), bounds.height(), | 251 bounds.width(), bounds.height(), |
273 0, 0, 0); | 252 0, 0, 0); |
274 | 253 |
275 long event_mask = ButtonPressMask | ButtonReleaseMask | | 254 long event_mask = ButtonPressMask | ButtonReleaseMask | |
276 KeyPressMask | KeyReleaseMask | | 255 KeyPressMask | KeyReleaseMask | |
277 ExposureMask | VisibilityChangeMask | | 256 ExposureMask | VisibilityChangeMask | |
278 StructureNotifyMask | PropertyChangeMask | | 257 StructureNotifyMask | PropertyChangeMask | |
279 PointerMotionMask; | 258 PointerMotionMask; |
280 XSelectInput(xdisplay_, xwindow_, event_mask); | 259 XSelectInput(xdisplay_, xwindow_, event_mask); |
281 XFlush(xdisplay_); | 260 XFlush(xdisplay_); |
282 | 261 |
283 // TODO(sadrul): reenable once 103981 is fixed. | 262 // TODO(sadrul): reenable once 103981 is fixed. |
284 #if defined(TOUCH_UI) | 263 #if defined(TOUCH_UI) |
285 if (base::MessagePumpForUI::HasXInput2()) | 264 if (base::MessagePumpForUI::HasXInput2()) |
286 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); | 265 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); |
287 #endif | 266 #endif |
| 267 |
| 268 // You can't call input_method_.Init() here since ui::InputMethod might depend |
| 269 // on aura::Desktop, and this constructor might be called during the |
| 270 // construction of the desktop singleton instance. |
288 } | 271 } |
289 | 272 |
290 DesktopHostLinux::~DesktopHostLinux() { | 273 DesktopHostLinux::~DesktopHostLinux() { |
291 XDestroyWindow(xdisplay_, xwindow_); | 274 XDestroyWindow(xdisplay_, xwindow_); |
292 | 275 |
293 // Clears XCursorCache. | 276 // Clears XCursorCache. |
294 ui::GetXCursor(ui::kCursorClearXCursorCache); | 277 ui::GetXCursor(ui::kCursorClearXCursorCache); |
295 } | 278 } |
296 | 279 |
297 base::MessagePumpDispatcher::DispatchStatus DesktopHostLinux::Dispatch( | 280 base::MessagePumpDispatcher::DispatchStatus DesktopHostLinux::Dispatch( |
298 XEvent* xev) { | 281 XEvent* xev) { |
299 bool handled = false; | 282 bool handled = false; |
300 switch (xev->type) { | 283 switch (xev->type) { |
301 case Expose: | 284 case Expose: |
302 desktop_->Draw(); | 285 desktop_->Draw(); |
303 handled = true; | 286 handled = true; |
304 break; | 287 break; |
305 case KeyPress: { | 288 case KeyPress: |
306 KeyEvent keydown_event(xev, false); | |
307 handled = desktop_->DispatchKeyEvent(&keydown_event); | |
308 if (ShouldSendCharEventForKeyboardCode(keydown_event.key_code())) { | |
309 KeyEvent char_event(xev, true); | |
310 handled |= desktop_->DispatchKeyEvent(&char_event); | |
311 } | |
312 break; | |
313 } | |
314 case KeyRelease: { | 289 case KeyRelease: { |
315 KeyEvent keyup_event(xev, false); | 290 KeyEvent key_event(xev, false); |
316 handled = desktop_->DispatchKeyEvent(&keyup_event); | 291 input_method_.DispatchKeyEvent(&key_event); |
317 break; | 292 handled = true; |
318 } | 293 } |
319 case ButtonPress: | 294 case ButtonPress: |
320 case ButtonRelease: { | 295 case ButtonRelease: { |
321 MouseEvent mouseev(xev); | 296 MouseEvent mouseev(xev); |
322 handled = desktop_->DispatchMouseEvent(&mouseev); | 297 handled = desktop_->DispatchMouseEvent(&mouseev); |
323 break; | 298 break; |
324 } | 299 } |
325 case ConfigureNotify: { | 300 case ConfigureNotify: { |
326 DCHECK_EQ(xdisplay_, xev->xconfigure.display); | 301 DCHECK_EQ(xdisplay_, xev->xconfigure.display); |
327 DCHECK_EQ(xwindow_, xev->xconfigure.window); | 302 DCHECK_EQ(xwindow_, xev->xconfigure.window); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 max(0, min(size_.height(), win_y_return))); | 456 max(0, min(size_.height(), win_y_return))); |
482 } | 457 } |
483 | 458 |
484 bool DesktopHostLinux::IsWindowManagerPresent() { | 459 bool DesktopHostLinux::IsWindowManagerPresent() { |
485 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership | 460 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
486 // of WM_Sn selections (where n is a screen number). | 461 // of WM_Sn selections (where n is a screen number). |
487 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); | 462 ::Atom wm_s0_atom = XInternAtom(xdisplay_, "WM_S0", False); |
488 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; | 463 return XGetSelectionOwner(xdisplay_, wm_s0_atom) != None; |
489 } | 464 } |
490 | 465 |
| 466 ui::InputMethod* DesktopHostLinux::GetInputMethod() { |
| 467 return &input_method_; |
| 468 } |
| 469 |
| 470 void DesktopHostLinux::DispatchKeyEventPostIME(Event* event) { |
| 471 DCHECK(event->type() == ui::ET_KEY_PRESSED || |
| 472 event->type() == ui::ET_KEY_RELEASED); |
| 473 const KeyEvent& key = *static_cast<KeyEvent*>(event); |
| 474 |
| 475 if (!key.native_event()) { |
| 476 // Dispatch a ui::VKEY_PROCESSKEY event generated by |input_method_|. |
| 477 KeyEvent aura_event(key.type(), key.key_code(), key.flags()); |
| 478 desktop_->DispatchKeyEvent(&aura_event); |
| 479 return; |
| 480 } |
| 481 |
| 482 if (key.type() == ui::ET_KEY_PRESSED) { |
| 483 KeyEvent keydown_event(key.native_event(), false); |
| 484 desktop_->DispatchKeyEvent(&keydown_event); |
| 485 // We don't send a Char event here since the input method in DesktopHost |
| 486 // takes care of it. |
| 487 } else { |
| 488 KeyEvent keyup_event(key.native_event(), false); |
| 489 desktop_->DispatchKeyEvent(&keyup_event); |
| 490 } |
| 491 } |
| 492 |
491 } // namespace | 493 } // namespace |
492 | 494 |
493 // static | 495 // static |
494 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { | 496 DesktopHost* DesktopHost::Create(const gfx::Rect& bounds) { |
495 return new DesktopHostLinux(bounds); | 497 return new DesktopHostLinux(bounds); |
496 } | 498 } |
497 | 499 |
498 // static | 500 // static |
499 gfx::Size DesktopHost::GetNativeDisplaySize() { | 501 gfx::Size DesktopHost::GetNativeDisplaySize() { |
500 ::Display* xdisplay = base::MessagePumpX::GetDefaultXDisplay(); | 502 ::Display* xdisplay = base::MessagePumpX::GetDefaultXDisplay(); |
501 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); | 503 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); |
502 } | 504 } |
503 | 505 |
504 } // namespace aura | 506 } // namespace aura |
OLD | NEW |