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 3 // found in the LICENSE file. 4 5 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" 6 7 #include <X11/extensions/shape.h> 8 #include <X11/extensions/XInput2.h> 9 #include <X11/Xatom.h> 10 #include <X11/Xregion.h> 11 #include <X11/Xutil.h> 12 13 #include "base/basictypes.h" 14 #include "base/command_line.h" 15 #include "base/debug/trace_event.h" 16 #include "base/strings/stringprintf.h" 17 #include "base/strings/utf_string_conversions.h" 18 #include "third_party/skia/include/core/SkPath.h" 19 #include "ui/aura/client/cursor_client.h" 20 #include "ui/aura/client/focus_client.h" 21 #include "ui/aura/window.h" 22 #include "ui/aura/window_event_dispatcher.h" 23 #include "ui/aura/window_property.h" 24 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" 25 #include "ui/base/hit_test.h" 26 #include "ui/base/x/x11_util.h" 27 #include "ui/events/event_utils.h" 28 #include "ui/events/platform/platform_event_source.h" 29 #include "ui/events/platform/x11/x11_event_source.h" 30 #include "ui/events/x/device_data_manager.h" 31 #include "ui/events/x/device_list_cache_x.h" 32 #include "ui/events/x/touch_factory_x11.h" 33 #include "ui/gfx/image/image_skia.h" 34 #include "ui/gfx/image/image_skia_rep.h" 35 #include "ui/gfx/insets.h" 36 #include "ui/gfx/path.h" 37 #include "ui/gfx/path_x11.h" 38 #include "ui/gfx/screen.h" 39 #include "ui/native_theme/native_theme.h" 40 #include "ui/views/corewm/tooltip_aura.h" 41 #include "ui/views/ime/input_method.h" 42 #include "ui/views/linux_ui/linux_ui.h" 43 #include "ui/views/views_delegate.h" 44 #include "ui/views/views_switches.h" 45 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h" 46 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" 47 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" 48 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" 49 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h" 50 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h" 51 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h" 52 #include "ui/views/widget/desktop_aura/x11_scoped_capture.h" 53 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h" 54 #include "ui/wm/core/compound_event_filter.h" 55 #include "ui/wm/core/window_util.h" 56 57 namespace views { 58 59 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture = 60 NULL; 61 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL; 62 63 DEFINE_WINDOW_PROPERTY_KEY( 64 aura::Window*, kViewsWindowForRootWindow, NULL); 65 66 DEFINE_WINDOW_PROPERTY_KEY( 67 DesktopWindowTreeHostX11*, kHostForRootWindow, NULL); 68 69 namespace { 70 71 // Constants that are part of EWMH. 72 const int k_NET_WM_STATE_ADD = 1; 73 const int k_NET_WM_STATE_REMOVE = 0; 74 75 // Special value of the _NET_WM_DESKTOP property which indicates that the window 76 // should appear on all desktops. 77 const int kAllDesktops = 0xFFFFFFFF; 78 79 const char* kAtomsToCache[] = { 80 "UTF8_STRING", 81 "WM_DELETE_WINDOW", 82 "WM_PROTOCOLS", 83 "_NET_FRAME_EXTENTS", 84 "_NET_WM_CM_S0", 85 "_NET_WM_DESKTOP", 86 "_NET_WM_ICON", 87 "_NET_WM_NAME", 88 "_NET_WM_PID", 89 "_NET_WM_PING", 90 "_NET_WM_STATE", 91 "_NET_WM_STATE_ABOVE", 92 "_NET_WM_STATE_FULLSCREEN", 93 "_NET_WM_STATE_HIDDEN", 94 "_NET_WM_STATE_MAXIMIZED_HORZ", 95 "_NET_WM_STATE_MAXIMIZED_VERT", 96 "_NET_WM_STATE_SKIP_TASKBAR", 97 "_NET_WM_STATE_STICKY", 98 "_NET_WM_USER_TIME", 99 "_NET_WM_WINDOW_OPACITY", 100 "_NET_WM_WINDOW_TYPE", 101 "_NET_WM_WINDOW_TYPE_DND", 102 "_NET_WM_WINDOW_TYPE_MENU", 103 "_NET_WM_WINDOW_TYPE_NORMAL", 104 "_NET_WM_WINDOW_TYPE_NOTIFICATION", 105 "_NET_WM_WINDOW_TYPE_TOOLTIP", 106 "XdndActionAsk", 107 "XdndActionCopy" 108 "XdndActionLink", 109 "XdndActionList", 110 "XdndActionMove", 111 "XdndActionPrivate", 112 "XdndAware", 113 "XdndDrop", 114 "XdndEnter", 115 "XdndFinished", 116 "XdndLeave", 117 "XdndPosition", 118 "XdndProxy", // Proxy windows? 119 "XdndSelection", 120 "XdndStatus", 121 "XdndTypeList", 122 NULL 123 }; 124 125 } // namespace 126 127 //////////////////////////////////////////////////////////////////////////////// 128 // DesktopWindowTreeHostX11, public: 129 130 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11( 131 internal::NativeWidgetDelegate* native_widget_delegate, 132 DesktopNativeWidgetAura* desktop_native_widget_aura) 133 : close_widget_factory_(this), 134 xdisplay_(gfx::GetXDisplay()), 135 xwindow_(0), 136 x_root_window_(DefaultRootWindow(xdisplay_)), 137 atom_cache_(xdisplay_, kAtomsToCache), 138 window_mapped_(false), 139 is_fullscreen_(false), 140 is_always_on_top_(false), 141 use_native_frame_(false), 142 use_argb_visual_(false), 143 drag_drop_client_(NULL), 144 current_cursor_(ui::kCursorNull), 145 native_widget_delegate_(native_widget_delegate), 146 desktop_native_widget_aura_(desktop_native_widget_aura), 147 content_window_(NULL), 148 window_parent_(NULL), 149 window_shape_(NULL), 150 custom_window_shape_(false), 151 urgency_hint_set_(false) { 152 } 153 154 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { 155 window()->ClearProperty(kHostForRootWindow); 156 aura::client::SetWindowMoveClient(window(), NULL); 157 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this); 158 if (window_shape_) 159 XDestroyRegion(window_shape_); 160 DestroyDispatcher(); 161 } 162 163 // static 164 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) { 165 aura::WindowTreeHost* host = 166 aura::WindowTreeHost::GetForAcceleratedWidget(xid); 167 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL; 168 } 169 170 // static 171 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) { 172 aura::WindowTreeHost* host = 173 aura::WindowTreeHost::GetForAcceleratedWidget(xid); 174 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL; 175 } 176 177 // static 178 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() { 179 std::vector<aura::Window*> windows(open_windows().size()); 180 std::transform(open_windows().begin(), 181 open_windows().end(), 182 windows.begin(), 183 GetContentWindowForXID); 184 return windows; 185 } 186 187 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const { 188 return bounds_; 189 } 190 191 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const { 192 gfx::Rect outer_bounds(bounds_); 193 outer_bounds.Inset(-native_window_frame_borders_); 194 return outer_bounds; 195 } 196 197 ::Region DesktopWindowTreeHostX11::GetWindowShape() const { 198 return window_shape_; 199 } 200 201 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged( 202 bool active) { 203 if (active) { 204 FlashFrame(false); 205 OnHostActivated(); 206 open_windows().remove(xwindow_); 207 open_windows().insert(open_windows().begin(), xwindow_); 208 } 209 210 desktop_native_widget_aura_->HandleActivationChanged(active); 211 212 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint(); 213 } 214 215 void DesktopWindowTreeHostX11::AddObserver( 216 views::DesktopWindowTreeHostObserverX11* observer) { 217 observer_list_.AddObserver(observer); 218 } 219 220 void DesktopWindowTreeHostX11::RemoveObserver( 221 views::DesktopWindowTreeHostObserverX11* observer) { 222 observer_list_.RemoveObserver(observer); 223 } 224 225 void DesktopWindowTreeHostX11::SwapNonClientEventHandler( 226 scoped_ptr<ui::EventHandler> handler) { 227 wm::CompoundEventFilter* compound_event_filter = 228 desktop_native_widget_aura_->root_window_event_filter(); 229 if (x11_non_client_event_filter_) 230 compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get()); 231 compound_event_filter->AddHandler(handler.get()); 232 x11_non_client_event_filter_ = handler.Pass(); 233 } 234 235 void DesktopWindowTreeHostX11::CleanUpWindowList() { 236 delete open_windows_; 237 open_windows_ = NULL; 238 } 239 240 //////////////////////////////////////////////////////////////////////////////// 241 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation: 242 243 void DesktopWindowTreeHostX11::Init(aura::Window* content_window, 244 const Widget::InitParams& params) { 245 content_window_ = content_window; 246 247 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or 248 // whether we should be proxying requests to another DRWHL. 249 250 // In some situations, views tries to make a zero sized window, and that 251 // makes us crash. Make sure we have valid sizes. 252 Widget::InitParams sanitized_params = params; 253 if (sanitized_params.bounds.width() == 0) 254 sanitized_params.bounds.set_width(100); 255 if (sanitized_params.bounds.height() == 0) 256 sanitized_params.bounds.set_height(100); 257 258 InitX11Window(sanitized_params); 259 } 260 261 void DesktopWindowTreeHostX11::OnNativeWidgetCreated( 262 const Widget::InitParams& params) { 263 window()->SetProperty(kViewsWindowForRootWindow, content_window_); 264 window()->SetProperty(kHostForRootWindow, this); 265 266 // Ensure that the X11DesktopHandler exists so that it dispatches activation 267 // messages to us. 268 X11DesktopHandler::get(); 269 270 // TODO(erg): Unify this code once the other consumer goes away. 271 SwapNonClientEventHandler( 272 scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass()); 273 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW && 274 !params.remove_standard_frame); 275 276 x11_window_move_client_.reset(new X11DesktopWindowMoveClient); 277 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get()); 278 279 SetWindowTransparency(); 280 281 native_widget_delegate_->OnNativeWidgetCreated(true); 282 } 283 284 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() { 285 return scoped_ptr<corewm::Tooltip>( 286 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE)); 287 } 288 289 scoped_ptr<aura::client::DragDropClient> 290 DesktopWindowTreeHostX11::CreateDragDropClient( 291 DesktopNativeCursorManager* cursor_manager) { 292 drag_drop_client_ = new DesktopDragDropClientAuraX11( 293 window(), cursor_manager, xdisplay_, xwindow_); 294 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass(); 295 } 296 297 void DesktopWindowTreeHostX11::Close() { 298 // TODO(erg): Might need to do additional hiding tasks here. 299 delayed_resize_task_.Cancel(); 300 301 if (!close_widget_factory_.HasWeakPtrs()) { 302 // And we delay the close so that if we are called from an ATL callback, 303 // we don't destroy the window before the callback returned (as the caller 304 // may delete ourselves on destroy and the ATL callback would still 305 // dereference us when the callback returns). 306 base::MessageLoop::current()->PostTask( 307 FROM_HERE, 308 base::Bind(&DesktopWindowTreeHostX11::CloseNow, 309 close_widget_factory_.GetWeakPtr())); 310 } 311 } 312 313 void DesktopWindowTreeHostX11::CloseNow() { 314 if (xwindow_ == None) 315 return; 316 317 x11_capture_.reset(); 318 native_widget_delegate_->OnNativeWidgetDestroying(); 319 320 // If we have children, close them. Use a copy for iteration because they'll 321 // remove themselves. 322 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_; 323 for (std::set<DesktopWindowTreeHostX11*>::iterator it = 324 window_children_copy.begin(); it != window_children_copy.end(); 325 ++it) { 326 (*it)->CloseNow(); 327 } 328 DCHECK(window_children_.empty()); 329 330 // If we have a parent, remove ourselves from its children list. 331 if (window_parent_) { 332 window_parent_->window_children_.erase(this); 333 window_parent_ = NULL; 334 } 335 336 // Remove the event listeners we've installed. We need to remove these 337 // because otherwise we get assert during ~WindowEventDispatcher(). 338 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler( 339 x11_non_client_event_filter_.get()); 340 x11_non_client_event_filter_.reset(); 341 342 // Destroy the compositor before destroying the |xwindow_| since shutdown 343 // may try to swap, and the swap without a window causes an X error, which 344 // causes a crash with in-process renderer. 345 DestroyCompositor(); 346 347 open_windows().remove(xwindow_); 348 // Actually free our native resources. 349 if (ui::PlatformEventSource::GetInstance()) 350 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); 351 XDestroyWindow(xdisplay_, xwindow_); 352 xwindow_ = None; 353 354 desktop_native_widget_aura_->OnHostClosed(); 355 } 356 357 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() { 358 return this; 359 } 360 361 void DesktopWindowTreeHostX11::ShowWindowWithState( 362 ui::WindowShowState show_state) { 363 if (!window_mapped_) 364 MapWindow(show_state); 365 366 if (show_state == ui::SHOW_STATE_NORMAL || 367 show_state == ui::SHOW_STATE_MAXIMIZED) { 368 // Note: XFCE ignores a maximize hint given before mapping the window. 369 if (show_state == ui::SHOW_STATE_MAXIMIZED) 370 Maximize(); 371 Activate(); 372 } 373 374 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state); 375 } 376 377 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds( 378 const gfx::Rect& restored_bounds) { 379 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED); 380 // Enforce |restored_bounds_| since calling Maximize() could have reset it. 381 restored_bounds_ = restored_bounds; 382 } 383 384 bool DesktopWindowTreeHostX11::IsVisible() const { 385 return window_mapped_; 386 } 387 388 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) { 389 bool size_changed = bounds_.size() != size; 390 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); 391 bounds_.set_size(size); 392 if (size_changed) { 393 OnHostResized(size); 394 ResetWindowRegion(); 395 } 396 } 397 398 void DesktopWindowTreeHostX11::StackAtTop() { 399 XRaiseWindow(xdisplay_, xwindow_); 400 } 401 402 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) { 403 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen(); 404 405 // If |window_|'s transient parent bounds are big enough to contain |size|, 406 // use them instead. 407 if (wm::GetTransientParent(content_window_)) { 408 gfx::Rect transient_parent_rect = 409 wm::GetTransientParent(content_window_)->GetBoundsInScreen(); 410 if (transient_parent_rect.height() >= size.height() && 411 transient_parent_rect.width() >= size.width()) { 412 parent_bounds = transient_parent_rect; 413 } 414 } 415 416 gfx::Rect window_bounds( 417 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2, 418 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2, 419 size.width(), 420 size.height()); 421 // Don't size the window bigger than the parent, otherwise the user may not be 422 // able to close or move it. 423 window_bounds.AdjustToFit(parent_bounds); 424 425 SetBounds(window_bounds); 426 } 427 428 void DesktopWindowTreeHostX11::GetWindowPlacement( 429 gfx::Rect* bounds, 430 ui::WindowShowState* show_state) const { 431 *bounds = GetRestoredBounds(); 432 433 if (IsFullscreen()) { 434 *show_state = ui::SHOW_STATE_FULLSCREEN; 435 } else if (IsMinimized()) { 436 *show_state = ui::SHOW_STATE_MINIMIZED; 437 } else if (IsMaximized()) { 438 *show_state = ui::SHOW_STATE_MAXIMIZED; 439 } else if (!IsActive()) { 440 *show_state = ui::SHOW_STATE_INACTIVE; 441 } else { 442 *show_state = ui::SHOW_STATE_NORMAL; 443 } 444 } 445 446 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const { 447 return bounds_; 448 } 449 450 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const { 451 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its 452 // needed for View::ConvertPointToScreen() to work 453 // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just 454 // asks windows what it thinks the client rect is. 455 // 456 // Attempts to calculate the rect by asking the NonClientFrameView what it 457 // thought its GetBoundsForClientView() were broke combobox drop down 458 // placement. 459 return bounds_; 460 } 461 462 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const { 463 // We can't reliably track the restored bounds of a window, but we can get 464 // the 90% case down. When *chrome* is the process that requests maximizing 465 // or restoring bounds, we can record the current bounds before we request 466 // maximization, and clear it when we detect a state change. 467 if (!restored_bounds_.IsEmpty()) 468 return restored_bounds_; 469 470 return GetWindowBoundsInScreen(); 471 } 472 473 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const { 474 std::vector<int> value; 475 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) && 476 value.size() >= 4) { 477 return gfx::Rect(value[0], value[1], value[2], value[3]); 478 } 479 480 // Fetch the geometry of the root window. 481 Window root; 482 int x, y; 483 unsigned int width, height; 484 unsigned int border_width, depth; 485 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, 486 &width, &height, &border_width, &depth)) { 487 NOTIMPLEMENTED(); 488 return gfx::Rect(0, 0, 10, 10); 489 } 490 491 return gfx::Rect(x, y, width, height); 492 } 493 494 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) { 495 if (window_shape_) 496 XDestroyRegion(window_shape_); 497 custom_window_shape_ = true; 498 window_shape_ = gfx::CreateRegionFromSkRegion(*native_region); 499 ResetWindowRegion(); 500 delete native_region; 501 } 502 503 void DesktopWindowTreeHostX11::Activate() { 504 if (!window_mapped_) 505 return; 506 507 X11DesktopHandler::get()->ActivateWindow(xwindow_); 508 } 509 510 void DesktopWindowTreeHostX11::Deactivate() { 511 if (!IsActive()) 512 return; 513 514 x11_capture_.reset(); 515 XLowerWindow(xdisplay_, xwindow_); 516 } 517 518 bool DesktopWindowTreeHostX11::IsActive() const { 519 return X11DesktopHandler::get()->IsActiveWindow(xwindow_); 520 } 521 522 void DesktopWindowTreeHostX11::Maximize() { 523 // When we are in the process of requesting to maximize a window, we can 524 // accurately keep track of our restored bounds instead of relying on the 525 // heuristics that are in the PropertyNotify and ConfigureNotify handlers. 526 restored_bounds_ = bounds_; 527 528 SetWMSpecState(true, 529 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), 530 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); 531 if (IsMinimized()) 532 ShowWindowWithState(ui::SHOW_STATE_NORMAL); 533 } 534 535 void DesktopWindowTreeHostX11::Minimize() { 536 x11_capture_.reset(); 537 XIconifyWindow(xdisplay_, xwindow_, 0); 538 } 539 540 void DesktopWindowTreeHostX11::Restore() { 541 SetWMSpecState(false, 542 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), 543 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); 544 if (IsMinimized()) 545 ShowWindowWithState(ui::SHOW_STATE_NORMAL); 546 } 547 548 bool DesktopWindowTreeHostX11::IsMaximized() const { 549 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") && 550 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ")); 551 } 552 553 bool DesktopWindowTreeHostX11::IsMinimized() const { 554 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN"); 555 } 556 557 bool DesktopWindowTreeHostX11::HasCapture() const { 558 return g_current_capture == this; 559 } 560 561 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) { 562 is_always_on_top_ = always_on_top; 563 SetWMSpecState(always_on_top, 564 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"), 565 None); 566 } 567 568 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const { 569 return is_always_on_top_; 570 } 571 572 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) { 573 SetWMSpecState(always_visible, 574 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"), 575 None); 576 577 int new_desktop = 0; 578 if (always_visible) { 579 new_desktop = kAllDesktops; 580 } else { 581 if (!ui::GetCurrentDesktop(&new_desktop)) 582 return; 583 } 584 585 XEvent xevent; 586 memset (&xevent, 0, sizeof (xevent)); 587 xevent.type = ClientMessage; 588 xevent.xclient.window = xwindow_; 589 xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP"); 590 xevent.xclient.format = 32; 591 xevent.xclient.data.l[0] = new_desktop; 592 xevent.xclient.data.l[1] = 0; 593 xevent.xclient.data.l[2] = 0; 594 xevent.xclient.data.l[3] = 0; 595 xevent.xclient.data.l[4] = 0; 596 XSendEvent(xdisplay_, x_root_window_, False, 597 SubstructureRedirectMask | SubstructureNotifyMask, 598 &xevent); 599 } 600 601 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) { 602 if (window_title_ == title) 603 return false; 604 window_title_ = title; 605 std::string utf8str = base::UTF16ToUTF8(title); 606 XChangeProperty(xdisplay_, 607 xwindow_, 608 atom_cache_.GetAtom("_NET_WM_NAME"), 609 atom_cache_.GetAtom("UTF8_STRING"), 610 8, 611 PropModeReplace, 612 reinterpret_cast<const unsigned char*>(utf8str.c_str()), 613 utf8str.size()); 614 // TODO(erg): This is technically wrong. So XStoreName and friends expect 615 // this in Host Portable Character Encoding instead of UTF-8, which I believe 616 // is Compound Text. This shouldn't matter 90% of the time since this is the 617 // fallback to the UTF8 property above. 618 XStoreName(xdisplay_, xwindow_, utf8str.c_str()); 619 return true; 620 } 621 622 void DesktopWindowTreeHostX11::ClearNativeFocus() { 623 // This method is weird and misnamed. Instead of clearing the native focus, 624 // it sets the focus to our |content_window_|, which will trigger a cascade 625 // of focus changes into views. 626 if (content_window_ && aura::client::GetFocusClient(content_window_) && 627 content_window_->Contains( 628 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) { 629 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_); 630 } 631 } 632 633 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop( 634 const gfx::Vector2d& drag_offset, 635 Widget::MoveLoopSource source, 636 Widget::MoveLoopEscapeBehavior escape_behavior) { 637 aura::client::WindowMoveSource window_move_source = 638 source == Widget::MOVE_LOOP_SOURCE_MOUSE ? 639 aura::client::WINDOW_MOVE_SOURCE_MOUSE : 640 aura::client::WINDOW_MOVE_SOURCE_TOUCH; 641 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset, 642 window_move_source) == aura::client::MOVE_SUCCESSFUL) 643 return Widget::MOVE_LOOP_SUCCESSFUL; 644 645 return Widget::MOVE_LOOP_CANCELED; 646 } 647 648 void DesktopWindowTreeHostX11::EndMoveLoop() { 649 x11_window_move_client_->EndMoveLoop(); 650 } 651 652 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled( 653 bool value) { 654 // Much like the previous NativeWidgetGtk, we don't have anything to do here. 655 } 656 657 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const { 658 return use_native_frame_; 659 } 660 661 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const { 662 return false; 663 } 664 665 void DesktopWindowTreeHostX11::FrameTypeChanged() { 666 Widget::FrameType new_type = 667 native_widget_delegate_->AsWidget()->frame_type(); 668 if (new_type == Widget::FRAME_TYPE_DEFAULT) { 669 // The default is determined by Widget::InitParams::remove_standard_frame 670 // and does not change. 671 return; 672 } 673 674 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE); 675 // Replace the frame and layout the contents. Even though we don't have a 676 // swapable glass frame like on Windows, we still replace the frame because 677 // the button assets don't update otherwise. 678 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(); 679 } 680 681 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) { 682 if (is_fullscreen_ == fullscreen) 683 return; 684 is_fullscreen_ = fullscreen; 685 SetWMSpecState(fullscreen, 686 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"), 687 None); 688 // Try to guess the size we will have after the switch to/from fullscreen: 689 // - (may) avoid transient states 690 // - works around Flash content which expects to have the size updated 691 // synchronously. 692 // See https://crbug.com/361408 693 if (fullscreen) { 694 restored_bounds_ = bounds_; 695 const gfx::Display display = 696 gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window()); 697 bounds_ = display.bounds(); 698 } else { 699 bounds_ = restored_bounds_; 700 } 701 OnHostMoved(bounds_.origin()); 702 OnHostResized(bounds_.size()); 703 704 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) { 705 Relayout(); 706 ResetWindowRegion(); 707 } 708 // Else: the widget will be relaid out either when the window bounds change or 709 // when |xwindow_|'s fullscreen state changes. 710 } 711 712 bool DesktopWindowTreeHostX11::IsFullscreen() const { 713 return is_fullscreen_; 714 } 715 716 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) { 717 // X server opacity is in terms of 32 bit unsigned int space, and counts from 718 // the opposite direction. 719 // XChangeProperty() expects "cardinality" to be long. 720 unsigned long cardinality = opacity * 0x1010101; 721 722 if (cardinality == 0xffffffff) { 723 XDeleteProperty(xdisplay_, xwindow_, 724 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY")); 725 } else { 726 XChangeProperty(xdisplay_, xwindow_, 727 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"), 728 XA_CARDINAL, 32, 729 PropModeReplace, 730 reinterpret_cast<unsigned char*>(&cardinality), 1); 731 } 732 } 733 734 void DesktopWindowTreeHostX11::SetWindowIcons( 735 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { 736 // TODO(erg): The way we handle icons across different versions of chrome 737 // could be substantially improved. The Windows version does its own thing 738 // and only sometimes comes down this code path. The icon stuff in 739 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard 740 // coded to be given two images instead of an arbitrary collection of images 741 // so that we can pass to the WM. 742 // 743 // All of this could be made much, much better. 744 std::vector<unsigned long> data; 745 746 if (window_icon.HasRepresentation(1.0f)) 747 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data); 748 749 if (app_icon.HasRepresentation(1.0f)) 750 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data); 751 752 if (data.empty()) 753 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON")); 754 else 755 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data); 756 } 757 758 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) { 759 switch (modal_type) { 760 case ui::MODAL_TYPE_NONE: 761 break; 762 default: 763 // TODO(erg): Figure out under what situations |modal_type| isn't 764 // none. The comment in desktop_native_widget_aura.cc suggests that this 765 // is rare. 766 NOTIMPLEMENTED(); 767 } 768 } 769 770 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) { 771 if (urgency_hint_set_ == flash_frame) 772 return; 773 774 XWMHints* hints = XGetWMHints(xdisplay_, xwindow_); 775 if (!hints) { 776 // The window hasn't had its hints set yet. 777 hints = XAllocWMHints(); 778 } 779 780 if (flash_frame) 781 hints->flags |= XUrgencyHint; 782 else 783 hints->flags &= ~XUrgencyHint; 784 785 XSetWMHints(xdisplay_, xwindow_, hints); 786 XFree(hints); 787 788 urgency_hint_set_ = flash_frame; 789 } 790 791 void DesktopWindowTreeHostX11::OnRootViewLayout() const { 792 if (!window_mapped_) 793 return; 794 795 XSizeHints hints; 796 long supplied_return; 797 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return); 798 799 gfx::Size minimum = native_widget_delegate_->GetMinimumSize(); 800 if (minimum.IsEmpty()) { 801 hints.flags &= ~PMinSize; 802 } else { 803 hints.flags |= PMinSize; 804 hints.min_width = minimum.width(); 805 hints.min_height = minimum.height(); 806 } 807 808 gfx::Size maximum = native_widget_delegate_->GetMaximumSize(); 809 if (maximum.IsEmpty()) { 810 hints.flags &= ~PMaxSize; 811 } else { 812 hints.flags |= PMaxSize; 813 hints.max_width = maximum.width(); 814 hints.max_height = maximum.height(); 815 } 816 817 XSetWMNormalHints(xdisplay_, xwindow_, &hints); 818 } 819 820 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() { 821 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus(); 822 } 823 824 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() { 825 if (xwindow_) { 826 x11_capture_.reset(); 827 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur(); 828 } 829 } 830 831 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const { 832 return false; 833 } 834 835 bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const { 836 return false; 837 } 838 839 //////////////////////////////////////////////////////////////////////////////// 840 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation: 841 842 ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() { 843 return this; 844 } 845 846 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() { 847 return xwindow_; 848 } 849 850 void DesktopWindowTreeHostX11::Show() { 851 ShowWindowWithState(ui::SHOW_STATE_NORMAL); 852 native_widget_delegate_->OnNativeWidgetVisibilityChanged(true); 853 } 854 855 void DesktopWindowTreeHostX11::Hide() { 856 if (window_mapped_) { 857 XWithdrawWindow(xdisplay_, xwindow_, 0); 858 window_mapped_ = false; 859 } 860 native_widget_delegate_->OnNativeWidgetVisibilityChanged(false); 861 } 862 863 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const { 864 return bounds_; 865 } 866 867 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) { 868 bool origin_changed = bounds_.origin() != bounds.origin(); 869 bool size_changed = bounds_.size() != bounds.size(); 870 XWindowChanges changes = {0}; 871 unsigned value_mask = 0; 872 873 if (size_changed) { 874 // X11 will send an XError at our process if have a 0 sized window. 875 DCHECK_GT(bounds.width(), 0); 876 DCHECK_GT(bounds.height(), 0); 877 878 changes.width = bounds.width(); 879 changes.height = bounds.height(); 880 value_mask |= CWHeight | CWWidth; 881 } 882 883 if (origin_changed) { 884 changes.x = bounds.x(); 885 changes.y = bounds.y(); 886 value_mask |= CWX | CWY; 887 } 888 if (value_mask) 889 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); 890 891 // Assume that the resize will go through as requested, which should be the 892 // case if we're running without a window manager. If there's a window 893 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a 894 // (possibly synthetic) ConfigureNotify about the actual size and correct 895 // |bounds_| later. 896 bounds_ = bounds; 897 898 if (origin_changed) 899 native_widget_delegate_->AsWidget()->OnNativeWidgetMove(); 900 if (size_changed) { 901 OnHostResized(bounds.size()); 902 ResetWindowRegion(); 903 } 904 } 905 906 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const { 907 return bounds_.origin(); 908 } 909 910 void DesktopWindowTreeHostX11::SetCapture() { 911 // This is vaguely based on the old NativeWidgetGtk implementation. 912 // 913 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map 914 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of 915 // a grab that wasn't the X11 pointer grab, but was instead a manual 916 // redirection of the event. (You need to drop into GDK if you want to 917 // perform a raw X11 grab). 918 919 if (g_current_capture) 920 g_current_capture->OnCaptureReleased(); 921 922 g_current_capture = this; 923 x11_capture_.reset(new X11ScopedCapture(xwindow_)); 924 } 925 926 void DesktopWindowTreeHostX11::ReleaseCapture() { 927 if (g_current_capture == this) 928 g_current_capture->OnCaptureReleased(); 929 } 930 931 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) { 932 XDefineCursor(xdisplay_, xwindow_, cursor.platform()); 933 } 934 935 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) { 936 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, 937 bounds_.x() + location.x(), bounds_.y() + location.y()); 938 } 939 940 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) { 941 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do 942 // the same tap-to-click disabling here that chromeos does. 943 } 944 945 void DesktopWindowTreeHostX11::PostNativeEvent( 946 const base::NativeEvent& native_event) { 947 DCHECK(xwindow_); 948 DCHECK(xdisplay_); 949 XEvent xevent = *native_event; 950 xevent.xany.display = xdisplay_; 951 xevent.xany.window = xwindow_; 952 953 switch (xevent.type) { 954 case EnterNotify: 955 case LeaveNotify: 956 case MotionNotify: 957 case KeyPress: 958 case KeyRelease: 959 case ButtonPress: 960 case ButtonRelease: { 961 // The fields used below are in the same place for all of events 962 // above. Using xmotion from XEvent's unions to avoid repeating 963 // the code. 964 xevent.xmotion.root = x_root_window_; 965 xevent.xmotion.time = CurrentTime; 966 967 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); 968 ConvertPointToNativeScreen(&point); 969 xevent.xmotion.x_root = point.x(); 970 xevent.xmotion.y_root = point.y(); 971 } 972 default: 973 break; 974 } 975 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); 976 } 977 978 void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged( 979 float device_scale_factor) { 980 } 981 982 //////////////////////////////////////////////////////////////////////////////// 983 // DesktopWindowTreeHostX11, ui::EventSource implementation: 984 985 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() { 986 return dispatcher(); 987 } 988 989 //////////////////////////////////////////////////////////////////////////////// 990 // DesktopWindowTreeHostX11, private: 991 992 void DesktopWindowTreeHostX11::InitX11Window( 993 const Widget::InitParams& params) { 994 unsigned long attribute_mask = CWBackPixmap; 995 XSetWindowAttributes swa; 996 memset(&swa, 0, sizeof(swa)); 997 swa.background_pixmap = None; 998 999 ::Atom window_type; 1000 switch (params.type) { 1001 case Widget::InitParams::TYPE_MENU: 1002 swa.override_redirect = True; 1003 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU"); 1004 break; 1005 case Widget::InitParams::TYPE_TOOLTIP: 1006 swa.override_redirect = True; 1007 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP"); 1008 break; 1009 case Widget::InitParams::TYPE_POPUP: 1010 swa.override_redirect = True; 1011 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION"); 1012 break; 1013 case Widget::InitParams::TYPE_DRAG: 1014 swa.override_redirect = True; 1015 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND"); 1016 break; 1017 default: 1018 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL"); 1019 break; 1020 } 1021 if (swa.override_redirect) 1022 attribute_mask |= CWOverrideRedirect; 1023 1024 // Detect whether we're running inside a compositing manager. If so, try to 1025 // use the ARGB visual. Otherwise, just use our parent's visual. 1026 Visual* visual = CopyFromParent; 1027 int depth = CopyFromParent; 1028 if (CommandLine::ForCurrentProcess()->HasSwitch( 1029 switches::kEnableTransparentVisuals) && 1030 XGetSelectionOwner(xdisplay_, 1031 atom_cache_.GetAtom("_NET_WM_CM_S0")) != None) { 1032 Visual* rgba_visual = GetARGBVisual(); 1033 if (rgba_visual) { 1034 visual = rgba_visual; 1035 depth = 32; 1036 1037 attribute_mask |= CWColormap; 1038 swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual, 1039 AllocNone); 1040 1041 // x.org will BadMatch if we don't set a border when the depth isn't the 1042 // same as the parent depth. 1043 attribute_mask |= CWBorderPixel; 1044 swa.border_pixel = 0; 1045 1046 use_argb_visual_ = true; 1047 } 1048 } 1049 1050 bounds_ = params.bounds; 1051 xwindow_ = XCreateWindow( 1052 xdisplay_, x_root_window_, 1053 bounds_.x(), bounds_.y(), 1054 bounds_.width(), bounds_.height(), 1055 0, // border width 1056 depth, 1057 InputOutput, 1058 visual, 1059 attribute_mask, 1060 &swa); 1061 if (ui::PlatformEventSource::GetInstance()) 1062 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); 1063 open_windows().push_back(xwindow_); 1064 1065 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL(). 1066 1067 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | 1068 KeyPressMask | KeyReleaseMask | 1069 EnterWindowMask | LeaveWindowMask | 1070 ExposureMask | VisibilityChangeMask | 1071 StructureNotifyMask | PropertyChangeMask | 1072 PointerMotionMask; 1073 XSelectInput(xdisplay_, xwindow_, event_mask); 1074 XFlush(xdisplay_); 1075 1076 if (ui::IsXInput2Available()) 1077 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); 1078 1079 // TODO(erg): We currently only request window deletion events. We also 1080 // should listen for activation events and anything else that GTK+ listens 1081 // for, and do something useful. 1082 ::Atom protocols[2]; 1083 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); 1084 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); 1085 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); 1086 1087 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with 1088 // the desktop environment. 1089 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); 1090 1091 // Likewise, the X server needs to know this window's pid so it knows which 1092 // program to kill if the window hangs. 1093 // XChangeProperty() expects "pid" to be long. 1094 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long); 1095 long pid = getpid(); 1096 XChangeProperty(xdisplay_, 1097 xwindow_, 1098 atom_cache_.GetAtom("_NET_WM_PID"), 1099 XA_CARDINAL, 1100 32, 1101 PropModeReplace, 1102 reinterpret_cast<unsigned char*>(&pid), 1); 1103 1104 XChangeProperty(xdisplay_, 1105 xwindow_, 1106 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"), 1107 XA_ATOM, 1108 32, 1109 PropModeReplace, 1110 reinterpret_cast<unsigned char*>(&window_type), 1); 1111 1112 // List of window state properties (_NET_WM_STATE) to set, if any. 1113 std::vector< ::Atom> state_atom_list; 1114 1115 // Remove popup windows from taskbar unless overridden. 1116 if ((params.type == Widget::InitParams::TYPE_POPUP || 1117 params.type == Widget::InitParams::TYPE_BUBBLE) && 1118 !params.force_show_in_taskbar) { 1119 state_atom_list.push_back( 1120 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); 1121 } 1122 1123 // If the window should stay on top of other windows, add the 1124 // _NET_WM_STATE_ABOVE property. 1125 is_always_on_top_ = params.keep_on_top; 1126 if (is_always_on_top_) 1127 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE")); 1128 1129 if (params.visible_on_all_workspaces) { 1130 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY")); 1131 ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops); 1132 } 1133 1134 // Setting _NET_WM_STATE by sending a message to the root_window (with 1135 // SetWMSpecState) has no effect here since the window has not yet been 1136 // mapped. So we manually change the state. 1137 if (!state_atom_list.empty()) { 1138 ui::SetAtomArrayProperty(xwindow_, 1139 "_NET_WM_STATE", 1140 "ATOM", 1141 state_atom_list); 1142 } 1143 1144 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) { 1145 ui::SetWindowClassHint( 1146 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class); 1147 } 1148 if (!params.wm_role_name.empty() || 1149 params.type == Widget::InitParams::TYPE_POPUP) { 1150 const char kX11WindowRolePopup[] = "popup"; 1151 ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ? 1152 std::string(kX11WindowRolePopup) : params.wm_role_name); 1153 } 1154 1155 if (params.remove_standard_frame) { 1156 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force 1157 // fullscreen on the window when it matches the desktop size. 1158 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_, 1159 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED); 1160 } 1161 1162 // If we have a parent, record the parent/child relationship. We use this 1163 // data during destruction to make sure that when we try to close a parent 1164 // window, we also destroy all child windows. 1165 if (params.parent && params.parent->GetHost()) { 1166 XID parent_xid = 1167 params.parent->GetHost()->GetAcceleratedWidget(); 1168 window_parent_ = GetHostForXID(parent_xid); 1169 DCHECK(window_parent_); 1170 window_parent_->window_children_.insert(this); 1171 } 1172 1173 // If we have a delegate which is providing a default window icon, use that 1174 // icon. 1175 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ? 1176 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL; 1177 if (window_icon) { 1178 SetWindowIcons(gfx::ImageSkia(), *window_icon); 1179 } 1180 CreateCompositor(GetAcceleratedWidget()); 1181 } 1182 1183 void DesktopWindowTreeHostX11::OnWMStateUpdated() { 1184 std::vector< ::Atom> atom_list; 1185 if (!ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) 1186 return; 1187 1188 bool was_minimized = IsMinimized(); 1189 1190 window_properties_.clear(); 1191 std::copy(atom_list.begin(), atom_list.end(), 1192 inserter(window_properties_, window_properties_.begin())); 1193 1194 // Propagate the window minimization information to the content window, so 1195 // the render side can update its visibility properly. OnWMStateUpdated() is 1196 // called by PropertyNofify event from DispatchEvent() when the browser is 1197 // minimized or shown from minimized state. On Windows, this is realized by 1198 // calling OnHostResized() with an empty size. In particular, 1199 // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the 1200 // window is minimized. On Linux, returning empty size in GetBounds() or 1201 // SetBounds() does not work. 1202 bool is_minimized = IsMinimized(); 1203 if (is_minimized != was_minimized) { 1204 if (is_minimized) 1205 content_window_->Hide(); 1206 else 1207 content_window_->Show(); 1208 } 1209 1210 if (restored_bounds_.IsEmpty()) { 1211 DCHECK(!IsFullscreen()); 1212 if (IsMaximized()) { 1213 // The request that we become maximized originated from a different 1214 // process. |bounds_| already contains our maximized bounds. Do a best 1215 // effort attempt to get restored bounds by setting it to our previously 1216 // set bounds (and if we get this wrong, we aren't any worse off since 1217 // we'd otherwise be returning our maximized bounds). 1218 restored_bounds_ = previous_bounds_; 1219 } 1220 } else if (!IsMaximized() && !IsFullscreen()) { 1221 // If we have restored bounds, but WM_STATE no longer claims to be 1222 // maximized or fullscreen, we should clear our restored bounds. 1223 restored_bounds_ = gfx::Rect(); 1224 } 1225 1226 // Ignore requests by the window manager to enter or exit fullscreen (e.g. as 1227 // a result of pressing a window manager accelerator key). Chrome does not 1228 // handle window manager initiated fullscreen. In particular, Chrome needs to 1229 // do preprocessing before the x window's fullscreen state is toggled. 1230 1231 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE"); 1232 1233 // Now that we have different window properties, we may need to relayout the 1234 // window. (The windows code doesn't need this because their window change is 1235 // synchronous.) 1236 Relayout(); 1237 ResetWindowRegion(); 1238 } 1239 1240 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() { 1241 std::vector<int> insets; 1242 if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && 1243 insets.size() == 4) { 1244 // |insets| are returned in the order: [left, right, top, bottom]. 1245 native_window_frame_borders_ = gfx::Insets( 1246 insets[2], 1247 insets[0], 1248 insets[3], 1249 insets[1]); 1250 } else { 1251 native_window_frame_borders_ = gfx::Insets(); 1252 } 1253 } 1254 1255 void DesktopWindowTreeHostX11::UpdateWMUserTime( 1256 const ui::PlatformEvent& event) { 1257 if (!IsActive()) 1258 return; 1259 1260 ui::EventType type = ui::EventTypeFromNative(event); 1261 if (type == ui::ET_MOUSE_PRESSED || 1262 type == ui::ET_KEY_PRESSED || 1263 type == ui::ET_TOUCH_PRESSED) { 1264 unsigned long wm_user_time_ms = static_cast<unsigned long>( 1265 ui::EventTimeFromNative(event).InMilliseconds()); 1266 XChangeProperty(xdisplay_, 1267 xwindow_, 1268 atom_cache_.GetAtom("_NET_WM_USER_TIME"), 1269 XA_CARDINAL, 1270 32, 1271 PropModeReplace, 1272 reinterpret_cast<const unsigned char *>(&wm_user_time_ms), 1273 1); 1274 X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms); 1275 } 1276 } 1277 1278 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled, 1279 ::Atom state1, 1280 ::Atom state2) { 1281 XEvent xclient; 1282 memset(&xclient, 0, sizeof(xclient)); 1283 xclient.type = ClientMessage; 1284 xclient.xclient.window = xwindow_; 1285 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE"); 1286 xclient.xclient.format = 32; 1287 xclient.xclient.data.l[0] = 1288 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE; 1289 xclient.xclient.data.l[1] = state1; 1290 xclient.xclient.data.l[2] = state2; 1291 xclient.xclient.data.l[3] = 1; 1292 xclient.xclient.data.l[4] = 0; 1293 1294 XSendEvent(xdisplay_, x_root_window_, False, 1295 SubstructureRedirectMask | SubstructureNotifyMask, 1296 &xclient); 1297 } 1298 1299 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const { 1300 return window_properties_.find(atom_cache_.GetAtom(property)) != 1301 window_properties_.end(); 1302 } 1303 1304 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) { 1305 use_native_frame_ = use_native_frame; 1306 ui::SetUseOSWindowFrame(xwindow_, use_native_frame); 1307 ResetWindowRegion(); 1308 } 1309 1310 void DesktopWindowTreeHostX11::OnCaptureReleased() { 1311 x11_capture_.reset(); 1312 g_current_capture = NULL; 1313 OnHostLostWindowCapture(); 1314 native_widget_delegate_->OnMouseCaptureLost(); 1315 } 1316 1317 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { 1318 // In Windows, the native events sent to chrome are separated into client 1319 // and non-client versions of events, which we record on our LocatedEvent 1320 // structures. On X11, we emulate the concept of non-client. Before we pass 1321 // this event to the cross platform event handling framework, we need to 1322 // make sure it is appropriately marked as non-client if it's in the non 1323 // client area, or otherwise, we can get into a state where the a window is 1324 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc 1325 // despite the mouse button being released. 1326 // 1327 // We can't do this later in the dispatch process because we share that 1328 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on 1329 // events, since ash doesn't expect this bit to be set, because it's never 1330 // been set before. (This works on ash on Windows because none of the mouse 1331 // events on the ash desktop are clicking in what Windows considers to be a 1332 // non client area.) Likewise, we won't want to do the following in any 1333 // WindowTreeHost that hosts ash. 1334 if (content_window_ && content_window_->delegate()) { 1335 int flags = event->flags(); 1336 int hit_test_code = 1337 content_window_->delegate()->GetNonClientComponent(event->location()); 1338 if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE) 1339 flags |= ui::EF_IS_NON_CLIENT; 1340 event->set_flags(flags); 1341 } 1342 1343 // While we unset the urgency hint when we gain focus, we also must remove it 1344 // on mouse clicks because we can call FlashFrame() on an active window. 1345 if (event->IsAnyButton() || event->IsMouseWheelEvent()) 1346 FlashFrame(false); 1347 1348 if (!g_current_capture || g_current_capture == this) { 1349 SendEventToProcessor(event); 1350 } else { 1351 // Another DesktopWindowTreeHostX11 has installed itself as 1352 // capture. Translate the event's location and dispatch to the other. 1353 event->ConvertLocationToTarget(window(), g_current_capture->window()); 1354 g_current_capture->SendEventToProcessor(event); 1355 } 1356 } 1357 1358 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) { 1359 if (g_current_capture && g_current_capture != this && 1360 event->type() == ui::ET_TOUCH_PRESSED) { 1361 event->ConvertLocationToTarget(window(), g_current_capture->window()); 1362 g_current_capture->SendEventToProcessor(event); 1363 } else { 1364 SendEventToProcessor(event); 1365 } 1366 } 1367 1368 void DesktopWindowTreeHostX11::ResetWindowRegion() { 1369 // If a custom window shape was supplied then apply it. 1370 if (custom_window_shape_) { 1371 XShapeCombineRegion( 1372 xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false); 1373 return; 1374 } 1375 1376 if (window_shape_) 1377 XDestroyRegion(window_shape_); 1378 window_shape_ = NULL; 1379 1380 if (!IsMaximized() && !IsFullscreen()) { 1381 gfx::Path window_mask; 1382 views::Widget* widget = native_widget_delegate_->AsWidget(); 1383 if (widget->non_client_view()) { 1384 // Some frame views define a custom (non-rectangular) window mask. If 1385 // so, use it to define the window shape. If not, fall through. 1386 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask); 1387 if (window_mask.countPoints() > 0) { 1388 window_shape_ = gfx::CreateRegionFromSkPath(window_mask); 1389 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 1390 0, 0, window_shape_, false); 1391 return; 1392 } 1393 } 1394 } 1395 1396 // If we didn't set the shape for any reason, reset the shaping information. 1397 // How this is done depends on the border style, due to quirks and bugs in 1398 // various window managers. 1399 if (ShouldUseNativeFrame()) { 1400 // If the window has system borders, the mask must be set to null (not a 1401 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will 1402 // not put borders on a window with a custom shape. 1403 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet); 1404 } else { 1405 // Conversely, if the window does not have system borders, the mask must be 1406 // manually set to a rectangle that covers the whole window (not null). This 1407 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null 1408 // shape causes the hint to disable system borders to be ignored (resulting 1409 // in a double border). 1410 XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()), 1411 static_cast<unsigned short>(bounds_.height())}; 1412 XShapeCombineRectangles( 1413 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded); 1414 } 1415 } 1416 1417 void DesktopWindowTreeHostX11::SerializeImageRepresentation( 1418 const gfx::ImageSkiaRep& rep, 1419 std::vector<unsigned long>* data) { 1420 int width = rep.GetWidth(); 1421 data->push_back(width); 1422 1423 int height = rep.GetHeight(); 1424 data->push_back(height); 1425 1426 const SkBitmap& bitmap = rep.sk_bitmap(); 1427 SkAutoLockPixels locker(bitmap); 1428 1429 for (int y = 0; y < height; ++y) 1430 for (int x = 0; x < width; ++x) 1431 data->push_back(bitmap.getColor(x, y)); 1432 } 1433 1434 Visual* DesktopWindowTreeHostX11::GetARGBVisual() { 1435 XVisualInfo visual_template; 1436 visual_template.screen = 0; 1437 Visual* to_return = NULL; 1438 1439 int visuals_len; 1440 XVisualInfo* visual_list = XGetVisualInfo(xdisplay_, 1441 VisualScreenMask, 1442 &visual_template, &visuals_len); 1443 for (int i = 0; i < visuals_len; ++i) { 1444 // Why support only 8888 ARGB? Because it's all that GTK+ supports. In 1445 // gdkvisual-x11.cc, they look for this specific visual and use it for all 1446 // their alpha channel using needs. 1447 // 1448 // TODO(erg): While the following does find a valid visual, some GL drivers 1449 // don't believe that this has an alpha channel. According to marcheu@, 1450 // this should work on open source driver though. (It doesn't work with 1451 // NVidia's binaries currently.) http://crbug.com/369209 1452 if (visual_list[i].depth == 32 && 1453 visual_list[i].visual->red_mask == 0xff0000 && 1454 visual_list[i].visual->green_mask == 0x00ff00 && 1455 visual_list[i].visual->blue_mask == 0x0000ff) { 1456 to_return = visual_list[i].visual; 1457 break; 1458 } 1459 } 1460 1461 if (visual_list) 1462 XFree(visual_list); 1463 1464 return to_return; 1465 } 1466 1467 std::list<XID>& DesktopWindowTreeHostX11::open_windows() { 1468 if (!open_windows_) 1469 open_windows_ = new std::list<XID>(); 1470 return *open_windows_; 1471 } 1472 1473 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) { 1474 if (show_state != ui::SHOW_STATE_DEFAULT && 1475 show_state != ui::SHOW_STATE_NORMAL && 1476 show_state != ui::SHOW_STATE_INACTIVE) { 1477 // It will behave like SHOW_STATE_NORMAL. 1478 NOTIMPLEMENTED(); 1479 } 1480 1481 // Before we map the window, set size hints. Otherwise, some window managers 1482 // will ignore toplevel XMoveWindow commands. 1483 XSizeHints size_hints; 1484 size_hints.flags = PPosition; 1485 size_hints.x = bounds_.x(); 1486 size_hints.y = bounds_.y(); 1487 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); 1488 1489 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window 1490 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g. 1491 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html 1492 unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ? 1493 0 : X11DesktopHandler::get()->wm_user_time_ms(); 1494 if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) { 1495 XChangeProperty(xdisplay_, 1496 xwindow_, 1497 atom_cache_.GetAtom("_NET_WM_USER_TIME"), 1498 XA_CARDINAL, 1499 32, 1500 PropModeReplace, 1501 reinterpret_cast<const unsigned char *>(&wm_user_time_ms), 1502 1); 1503 } 1504 1505 XMapWindow(xdisplay_, xwindow_); 1506 1507 // We now block until our window is mapped. Some X11 APIs will crash and 1508 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is 1509 // asynchronous. 1510 if (ui::X11EventSource::GetInstance()) 1511 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_); 1512 window_mapped_ = true; 1513 } 1514 1515 void DesktopWindowTreeHostX11::SetWindowTransparency() { 1516 compositor()->SetHostHasTransparentBackground(use_argb_visual_); 1517 window()->SetTransparent(use_argb_visual_); 1518 content_window_->SetTransparent(use_argb_visual_); 1519 } 1520 1521 void DesktopWindowTreeHostX11::Relayout() { 1522 Widget* widget = native_widget_delegate_->AsWidget(); 1523 NonClientView* non_client_view = widget->non_client_view(); 1524 // non_client_view may be NULL, especially during creation. 1525 if (non_client_view) { 1526 non_client_view->client_view()->InvalidateLayout(); 1527 non_client_view->InvalidateLayout(); 1528 } 1529 widget->GetRootView()->Layout(); 1530 } 1531 1532 //////////////////////////////////////////////////////////////////////////////// 1533 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation: 1534 1535 bool DesktopWindowTreeHostX11::CanDispatchEvent( 1536 const ui::PlatformEvent& event) { 1537 return event->xany.window == xwindow_ || 1538 (event->type == GenericEvent && 1539 static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_); 1540 } 1541 1542 uint32_t DesktopWindowTreeHostX11::DispatchEvent( 1543 const ui::PlatformEvent& event) { 1544 XEvent* xev = event; 1545 1546 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch", 1547 "event->type", event->type); 1548 1549 UpdateWMUserTime(event); 1550 1551 // May want to factor CheckXEventForConsistency(xev); into a common location 1552 // since it is called here. 1553 switch (xev->type) { 1554 case EnterNotify: 1555 case LeaveNotify: { 1556 // Ignore EventNotify and LeaveNotify events from children of |xwindow_|. 1557 // NativeViewGLSurfaceGLX adds a child to |xwindow_|. 1558 // TODO(pkotwicz|tdanderson): Figure out whether the suppression is 1559 // necessary. crbug.com/385716 1560 if (xev->xcrossing.detail == NotifyInferior) 1561 break; 1562 1563 ui::MouseEvent mouse_event(xev); 1564 DispatchMouseEvent(&mouse_event); 1565 break; 1566 } 1567 case Expose: { 1568 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, 1569 xev->xexpose.width, xev->xexpose.height); 1570 compositor()->ScheduleRedrawRect(damage_rect); 1571 break; 1572 } 1573 case KeyPress: { 1574 ui::KeyEvent keydown_event(xev, false); 1575 SendEventToProcessor(&keydown_event); 1576 break; 1577 } 1578 case KeyRelease: { 1579 ui::KeyEvent keyup_event(xev, false); 1580 SendEventToProcessor(&keyup_event); 1581 break; 1582 } 1583 case ButtonPress: 1584 case ButtonRelease: { 1585 ui::EventType event_type = ui::EventTypeFromNative(xev); 1586 switch (event_type) { 1587 case ui::ET_MOUSEWHEEL: { 1588 ui::MouseWheelEvent mouseev(xev); 1589 DispatchMouseEvent(&mouseev); 1590 break; 1591 } 1592 case ui::ET_MOUSE_PRESSED: 1593 case ui::ET_MOUSE_RELEASED: { 1594 ui::MouseEvent mouseev(xev); 1595 DispatchMouseEvent(&mouseev); 1596 break; 1597 } 1598 case ui::ET_UNKNOWN: 1599 // No event is created for X11-release events for mouse-wheel buttons. 1600 break; 1601 default: 1602 NOTREACHED() << event_type; 1603 } 1604 break; 1605 } 1606 case FocusOut: 1607 if (xev->xfocus.mode != NotifyGrab) { 1608 ReleaseCapture(); 1609 OnHostLostWindowCapture(); 1610 X11DesktopHandler::get()->ProcessXEvent(xev); 1611 } else { 1612 dispatcher()->OnHostLostMouseGrab(); 1613 } 1614 break; 1615 case FocusIn: 1616 X11DesktopHandler::get()->ProcessXEvent(xev); 1617 break; 1618 case ConfigureNotify: { 1619 DCHECK_EQ(xwindow_, xev->xconfigure.window); 1620 DCHECK_EQ(xwindow_, xev->xconfigure.event); 1621 // It's possible that the X window may be resized by some other means than 1622 // from within aura (e.g. the X window manager can change the size). Make 1623 // sure the root window size is maintained properly. 1624 int translated_x = xev->xconfigure.x; 1625 int translated_y = xev->xconfigure.y; 1626 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) { 1627 Window unused; 1628 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, 1629 0, 0, &translated_x, &translated_y, &unused); 1630 } 1631 gfx::Rect bounds(translated_x, translated_y, 1632 xev->xconfigure.width, xev->xconfigure.height); 1633 bool size_changed = bounds_.size() != bounds.size(); 1634 bool origin_changed = bounds_.origin() != bounds.origin(); 1635 previous_bounds_ = bounds_; 1636 bounds_ = bounds; 1637 1638 if (origin_changed) 1639 OnHostMoved(bounds_.origin()); 1640 1641 if (size_changed) { 1642 delayed_resize_task_.Reset(base::Bind( 1643 &DesktopWindowTreeHostX11::DelayedResize, 1644 close_widget_factory_.GetWeakPtr(), 1645 bounds.size())); 1646 base::MessageLoop::current()->PostTask( 1647 FROM_HERE, delayed_resize_task_.callback()); 1648 } 1649 break; 1650 } 1651 case GenericEvent: { 1652 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 1653 if (!factory->ShouldProcessXI2Event(xev)) 1654 break; 1655 1656 ui::EventType type = ui::EventTypeFromNative(xev); 1657 XEvent last_event; 1658 int num_coalesced = 0; 1659 1660 switch (type) { 1661 case ui::ET_TOUCH_MOVED: 1662 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); 1663 if (num_coalesced > 0) 1664 xev = &last_event; 1665 // fallthrough 1666 case ui::ET_TOUCH_PRESSED: 1667 case ui::ET_TOUCH_RELEASED: { 1668 ui::TouchEvent touchev(xev); 1669 DispatchTouchEvent(&touchev); 1670 break; 1671 } 1672 case ui::ET_MOUSE_MOVED: 1673 case ui::ET_MOUSE_DRAGGED: 1674 case ui::ET_MOUSE_PRESSED: 1675 case ui::ET_MOUSE_RELEASED: 1676 case ui::ET_MOUSE_ENTERED: 1677 case ui::ET_MOUSE_EXITED: { 1678 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { 1679 // If this is a motion event, we want to coalesce all pending motion 1680 // events that are at the top of the queue. 1681 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); 1682 if (num_coalesced > 0) 1683 xev = &last_event; 1684 } 1685 ui::MouseEvent mouseev(xev); 1686 DispatchMouseEvent(&mouseev); 1687 break; 1688 } 1689 case ui::ET_MOUSEWHEEL: { 1690 ui::MouseWheelEvent mouseev(xev); 1691 DispatchMouseEvent(&mouseev); 1692 break; 1693 } 1694 case ui::ET_SCROLL_FLING_START: 1695 case ui::ET_SCROLL_FLING_CANCEL: 1696 case ui::ET_SCROLL: { 1697 ui::ScrollEvent scrollev(xev); 1698 SendEventToProcessor(&scrollev); 1699 break; 1700 } 1701 case ui::ET_UNKNOWN: 1702 break; 1703 default: 1704 NOTREACHED(); 1705 } 1706 1707 // If we coalesced an event we need to free its cookie. 1708 if (num_coalesced > 0) 1709 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); 1710 break; 1711 } 1712 case MapNotify: { 1713 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, 1714 observer_list_, 1715 OnWindowMapped(xwindow_)); 1716 break; 1717 } 1718 case UnmapNotify: { 1719 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, 1720 observer_list_, 1721 OnWindowUnmapped(xwindow_)); 1722 break; 1723 } 1724 case ClientMessage: { 1725 Atom message_type = xev->xclient.message_type; 1726 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) { 1727 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]); 1728 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { 1729 // We have received a close message from the window manager. 1730 OnHostCloseRequested(); 1731 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) { 1732 XEvent reply_event = *xev; 1733 reply_event.xclient.window = x_root_window_; 1734 1735 XSendEvent(xdisplay_, 1736 reply_event.xclient.window, 1737 False, 1738 SubstructureRedirectMask | SubstructureNotifyMask, 1739 &reply_event); 1740 } 1741 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) { 1742 drag_drop_client_->OnXdndEnter(xev->xclient); 1743 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) { 1744 drag_drop_client_->OnXdndLeave(xev->xclient); 1745 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) { 1746 drag_drop_client_->OnXdndPosition(xev->xclient); 1747 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) { 1748 drag_drop_client_->OnXdndStatus(xev->xclient); 1749 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) { 1750 drag_drop_client_->OnXdndFinished(xev->xclient); 1751 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) { 1752 drag_drop_client_->OnXdndDrop(xev->xclient); 1753 } 1754 break; 1755 } 1756 case MappingNotify: { 1757 switch (xev->xmapping.request) { 1758 case MappingModifier: 1759 case MappingKeyboard: 1760 XRefreshKeyboardMapping(&xev->xmapping); 1761 break; 1762 case MappingPointer: 1763 ui::DeviceDataManager::GetInstance()->UpdateButtonMap(); 1764 break; 1765 default: 1766 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; 1767 break; 1768 } 1769 break; 1770 } 1771 case MotionNotify: { 1772 // Discard all but the most recent motion event that targets the same 1773 // window with unchanged state. 1774 XEvent last_event; 1775 while (XPending(xev->xany.display)) { 1776 XEvent next_event; 1777 XPeekEvent(xev->xany.display, &next_event); 1778 if (next_event.type == MotionNotify && 1779 next_event.xmotion.window == xev->xmotion.window && 1780 next_event.xmotion.subwindow == xev->xmotion.subwindow && 1781 next_event.xmotion.state == xev->xmotion.state) { 1782 XNextEvent(xev->xany.display, &last_event); 1783 xev = &last_event; 1784 } else { 1785 break; 1786 } 1787 } 1788 1789 ui::MouseEvent mouseev(xev); 1790 DispatchMouseEvent(&mouseev); 1791 break; 1792 } 1793 case PropertyNotify: { 1794 ::Atom changed_atom = xev->xproperty.atom; 1795 if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE")) 1796 OnWMStateUpdated(); 1797 else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS")) 1798 OnFrameExtentsUpdated(); 1799 break; 1800 } 1801 case SelectionNotify: { 1802 drag_drop_client_->OnSelectionNotify(xev->xselection); 1803 break; 1804 } 1805 } 1806 return ui::POST_DISPATCH_STOP_PROPAGATION; 1807 } 1808 1809 void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size) { 1810 OnHostResized(size); 1811 ResetWindowRegion(); 1812 delayed_resize_task_.Cancel(); 1813 } 1814 1815 //////////////////////////////////////////////////////////////////////////////// 1816 // DesktopWindowTreeHost, public: 1817 1818 // static 1819 DesktopWindowTreeHost* DesktopWindowTreeHost::Create( 1820 internal::NativeWidgetDelegate* native_widget_delegate, 1821 DesktopNativeWidgetAura* desktop_native_widget_aura) { 1822 return new DesktopWindowTreeHostX11(native_widget_delegate, 1823 desktop_native_widget_aura); 1824 } 1825 1826 // static 1827 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) { 1828 const views::LinuxUI* linux_ui = views::LinuxUI::instance(); 1829 if (linux_ui) { 1830 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window); 1831 if (native_theme) 1832 return native_theme; 1833 } 1834 1835 return ui::NativeTheme::instance(); 1836 } 1837 1838 } // namespace views 1839