| 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 |