OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/views/widget/desktop_root_window_host_linux.h" | 5 #include "ui/views/widget/desktop_root_window_host_linux.h" |
6 | 6 |
| 7 #include <X11/extensions/XInput2.h> |
| 8 #include <X11/Xatom.h> |
| 9 #include <X11/Xutil.h> |
| 10 |
| 11 #include "base/message_pump_aurax11.h" |
| 12 #include "base/stringprintf.h" |
| 13 #include "ui/aura/client/screen_position_client.h" |
| 14 #include "ui/aura/client/user_action_client.h" |
| 15 #include "ui/aura/desktop/desktop_activation_client.h" |
| 16 #include "ui/aura/desktop/desktop_dispatcher_client.h" |
| 17 #include "ui/aura/focus_manager.h" |
7 #include "ui/aura/root_window.h" | 18 #include "ui/aura/root_window.h" |
| 19 #include "ui/aura/shared/compound_event_filter.h" |
| 20 #include "ui/aura/shared/input_method_event_filter.h" |
| 21 #include "ui/base/touch/touch_factory.h" |
| 22 #include "ui/base/x/x11_util.h" |
| 23 #include "ui/views/widget/desktop_capture_client.h" |
| 24 #include "ui/views/widget/x11_desktop_handler.h" |
| 25 #include "ui/views/widget/x11_window_event_filter.h" |
8 | 26 |
9 namespace views { | 27 namespace views { |
10 | 28 |
| 29 namespace { |
| 30 |
| 31 // Standard Linux mouse buttons for going back and forward. |
| 32 const int kBackMouseButton = 8; |
| 33 const int kForwardMouseButton = 9; |
| 34 |
| 35 const char* kAtomsToCache[] = { |
| 36 "WM_DELETE_WINDOW", |
| 37 "_NET_WM_PING", |
| 38 "_NET_WM_PID", |
| 39 "WM_S0", |
| 40 NULL |
| 41 }; |
| 42 |
| 43 } // namespace |
| 44 |
11 //////////////////////////////////////////////////////////////////////////////// | 45 //////////////////////////////////////////////////////////////////////////////// |
12 // DesktopRootWindowHostLinux, public: | 46 // DesktopRootWindowHostLinux, public: |
13 | 47 |
14 DesktopRootWindowHostLinux::DesktopRootWindowHostLinux() { | 48 DesktopRootWindowHostLinux::DesktopRootWindowHostLinux() |
| 49 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), |
| 50 xwindow_(0), |
| 51 x_root_window_(DefaultRootWindow(xdisplay_)), |
| 52 atom_cache_(xdisplay_, kAtomsToCache), |
| 53 window_mapped_(false), |
| 54 focus_when_shown_(false) { |
15 } | 55 } |
16 | 56 |
17 DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() { | 57 DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() { |
| 58 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); |
| 59 XDestroyWindow(xdisplay_, xwindow_); |
18 } | 60 } |
19 | 61 |
20 //////////////////////////////////////////////////////////////////////////////// | 62 //////////////////////////////////////////////////////////////////////////////// |
| 63 // DesktopRootWindowHostLinux, private: |
| 64 |
| 65 void DesktopRootWindowHostLinux::InitX11Window(const gfx::Rect& bounds) { |
| 66 XSetWindowAttributes swa; |
| 67 memset(&swa, 0, sizeof(swa)); |
| 68 swa.background_pixmap = None; |
| 69 xwindow_ = XCreateWindow( |
| 70 xdisplay_, x_root_window_, |
| 71 bounds.x(), bounds.y(), bounds.width(), bounds.height(), |
| 72 0, // border width |
| 73 CopyFromParent, // depth |
| 74 InputOutput, |
| 75 CopyFromParent, // visual |
| 76 CWBackPixmap, |
| 77 &swa); |
| 78 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); |
| 79 |
| 80 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL(). |
| 81 |
| 82 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | |
| 83 KeyPressMask | KeyReleaseMask | |
| 84 EnterWindowMask | LeaveWindowMask | |
| 85 ExposureMask | VisibilityChangeMask | |
| 86 StructureNotifyMask | PropertyChangeMask | |
| 87 PointerMotionMask; |
| 88 XSelectInput(xdisplay_, xwindow_, event_mask); |
| 89 XFlush(xdisplay_); |
| 90 |
| 91 // TODO(erg): Something about an invisible cursor here? Don't think I need |
| 92 // it, but this is where it was. |
| 93 |
| 94 // TODO(erg): We currently only request window deletion events. We also |
| 95 // should listen for activation events and anything else that GTK+ listens |
| 96 // for, and do something useful. |
| 97 ::Atom protocols[2]; |
| 98 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); |
| 99 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); |
| 100 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); |
| 101 |
| 102 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with |
| 103 // the desktop environment. |
| 104 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); |
| 105 |
| 106 // Likewise, the X server needs to know this window's pid so it knows which |
| 107 // program to kill if the window hangs. |
| 108 pid_t pid = getpid(); |
| 109 XChangeProperty(xdisplay_, |
| 110 xwindow_, |
| 111 atom_cache_.GetAtom("_NET_WM_PID"), |
| 112 XA_CARDINAL, |
| 113 32, |
| 114 PropModeReplace, |
| 115 reinterpret_cast<unsigned char*>(&pid), 1); |
| 116 |
| 117 // TODO(erg): Now that we're forked from RootWindowHostLinux, we should be |
| 118 // doing a much better job about communicating things like the window title |
| 119 // and icon to the window manager, which should replace this piece of copied |
| 120 // code. |
| 121 static int root_window_number = 0; |
| 122 std::string name = StringPrintf("aura_root_%d", root_window_number++); |
| 123 XStoreName(xdisplay_, xwindow_, name.c_str()); |
| 124 } |
| 125 |
| 126 // TODO(erg): This method should basically be everything I need form |
| 127 // RootWindowHostLinux::RootWindowHostLinux(). |
| 128 void DesktopRootWindowHostLinux::InitRootWindow( |
| 129 const Widget::InitParams& params) { |
| 130 aura::RootWindow::CreateParams rw_params(params.bounds); |
| 131 rw_params.host = this; |
| 132 root_window_.reset(new aura::RootWindow(rw_params)); |
| 133 root_window_->Init(); |
| 134 root_window_->AddChild(content_window_); |
| 135 root_window_host_delegate_ = root_window_.get(); |
| 136 |
| 137 capture_client_.reset(new DesktopCaptureClient); |
| 138 aura::client::SetCaptureClient(root_window_.get(), capture_client_.get()); |
| 139 |
| 140 root_window_->set_focus_manager( |
| 141 X11DesktopHandler::get()->get_focus_manager()); |
| 142 |
| 143 aura::DesktopActivationClient* activation_client = |
| 144 X11DesktopHandler::get()->get_activation_client(); |
| 145 aura::client::SetActivationClient( |
| 146 root_window_.get(), activation_client); |
| 147 |
| 148 dispatcher_client_.reset(new aura::DesktopDispatcherClient); |
| 149 aura::client::SetDispatcherClient(root_window_.get(), |
| 150 dispatcher_client_.get()); |
| 151 |
| 152 // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow. |
| 153 root_window_event_filter_ = new aura::shared::CompoundEventFilter; |
| 154 // Pass ownership of the filter to the root_window. |
| 155 root_window_->SetEventFilter(root_window_event_filter_); |
| 156 |
| 157 input_method_filter_.reset(new aura::shared::InputMethodEventFilter()); |
| 158 input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_.get()); |
| 159 root_window_event_filter_->AddFilter(input_method_filter_.get()); |
| 160 |
| 161 // TODO(erg): Unify this code once the other consumer goes away. |
| 162 x11_window_event_filter_.reset( |
| 163 new X11WindowEventFilter(root_window_.get(), activation_client)); |
| 164 x11_window_event_filter_->SetUseHostWindowBorders(false); |
| 165 root_window_event_filter_->AddFilter(x11_window_event_filter_.get()); |
| 166 } |
| 167 |
| 168 bool DesktopRootWindowHostLinux::IsWindowManagerPresent() { |
| 169 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
| 170 // of WM_Sn selections (where n is a screen number). |
| 171 return XGetSelectionOwner( |
| 172 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; |
| 173 } |
| 174 |
| 175 //////////////////////////////////////////////////////////////////////////////// |
21 // DesktopRootWindowHostLinux, DesktopRootWindowHost implementation: | 176 // DesktopRootWindowHostLinux, DesktopRootWindowHost implementation: |
22 | 177 |
23 void DesktopRootWindowHostLinux::Init(aura::Window* content_window, | 178 void DesktopRootWindowHostLinux::Init(aura::Window* content_window, |
24 const Widget::InitParams& params) { | 179 const Widget::InitParams& params) { |
25 // TODO(erg): | 180 content_window_ = content_window; |
26 NOTIMPLEMENTED(); | 181 |
| 182 // TODO(erg): Check whether we *should* be building a RootWindowHost here, or |
| 183 // whether we should be proxying requests to another DRWHL. |
| 184 |
| 185 // TODO(erg): We can finally solve the role problem! Based on params, try to |
| 186 // determine whether this is a utility window such as a menu. |
| 187 |
| 188 InitX11Window(params.bounds); |
| 189 InitRootWindow(params); |
| 190 |
| 191 // TODO(erg): This should be done by a LayoutManager instead of being a |
| 192 // one-off hack. |
| 193 content_window_->SetBounds(params.bounds); |
| 194 |
| 195 // This needs to be the intersection of: |
| 196 // - NativeWidgetAura::InitNativeWidget() |
| 197 // - DesktopNativeWidgetHelperAura::PreInitialize() |
27 } | 198 } |
28 | 199 |
29 void DesktopRootWindowHostLinux::Close() { | 200 void DesktopRootWindowHostLinux::Close() { |
30 // TODO(erg): | 201 // TODO(erg): |
31 NOTIMPLEMENTED(); | 202 NOTIMPLEMENTED(); |
32 } | 203 } |
33 | 204 |
34 void DesktopRootWindowHostLinux::CloseNow() { | 205 void DesktopRootWindowHostLinux::CloseNow() { |
35 // TODO(erg): | |
36 NOTIMPLEMENTED(); | 206 NOTIMPLEMENTED(); |
37 } | 207 } |
38 | 208 |
39 aura::RootWindowHost* DesktopRootWindowHostLinux::AsRootWindowHost() { | 209 aura::RootWindowHost* DesktopRootWindowHostLinux::AsRootWindowHost() { |
40 // TODO(erg): | 210 return this; |
41 NOTIMPLEMENTED(); | |
42 return NULL; | |
43 } | 211 } |
44 | 212 |
45 void DesktopRootWindowHostLinux::ShowWindowWithState( | 213 void DesktopRootWindowHostLinux::ShowWindowWithState( |
46 ui::WindowShowState show_state) { | 214 ui::WindowShowState show_state) { |
47 // TODO(erg): | 215 if (show_state != ui::SHOW_STATE_DEFAULT && |
48 NOTIMPLEMENTED(); | 216 show_state != ui::SHOW_STATE_NORMAL) { |
| 217 // Only forwarding to Show(). |
| 218 NOTIMPLEMENTED(); |
| 219 } |
| 220 |
| 221 Show(); |
49 } | 222 } |
50 | 223 |
51 void DesktopRootWindowHostLinux::ShowMaximizedWithBounds( | 224 void DesktopRootWindowHostLinux::ShowMaximizedWithBounds( |
52 const gfx::Rect& restored_bounds) { | 225 const gfx::Rect& restored_bounds) { |
53 // TODO(erg): | 226 // TODO(erg): |
54 NOTIMPLEMENTED(); | 227 NOTIMPLEMENTED(); |
55 } | 228 } |
56 | 229 |
57 bool DesktopRootWindowHostLinux::IsVisible() const { | 230 bool DesktopRootWindowHostLinux::IsVisible() const { |
58 // TODO(erg): | 231 return window_mapped_; |
59 NOTIMPLEMENTED(); | |
60 return true; | |
61 } | 232 } |
62 | 233 |
63 void DesktopRootWindowHostLinux::SetSize(const gfx::Size& size) { | 234 void DesktopRootWindowHostLinux::SetSize(const gfx::Size& size) { |
64 // TODO(erg): | 235 // TODO(erg): |
65 NOTIMPLEMENTED(); | 236 NOTIMPLEMENTED(); |
66 } | 237 } |
67 | 238 |
68 void DesktopRootWindowHostLinux::CenterWindow(const gfx::Size& size) { | 239 void DesktopRootWindowHostLinux::CenterWindow(const gfx::Size& size) { |
69 // TODO(erg): | 240 // TODO(erg): |
70 NOTIMPLEMENTED(); | 241 NOTIMPLEMENTED(); |
71 } | 242 } |
72 | 243 |
73 void DesktopRootWindowHostLinux::GetWindowPlacement( | 244 void DesktopRootWindowHostLinux::GetWindowPlacement( |
74 gfx::Rect* bounds, | 245 gfx::Rect* bounds, |
75 ui::WindowShowState* show_state) const { | 246 ui::WindowShowState* show_state) const { |
76 // TODO(erg): | 247 // TODO(erg): |
77 NOTIMPLEMENTED(); | 248 NOTIMPLEMENTED(); |
78 } | 249 } |
79 | 250 |
80 gfx::Rect DesktopRootWindowHostLinux::GetWindowBoundsInScreen() const { | 251 gfx::Rect DesktopRootWindowHostLinux::GetWindowBoundsInScreen() const { |
81 // TODO(erg): | 252 // TODO(erg): |
82 NOTIMPLEMENTED(); | 253 NOTIMPLEMENTED(); |
83 return gfx::Rect(); | 254 return gfx::Rect(); |
84 } | 255 } |
85 | 256 |
86 gfx::Rect DesktopRootWindowHostLinux::GetClientAreaBoundsInScreen() const { | 257 gfx::Rect DesktopRootWindowHostLinux::GetClientAreaBoundsInScreen() const { |
87 // TODO(erg): | 258 // TODO(erg): |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 NOTIMPLEMENTED(); | 341 NOTIMPLEMENTED(); |
171 return NULL; | 342 return NULL; |
172 } | 343 } |
173 | 344 |
174 void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) { | 345 void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) { |
175 // TODO(erg): | 346 // TODO(erg): |
176 NOTIMPLEMENTED(); | 347 NOTIMPLEMENTED(); |
177 } | 348 } |
178 | 349 |
179 //////////////////////////////////////////////////////////////////////////////// | 350 //////////////////////////////////////////////////////////////////////////////// |
| 351 // DesktopRootWindowHostLinux, aura::RootWindowHost implementation: |
| 352 |
| 353 aura::RootWindow* DesktopRootWindowHostLinux::GetRootWindow() { |
| 354 return root_window_.get(); |
| 355 } |
| 356 |
| 357 gfx::AcceleratedWidget DesktopRootWindowHostLinux::GetAcceleratedWidget() { |
| 358 return xwindow_; |
| 359 } |
| 360 |
| 361 void DesktopRootWindowHostLinux::Show() { |
| 362 if (!window_mapped_) { |
| 363 // Before we map the window, set size hints. Otherwise, some window managers |
| 364 // will ignore toplevel XMoveWindow commands. |
| 365 XSizeHints size_hints; |
| 366 size_hints.flags = PPosition; |
| 367 size_hints.x = bounds_.x(); |
| 368 size_hints.y = bounds_.y(); |
| 369 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); |
| 370 |
| 371 XMapWindow(xdisplay_, xwindow_); |
| 372 |
| 373 // We now block until our window is mapped. Some X11 APIs will crash and |
| 374 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is |
| 375 // asynchronous. |
| 376 base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_); |
| 377 window_mapped_ = true; |
| 378 } |
| 379 } |
| 380 |
| 381 void DesktopRootWindowHostLinux::Hide() { |
| 382 if (window_mapped_) { |
| 383 XWithdrawWindow(xdisplay_, xwindow_, 0); |
| 384 window_mapped_ = false; |
| 385 } |
| 386 } |
| 387 |
| 388 void DesktopRootWindowHostLinux::ToggleFullScreen() { |
| 389 } |
| 390 |
| 391 gfx::Rect DesktopRootWindowHostLinux::GetBounds() const { |
| 392 return gfx::Rect(100, 100); |
| 393 } |
| 394 |
| 395 void DesktopRootWindowHostLinux::SetBounds(const gfx::Rect& bounds) { |
| 396 } |
| 397 |
| 398 gfx::Point DesktopRootWindowHostLinux::GetLocationOnNativeScreen() const { |
| 399 return gfx::Point(1, 1); |
| 400 } |
| 401 |
| 402 void DesktopRootWindowHostLinux::SetCapture() { |
| 403 } |
| 404 |
| 405 void DesktopRootWindowHostLinux::ReleaseCapture() { |
| 406 } |
| 407 |
| 408 void DesktopRootWindowHostLinux::SetCursor(gfx::NativeCursor cursor) { |
| 409 } |
| 410 |
| 411 void DesktopRootWindowHostLinux::ShowCursor(bool show) { |
| 412 } |
| 413 |
| 414 bool DesktopRootWindowHostLinux::QueryMouseLocation( |
| 415 gfx::Point* location_return) { |
| 416 return false; |
| 417 } |
| 418 |
| 419 bool DesktopRootWindowHostLinux::ConfineCursorToRootWindow() { |
| 420 return false; |
| 421 } |
| 422 |
| 423 void DesktopRootWindowHostLinux::UnConfineCursor() { |
| 424 } |
| 425 |
| 426 void DesktopRootWindowHostLinux::MoveCursorTo(const gfx::Point& location) { |
| 427 } |
| 428 |
| 429 void DesktopRootWindowHostLinux::SetFocusWhenShown(bool focus_when_shown) { |
| 430 static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME"; |
| 431 focus_when_shown_ = focus_when_shown; |
| 432 if (IsWindowManagerPresent() && !focus_when_shown_) { |
| 433 ui::SetIntProperty(xwindow_, |
| 434 k_NET_WM_USER_TIME, |
| 435 k_NET_WM_USER_TIME, |
| 436 0); |
| 437 } |
| 438 } |
| 439 |
| 440 bool DesktopRootWindowHostLinux::GrabSnapshot( |
| 441 const gfx::Rect& snapshot_bounds, |
| 442 std::vector<unsigned char>* png_representation) { |
| 443 return false; |
| 444 } |
| 445 |
| 446 void DesktopRootWindowHostLinux::PostNativeEvent( |
| 447 const base::NativeEvent& native_event) { |
| 448 DCHECK(xwindow_); |
| 449 DCHECK(xdisplay_); |
| 450 XEvent xevent = *native_event; |
| 451 xevent.xany.display = xdisplay_; |
| 452 xevent.xany.window = xwindow_; |
| 453 |
| 454 switch (xevent.type) { |
| 455 case EnterNotify: |
| 456 case LeaveNotify: |
| 457 case MotionNotify: |
| 458 case KeyPress: |
| 459 case KeyRelease: |
| 460 case ButtonPress: |
| 461 case ButtonRelease: { |
| 462 // The fields used below are in the same place for all of events |
| 463 // above. Using xmotion from XEvent's unions to avoid repeating |
| 464 // the code. |
| 465 xevent.xmotion.root = x_root_window_; |
| 466 xevent.xmotion.time = CurrentTime; |
| 467 |
| 468 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); |
| 469 root_window_->ConvertPointToNativeScreen(&point); |
| 470 xevent.xmotion.x_root = point.x(); |
| 471 xevent.xmotion.y_root = point.y(); |
| 472 } |
| 473 default: |
| 474 break; |
| 475 } |
| 476 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); |
| 477 } |
| 478 |
| 479 void DesktopRootWindowHostLinux::OnDeviceScaleFactorChanged( |
| 480 float device_scale_factor) { |
| 481 } |
| 482 |
| 483 void DesktopRootWindowHostLinux::PrepareForShutdown() { |
| 484 } |
| 485 |
| 486 //////////////////////////////////////////////////////////////////////////////// |
| 487 // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation: |
| 488 |
| 489 bool DesktopRootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
| 490 XEvent* xev = event; |
| 491 |
| 492 // May want to factor CheckXEventForConsistency(xev); into a common location |
| 493 // since it is called here. |
| 494 switch (xev->type) { |
| 495 case Expose: |
| 496 // TODO(erg): Can we only redraw the affected areas? |
| 497 root_window_host_delegate_->OnHostPaint(); |
| 498 break; |
| 499 case KeyPress: { |
| 500 ui::KeyEvent keydown_event(xev, false); |
| 501 root_window_host_delegate_->OnHostKeyEvent(&keydown_event); |
| 502 break; |
| 503 } |
| 504 case KeyRelease: { |
| 505 ui::KeyEvent keyup_event(xev, false); |
| 506 root_window_host_delegate_->OnHostKeyEvent(&keyup_event); |
| 507 break; |
| 508 } |
| 509 case ButtonPress: { |
| 510 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || |
| 511 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { |
| 512 aura::client::UserActionClient* gesture_client = |
| 513 aura::client::GetUserActionClient(root_window_.get()); |
| 514 if (gesture_client) { |
| 515 gesture_client->OnUserAction( |
| 516 static_cast<int>(xev->xbutton.button) == kBackMouseButton ? |
| 517 aura::client::UserActionClient::BACK : |
| 518 aura::client::UserActionClient::FORWARD); |
| 519 } |
| 520 break; |
| 521 } |
| 522 } // fallthrough |
| 523 case ButtonRelease: { |
| 524 ui::MouseEvent mouseev(xev); |
| 525 root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
| 526 break; |
| 527 } |
| 528 case FocusOut: |
| 529 if (xev->xfocus.mode != NotifyGrab) |
| 530 root_window_host_delegate_->OnHostLostCapture(); |
| 531 break; |
| 532 case ConfigureNotify: { |
| 533 DCHECK_EQ(xwindow_, xev->xconfigure.window); |
| 534 DCHECK_EQ(xwindow_, xev->xconfigure.event); |
| 535 // It's possible that the X window may be resized by some other means than |
| 536 // from within aura (e.g. the X window manager can change the size). Make |
| 537 // sure the root window size is maintained properly. |
| 538 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, |
| 539 xev->xconfigure.width, xev->xconfigure.height); |
| 540 bool size_changed = bounds_.size() != bounds.size(); |
| 541 bool origin_changed = bounds_.origin() != bounds.origin(); |
| 542 bounds_ = bounds; |
| 543 if (size_changed) |
| 544 root_window_host_delegate_->OnHostResized(bounds.size()); |
| 545 if (origin_changed) |
| 546 root_window_host_delegate_->OnHostMoved(bounds_.origin()); |
| 547 break; |
| 548 } |
| 549 case GenericEvent: { |
| 550 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
| 551 if (!factory->ShouldProcessXI2Event(xev)) |
| 552 break; |
| 553 |
| 554 ui::EventType type = ui::EventTypeFromNative(xev); |
| 555 XEvent last_event; |
| 556 int num_coalesced = 0; |
| 557 |
| 558 switch (type) { |
| 559 // case ui::ET_TOUCH_MOVED: |
| 560 // num_coalesced = CoalescePendingMotionEvents(xev, &last_event); |
| 561 // if (num_coalesced > 0) |
| 562 // xev = &last_event; |
| 563 // // fallthrough |
| 564 // case ui::ET_TOUCH_PRESSED: |
| 565 // case ui::ET_TOUCH_RELEASED: { |
| 566 // ui::TouchEvent touchev(xev); |
| 567 // root_window_host_delegate_->OnHostTouchEvent(&touchev); |
| 568 // break; |
| 569 // } |
| 570 case ui::ET_MOUSE_MOVED: |
| 571 case ui::ET_MOUSE_DRAGGED: |
| 572 case ui::ET_MOUSE_PRESSED: |
| 573 case ui::ET_MOUSE_RELEASED: |
| 574 case ui::ET_MOUSE_ENTERED: |
| 575 case ui::ET_MOUSE_EXITED: { |
| 576 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
| 577 // If this is a motion event, we want to coalesce all pending motion |
| 578 // events that are at the top of the queue. |
| 579 // num_coalesced = CoalescePendingMotionEvents(xev, &last_event); |
| 580 // if (num_coalesced > 0) |
| 581 // xev = &last_event; |
| 582 } else if (type == ui::ET_MOUSE_PRESSED) { |
| 583 XIDeviceEvent* xievent = |
| 584 static_cast<XIDeviceEvent*>(xev->xcookie.data); |
| 585 int button = xievent->detail; |
| 586 if (button == kBackMouseButton || button == kForwardMouseButton) { |
| 587 aura::client::UserActionClient* gesture_client = |
| 588 aura::client::GetUserActionClient( |
| 589 root_window_host_delegate_->AsRootWindow()); |
| 590 if (gesture_client) { |
| 591 bool reverse_direction = |
| 592 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
| 593 gesture_client->OnUserAction( |
| 594 (button == kBackMouseButton && !reverse_direction) || |
| 595 (button == kForwardMouseButton && reverse_direction) ? |
| 596 aura::client::UserActionClient::BACK : |
| 597 aura::client::UserActionClient::FORWARD); |
| 598 } |
| 599 break; |
| 600 } |
| 601 } |
| 602 ui::MouseEvent mouseev(xev); |
| 603 root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
| 604 break; |
| 605 } |
| 606 case ui::ET_MOUSEWHEEL: { |
| 607 ui::MouseWheelEvent mouseev(xev); |
| 608 root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
| 609 break; |
| 610 } |
| 611 case ui::ET_SCROLL_FLING_START: |
| 612 case ui::ET_SCROLL_FLING_CANCEL: |
| 613 case ui::ET_SCROLL: { |
| 614 ui::ScrollEvent scrollev(xev); |
| 615 root_window_host_delegate_->OnHostScrollEvent(&scrollev); |
| 616 break; |
| 617 } |
| 618 case ui::ET_UNKNOWN: |
| 619 break; |
| 620 default: |
| 621 NOTREACHED(); |
| 622 } |
| 623 |
| 624 // If we coalesced an event we need to free its cookie. |
| 625 if (num_coalesced > 0) |
| 626 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
| 627 break; |
| 628 } |
| 629 case MapNotify: { |
| 630 // If there's no window manager running, we need to assign the X input |
| 631 // focus to our host window. |
| 632 if (!IsWindowManagerPresent() && focus_when_shown_) |
| 633 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); |
| 634 break; |
| 635 } |
| 636 case ClientMessage: { |
| 637 Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]); |
| 638 if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { |
| 639 // We have received a close message from the window manager. |
| 640 root_window_->OnRootWindowHostCloseRequested(); |
| 641 } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) { |
| 642 XEvent reply_event = *xev; |
| 643 reply_event.xclient.window = x_root_window_; |
| 644 |
| 645 XSendEvent(xdisplay_, |
| 646 reply_event.xclient.window, |
| 647 False, |
| 648 SubstructureRedirectMask | SubstructureNotifyMask, |
| 649 &reply_event); |
| 650 } |
| 651 break; |
| 652 } |
| 653 case MappingNotify: { |
| 654 switch (xev->xmapping.request) { |
| 655 case MappingModifier: |
| 656 case MappingKeyboard: |
| 657 XRefreshKeyboardMapping(&xev->xmapping); |
| 658 root_window_->OnKeyboardMappingChanged(); |
| 659 break; |
| 660 case MappingPointer: |
| 661 ui::UpdateButtonMap(); |
| 662 break; |
| 663 default: |
| 664 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; |
| 665 break; |
| 666 } |
| 667 break; |
| 668 } |
| 669 case MotionNotify: { |
| 670 // Discard all but the most recent motion event that targets the same |
| 671 // window with unchanged state. |
| 672 XEvent last_event; |
| 673 while (XPending(xev->xany.display)) { |
| 674 XEvent next_event; |
| 675 XPeekEvent(xev->xany.display, &next_event); |
| 676 if (next_event.type == MotionNotify && |
| 677 next_event.xmotion.window == xev->xmotion.window && |
| 678 next_event.xmotion.subwindow == xev->xmotion.subwindow && |
| 679 next_event.xmotion.state == xev->xmotion.state) { |
| 680 XNextEvent(xev->xany.display, &last_event); |
| 681 xev = &last_event; |
| 682 } else { |
| 683 break; |
| 684 } |
| 685 } |
| 686 |
| 687 ui::MouseEvent mouseev(xev); |
| 688 root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
| 689 break; |
| 690 } |
| 691 } |
| 692 return true; |
| 693 } |
| 694 |
| 695 //////////////////////////////////////////////////////////////////////////////// |
180 // DesktopRootWindowHost, public: | 696 // DesktopRootWindowHost, public: |
181 | 697 |
182 // static | 698 // static |
183 DesktopRootWindowHost* DesktopRootWindowHost::Create( | 699 DesktopRootWindowHost* DesktopRootWindowHost::Create( |
184 internal::NativeWidgetDelegate* native_widget_delegate, | 700 internal::NativeWidgetDelegate* native_widget_delegate, |
185 const gfx::Rect& initial_bounds) { | 701 const gfx::Rect& initial_bounds) { |
186 return new DesktopRootWindowHostLinux; | 702 return new DesktopRootWindowHostLinux; |
187 } | 703 } |
188 | 704 |
189 } // namespace views | 705 } // namespace views |
OLD | NEW |