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