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.
5 #include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
7 #include <X11/extensions/shape.h>
8 #include <X11/extensions/XInput2.h>
10 #include <X11/Xregion.h>
11 #include <X11/Xutil.h>
13 #include "base/basictypes.h"
14 #include "base/message_loop/message_pump_x11.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "third_party/skia/include/core/SkPath.h"
18 #include "ui/aura/client/cursor_client.h"
19 #include "ui/aura/client/focus_client.h"
20 #include "ui/aura/client/user_action_client.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/window_property.h"
23 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
24 #include "ui/base/x/x11_util.h"
25 #include "ui/events/event_utils.h"
26 #include "ui/events/x/device_data_manager.h"
27 #include "ui/events/x/touch_factory_x11.h"
28 #include "ui/gfx/insets.h"
29 #include "ui/gfx/path.h"
30 #include "ui/gfx/path_x11.h"
31 #include "ui/native_theme/native_theme.h"
32 #include "ui/views/corewm/compound_event_filter.h"
33 #include "ui/views/corewm/corewm_switches.h"
34 #include "ui/views/corewm/tooltip_aura.h"
35 #include "ui/views/ime/input_method.h"
36 #include "ui/views/linux_ui/linux_ui.h"
37 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
38 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
39 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
40 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
41 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
42 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
43 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
44 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
48 DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
50 std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
52 DEFINE_WINDOW_PROPERTY_KEY(
53 aura::Window*, kViewsWindowForRootWindow, NULL);
55 DEFINE_WINDOW_PROPERTY_KEY(
56 DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
60 // Standard Linux mouse buttons for going back and forward.
61 const int kBackMouseButton = 8;
62 const int kForwardMouseButton = 9;
64 // Constants that are part of EWMH.
65 const int k_NET_WM_STATE_ADD = 1;
66 const int k_NET_WM_STATE_REMOVE = 0;
68 const char* kAtomsToCache[] = {
75 "_NET_WM_STATE_ABOVE",
76 "_NET_WM_STATE_FULLSCREEN",
77 "_NET_WM_STATE_HIDDEN",
78 "_NET_WM_STATE_MAXIMIZED_HORZ",
79 "_NET_WM_STATE_MAXIMIZED_VERT",
80 "_NET_WM_STATE_SKIP_TASKBAR",
81 "_NET_WM_WINDOW_OPACITY",
82 "_NET_WM_WINDOW_TYPE",
83 "_NET_WM_WINDOW_TYPE_MENU",
84 "_NET_WM_WINDOW_TYPE_NORMAL",
85 "_NET_WM_WINDOW_TYPE_TOOLTIP",
98 "XdndProxy", // Proxy windows?
107 ////////////////////////////////////////////////////////////////////////////////
108 // DesktopRootWindowHostX11, public:
110 DesktopRootWindowHostX11::DesktopRootWindowHostX11(
111 internal::NativeWidgetDelegate* native_widget_delegate,
112 DesktopNativeWidgetAura* desktop_native_widget_aura)
113 : close_widget_factory_(this),
114 xdisplay_(gfx::GetXDisplay()),
116 x_root_window_(DefaultRootWindow(xdisplay_)),
117 atom_cache_(xdisplay_, kAtomsToCache),
118 window_mapped_(false),
119 focus_when_shown_(false),
120 is_fullscreen_(false),
121 is_always_on_top_(false),
123 drag_drop_client_(NULL),
124 current_cursor_(ui::kCursorNull),
125 native_widget_delegate_(native_widget_delegate),
126 desktop_native_widget_aura_(desktop_native_widget_aura),
127 root_window_host_delegate_(NULL),
128 content_window_(NULL),
129 window_parent_(NULL) {
132 DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
133 root_window_->ClearProperty(kHostForRootWindow);
134 aura::client::SetWindowMoveClient(root_window_, NULL);
135 desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_);
139 aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
140 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
141 return root ? root->GetProperty(kViewsWindowForRootWindow) : NULL;
145 DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
146 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
147 return root ? root->GetProperty(kHostForRootWindow) : NULL;
151 std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
152 std::vector<aura::Window*> windows(open_windows().size());
153 std::transform(open_windows().begin(),
154 open_windows().end(),
156 GetContentWindowForXID);
160 gfx::Rect DesktopRootWindowHostX11::GetX11RootWindowBounds() const {
164 void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
167 root_window_host_delegate_->OnHostActivated();
169 desktop_native_widget_aura_->HandleActivationChanged(active);
171 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
174 void DesktopRootWindowHostX11::AddObserver(
175 views::DesktopRootWindowHostObserverX11* observer) {
176 observer_list_.AddObserver(observer);
179 void DesktopRootWindowHostX11::RemoveObserver(
180 views::DesktopRootWindowHostObserverX11* observer) {
181 observer_list_.RemoveObserver(observer);
184 void DesktopRootWindowHostX11::CleanUpWindowList() {
185 delete open_windows_;
186 open_windows_ = NULL;
189 ////////////////////////////////////////////////////////////////////////////////
190 // DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
192 void DesktopRootWindowHostX11::Init(
193 aura::Window* content_window,
194 const Widget::InitParams& params,
195 aura::RootWindow::CreateParams* rw_create_params) {
196 content_window_ = content_window;
198 // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
199 // whether we should be proxying requests to another DRWHL.
201 // In some situations, views tries to make a zero sized window, and that
202 // makes us crash. Make sure we have valid sizes.
203 Widget::InitParams sanitized_params = params;
204 if (sanitized_params.bounds.width() == 0)
205 sanitized_params.bounds.set_width(100);
206 if (sanitized_params.bounds.height() == 0)
207 sanitized_params.bounds.set_height(100);
209 InitX11Window(sanitized_params);
211 rw_create_params->initial_bounds = bounds_;
212 rw_create_params->host = this;
215 void DesktopRootWindowHostX11::OnRootWindowCreated(
216 aura::RootWindow* root,
217 const Widget::InitParams& params) {
220 root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
221 root_window_->SetProperty(kHostForRootWindow, this);
222 root_window_host_delegate_ = root_window_;
224 // If we're given a parent, we need to mark ourselves as transient to another
225 // window. Otherwise activation gets screwy.
226 gfx::NativeView parent = params.parent;
227 if (!params.child && params.parent)
228 parent->AddTransientChild(content_window_);
230 // Ensure that the X11DesktopHandler exists so that it dispatches activation
232 X11DesktopHandler::get();
234 // TODO(erg): Unify this code once the other consumer goes away.
235 x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_));
236 x11_window_event_filter_->SetUseHostWindowBorders(false);
237 desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
238 x11_window_event_filter_.get());
240 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
241 aura::client::SetWindowMoveClient(root_window_,
242 x11_window_move_client_.get());
244 native_widget_delegate_->OnNativeWidgetCreated(true);
247 scoped_ptr<corewm::Tooltip> DesktopRootWindowHostX11::CreateTooltip() {
248 return scoped_ptr<corewm::Tooltip>(
249 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
252 scoped_ptr<aura::client::DragDropClient>
253 DesktopRootWindowHostX11::CreateDragDropClient(
254 DesktopNativeCursorManager* cursor_manager) {
255 drag_drop_client_ = new DesktopDragDropClientAuraX11(
256 root_window_, cursor_manager, xdisplay_, xwindow_);
257 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
260 void DesktopRootWindowHostX11::Close() {
261 // TODO(erg): Might need to do additional hiding tasks here.
263 if (!close_widget_factory_.HasWeakPtrs()) {
264 // And we delay the close so that if we are called from an ATL callback,
265 // we don't destroy the window before the callback returned (as the caller
266 // may delete ourselves on destroy and the ATL callback would still
267 // dereference us when the callback returns).
268 base::MessageLoop::current()->PostTask(
270 base::Bind(&DesktopRootWindowHostX11::CloseNow,
271 close_widget_factory_.GetWeakPtr()));
275 void DesktopRootWindowHostX11::CloseNow() {
276 if (xwindow_ == None)
279 native_widget_delegate_->OnNativeWidgetDestroying();
281 // If we have children, close them. Use a copy for iteration because they'll
282 // remove themselves.
283 std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_;
284 for (std::set<DesktopRootWindowHostX11*>::iterator it =
285 window_children_copy.begin(); it != window_children_copy.end();
289 DCHECK(window_children_.empty());
291 // If we have a parent, remove ourselves from its children list.
292 if (window_parent_) {
293 window_parent_->window_children_.erase(this);
294 window_parent_ = NULL;
297 // Remove the event listeners we've installed. We need to remove these
298 // because otherwise we get assert during ~RootWindow().
299 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
300 x11_window_event_filter_.get());
302 open_windows().remove(xwindow_);
303 // Actually free our native resources.
304 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
305 XDestroyWindow(xdisplay_, xwindow_);
308 desktop_native_widget_aura_->OnHostClosed();
311 aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
315 void DesktopRootWindowHostX11::ShowWindowWithState(
316 ui::WindowShowState show_state) {
317 if (show_state != ui::SHOW_STATE_DEFAULT &&
318 show_state != ui::SHOW_STATE_NORMAL) {
319 // Only forwarding to Show().
326 void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
327 const gfx::Rect& restored_bounds) {
328 restored_bounds_ = restored_bounds;
333 bool DesktopRootWindowHostX11::IsVisible() const {
334 return window_mapped_;
337 void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
342 void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
343 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
345 // If |window_|'s transient parent bounds are big enough to contain |size|,
347 if (content_window_->transient_parent()) {
348 gfx::Rect transient_parent_rect =
349 content_window_->transient_parent()->GetBoundsInScreen();
350 if (transient_parent_rect.height() >= size.height() &&
351 transient_parent_rect.width() >= size.width()) {
352 parent_bounds = transient_parent_rect;
356 gfx::Rect window_bounds(
357 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
358 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
361 // Don't size the window bigger than the parent, otherwise the user may not be
362 // able to close or move it.
363 window_bounds.AdjustToFit(parent_bounds);
365 SetBounds(window_bounds);
368 void DesktopRootWindowHostX11::GetWindowPlacement(
370 ui::WindowShowState* show_state) const {
373 if (IsFullscreen()) {
374 *show_state = ui::SHOW_STATE_FULLSCREEN;
375 } else if (IsMinimized()) {
376 *show_state = ui::SHOW_STATE_MINIMIZED;
377 } else if (IsMaximized()) {
378 *show_state = ui::SHOW_STATE_MAXIMIZED;
379 } else if (!IsActive()) {
380 *show_state = ui::SHOW_STATE_INACTIVE;
382 *show_state = ui::SHOW_STATE_NORMAL;
386 gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
390 gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
391 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
392 // needed for View::ConvertPointToScreen() to work
393 // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
394 // asks windows what it thinks the client rect is.
396 // Attempts to calculate the rect by asking the NonClientFrameView what it
397 // thought its GetBoundsForClientView() were broke combobox drop down
402 gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
403 // We can't reliably track the restored bounds of a window, but we can get
404 // the 90% case down. When *chrome* is the process that requests maximizing
405 // or restoring bounds, we can record the current bounds before we request
406 // maximization, and clear it when we detect a state change.
407 if (!restored_bounds_.IsEmpty())
408 return restored_bounds_;
410 return GetWindowBoundsInScreen();
413 gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
414 std::vector<int> value;
415 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
417 return gfx::Rect(value[0], value[1], value[2], value[3]);
420 // Fetch the geometry of the root window.
423 unsigned int width, height;
424 unsigned int border_width, depth;
425 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
426 &width, &height, &border_width, &depth)) {
428 return gfx::Rect(0, 0, 10, 10);
431 return gfx::Rect(x, y, width, height);
434 void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
437 native_region->getBoundaryPath(&path);
438 Region region = gfx::CreateRegionFromSkPath(path);
440 xdisplay_, xwindow_, ShapeBounding, 0, 0, region, false);
441 XDestroyRegion(region);
446 delete native_region;
449 void DesktopRootWindowHostX11::Activate() {
450 X11DesktopHandler::get()->ActivateWindow(xwindow_);
453 void DesktopRootWindowHostX11::Deactivate() {
454 // Deactivating a window means activating nothing.
455 X11DesktopHandler::get()->ActivateWindow(None);
458 bool DesktopRootWindowHostX11::IsActive() const {
459 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
462 void DesktopRootWindowHostX11::Maximize() {
463 // When we're the process requesting the maximizing, we can accurately keep
464 // track of our restored bounds instead of relying on the heuristics that are
465 // in the PropertyNotify and ConfigureNotify handlers.
466 restored_bounds_ = bounds_;
469 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
470 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
473 void DesktopRootWindowHostX11::Minimize() {
474 XIconifyWindow(xdisplay_, xwindow_, 0);
477 void DesktopRootWindowHostX11::Restore() {
478 SetWMSpecState(false,
479 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
480 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
483 bool DesktopRootWindowHostX11::IsMaximized() const {
484 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") ||
485 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
488 bool DesktopRootWindowHostX11::IsMinimized() const {
489 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
493 bool DesktopRootWindowHostX11::HasCapture() const {
494 return g_current_capture == this;
497 void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
498 is_always_on_top_ = always_on_top;
499 SetWMSpecState(always_on_top,
500 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
504 bool DesktopRootWindowHostX11::IsAlwaysOnTop() const {
505 return is_always_on_top_;
508 void DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
509 XmbSetWMProperties(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str(), NULL,
510 NULL, 0, NULL, NULL, NULL);
513 void DesktopRootWindowHostX11::ClearNativeFocus() {
514 // This method is weird and misnamed. Instead of clearing the native focus,
515 // it sets the focus to our |content_window_|, which will trigger a cascade
516 // of focus changes into views.
517 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
518 content_window_->Contains(
519 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
520 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
524 Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
525 const gfx::Vector2d& drag_offset,
526 Widget::MoveLoopSource source,
527 Widget::MoveLoopEscapeBehavior escape_behavior) {
530 aura::client::WindowMoveSource window_move_source =
531 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
532 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
533 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
534 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
535 window_move_source) == aura::client::MOVE_SUCCESSFUL)
536 return Widget::MOVE_LOOP_SUCCESSFUL;
538 return Widget::MOVE_LOOP_CANCELED;
541 void DesktopRootWindowHostX11::EndMoveLoop() {
542 x11_window_move_client_->EndMoveLoop();
545 void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
547 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
550 bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
554 void DesktopRootWindowHostX11::FrameTypeChanged() {
555 // Replace the frame and layout the contents. Even though we don't have a
556 // swapable glass frame like on Windows, we still replace the frame because
557 // the button assets don't update otherwise.
558 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(true);
561 NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
565 void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
566 is_fullscreen_ = fullscreen;
567 SetWMSpecState(fullscreen,
568 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
572 bool DesktopRootWindowHostX11::IsFullscreen() const {
573 return is_fullscreen_;
576 void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
577 // X server opacity is in terms of 32 bit unsigned int space, and counts from
578 // the opposite direction.
579 // XChangeProperty() expects "cardinality" to be long.
580 unsigned long cardinality = opacity * 0x1010101;
582 if (cardinality == 0xffffffff) {
583 XDeleteProperty(xdisplay_, xwindow_,
584 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
586 XChangeProperty(xdisplay_, xwindow_,
587 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
590 reinterpret_cast<unsigned char*>(&cardinality), 1);
594 void DesktopRootWindowHostX11::SetWindowIcons(
595 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
600 void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
601 switch (modal_type) {
602 case ui::MODAL_TYPE_NONE:
605 // TODO(erg): Figure out under what situations |modal_type| isn't
606 // none. The comment in desktop_native_widget_aura.cc suggests that this
612 void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
617 void DesktopRootWindowHostX11::OnRootViewLayout() const {
622 long supplied_return;
623 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
625 gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
626 if (minimum.IsEmpty()) {
627 hints.flags &= ~PMinSize;
629 hints.flags |= PMinSize;
630 hints.min_width = minimum.width();
631 hints.min_height = minimum.height();
634 gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
635 if (maximum.IsEmpty()) {
636 hints.flags &= ~PMaxSize;
638 hints.flags |= PMaxSize;
639 hints.max_width = maximum.width();
640 hints.max_height = maximum.height();
643 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
646 void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
647 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
650 void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
652 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
655 bool DesktopRootWindowHostX11::IsAnimatingClosed() const {
659 ////////////////////////////////////////////////////////////////////////////////
660 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
662 void DesktopRootWindowHostX11::SetDelegate(
663 aura::RootWindowHostDelegate* delegate) {
664 root_window_host_delegate_ = delegate;
667 aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
671 gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
675 void DesktopRootWindowHostX11::Show() {
676 if (!window_mapped_) {
677 // Before we map the window, set size hints. Otherwise, some window managers
678 // will ignore toplevel XMoveWindow commands.
679 XSizeHints size_hints;
680 size_hints.flags = PPosition;
681 size_hints.x = bounds_.x();
682 size_hints.y = bounds_.y();
683 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
685 XMapWindow(xdisplay_, xwindow_);
687 // We now block until our window is mapped. Some X11 APIs will crash and
688 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
690 base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
691 window_mapped_ = true;
695 void DesktopRootWindowHostX11::Hide() {
696 if (window_mapped_) {
697 XWithdrawWindow(xdisplay_, xwindow_, 0);
698 window_mapped_ = false;
702 void DesktopRootWindowHostX11::ToggleFullScreen() {
706 gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
710 void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
711 bool origin_changed = bounds_.origin() != bounds.origin();
712 bool size_changed = bounds_.size() != bounds.size();
713 XWindowChanges changes = {0};
714 unsigned value_mask = 0;
717 // X11 will send an XError at our process if have a 0 sized window.
718 DCHECK_GT(bounds.width(), 0);
719 DCHECK_GT(bounds.height(), 0);
721 changes.width = bounds.width();
722 changes.height = bounds.height();
723 value_mask |= CWHeight | CWWidth;
726 if (origin_changed) {
727 changes.x = bounds.x();
728 changes.y = bounds.y();
729 value_mask |= CWX | CWY;
732 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
734 // Assume that the resize will go through as requested, which should be the
735 // case if we're running without a window manager. If there's a window
736 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
737 // (possibly synthetic) ConfigureNotify about the actual size and correct
742 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
744 root_window_host_delegate_->OnHostResized(bounds.size());
746 root_window_host_delegate_->OnHostPaint(gfx::Rect(bounds.size()));
749 gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
750 return gfx::Insets();
753 void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
756 gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
757 return bounds_.origin();
760 void DesktopRootWindowHostX11::SetCapture() {
761 // This is vaguely based on the old NativeWidgetGtk implementation.
763 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
764 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
765 // a grab that wasn't the X11 pointer grab, but was instead a manual
766 // redirection of the event. (You need to drop into GDK if you want to
767 // perform a raw X11 grab).
769 if (g_current_capture)
770 g_current_capture->OnCaptureReleased();
772 g_current_capture = this;
774 // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
775 // pointer grab when our NativeWidget is of type Menu. However, things work
776 // without it. Clicking inside a chrome window causes a release capture, and
777 // clicking outside causes an activation change. Since previous attempts at
778 // using XPointerGrab() to implement this have locked my X server, I'm going
779 // to skip this for now.
782 void DesktopRootWindowHostX11::ReleaseCapture() {
783 if (g_current_capture)
784 g_current_capture->OnCaptureReleased();
787 void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
788 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
791 bool DesktopRootWindowHostX11::QueryMouseLocation(
792 gfx::Point* location_return) {
793 aura::client::CursorClient* cursor_client =
794 aura::client::GetCursorClient(GetRootWindow());
795 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
796 *location_return = gfx::Point(0, 0);
800 ::Window root_return, child_return;
801 int root_x_return, root_y_return, win_x_return, win_y_return;
802 unsigned int mask_return;
803 XQueryPointer(xdisplay_,
807 &root_x_return, &root_y_return,
808 &win_x_return, &win_y_return,
810 *location_return = gfx::Point(
811 std::max(0, std::min(bounds_.width(), win_x_return)),
812 std::max(0, std::min(bounds_.height(), win_y_return)));
813 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
814 win_y_return >= 0 && win_y_return < bounds_.height());
817 bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
822 void DesktopRootWindowHostX11::UnConfineCursor() {
826 void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
827 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
828 // the same tap-to-click disabling here that chromeos does.
831 void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
832 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
833 bounds_.x() + location.x(), bounds_.y() + location.y());
836 void DesktopRootWindowHostX11::SetFocusWhenShown(bool focus_when_shown) {
837 static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
838 focus_when_shown_ = focus_when_shown;
839 if (IsWindowManagerPresent() && !focus_when_shown_) {
840 ui::SetIntProperty(xwindow_,
847 void DesktopRootWindowHostX11::PostNativeEvent(
848 const base::NativeEvent& native_event) {
851 XEvent xevent = *native_event;
852 xevent.xany.display = xdisplay_;
853 xevent.xany.window = xwindow_;
855 switch (xevent.type) {
862 case ButtonRelease: {
863 // The fields used below are in the same place for all of events
864 // above. Using xmotion from XEvent's unions to avoid repeating
866 xevent.xmotion.root = x_root_window_;
867 xevent.xmotion.time = CurrentTime;
869 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
870 root_window_->ConvertPointToNativeScreen(&point);
871 xevent.xmotion.x_root = point.x();
872 xevent.xmotion.y_root = point.y();
877 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
880 void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
881 float device_scale_factor) {
884 void DesktopRootWindowHostX11::PrepareForShutdown() {
887 ////////////////////////////////////////////////////////////////////////////////
888 // DesktopRootWindowHostX11, private:
890 void DesktopRootWindowHostX11::InitX11Window(
891 const Widget::InitParams& params) {
892 unsigned long attribute_mask = CWBackPixmap;
893 XSetWindowAttributes swa;
894 memset(&swa, 0, sizeof(swa));
895 swa.background_pixmap = None;
898 switch (params.type) {
899 case Widget::InitParams::TYPE_MENU:
900 swa.override_redirect = True;
901 attribute_mask |= CWOverrideRedirect;
902 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
904 case Widget::InitParams::TYPE_TOOLTIP:
905 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
908 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
912 bounds_ = params.bounds;
913 xwindow_ = XCreateWindow(
914 xdisplay_, x_root_window_,
915 bounds_.x(), bounds_.y(),
916 bounds_.width(), bounds_.height(),
918 CopyFromParent, // depth
920 CopyFromParent, // visual
923 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
924 open_windows().push_back(xwindow_);
926 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
928 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
929 KeyPressMask | KeyReleaseMask |
930 EnterWindowMask | LeaveWindowMask |
931 ExposureMask | VisibilityChangeMask |
932 StructureNotifyMask | PropertyChangeMask |
934 XSelectInput(xdisplay_, xwindow_, event_mask);
937 if (base::MessagePumpForUI::HasXInput2())
938 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
940 // TODO(erg): We currently only request window deletion events. We also
941 // should listen for activation events and anything else that GTK+ listens
942 // for, and do something useful.
944 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
945 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
946 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
948 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
949 // the desktop environment.
950 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
952 // Likewise, the X server needs to know this window's pid so it knows which
953 // program to kill if the window hangs.
954 // XChangeProperty() expects "pid" to be long.
955 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
956 long pid = params.net_wm_pid;
959 XChangeProperty(xdisplay_,
961 atom_cache_.GetAtom("_NET_WM_PID"),
965 reinterpret_cast<unsigned char*>(&pid), 1);
967 XChangeProperty(xdisplay_,
969 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
973 reinterpret_cast<unsigned char*>(&window_type), 1);
975 // List of window state properties (_NET_WM_STATE) to set, if any.
976 std::vector< ::Atom> state_atom_list;
978 // Remove popup windows from taskbar.
979 if (params.type == Widget::InitParams::TYPE_POPUP ||
980 params.type == Widget::InitParams::TYPE_BUBBLE) {
981 state_atom_list.push_back(
982 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
985 // If the window should stay on top of other windows, add the
986 // _NET_WM_STATE_ABOVE property.
987 is_always_on_top_ = params.keep_on_top;
988 if (is_always_on_top_)
989 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
991 // Setting _NET_WM_STATE by sending a message to the root_window (with
992 // SetWMSpecState) has no effect here since the window has not yet been
993 // mapped. So we manually change the state.
994 if (!state_atom_list.empty()) {
995 ui::SetAtomArrayProperty(xwindow_,
1001 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1002 ui::SetWindowClassHint(
1003 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1006 // If we have a parent, record the parent/child relationship. We use this
1007 // data during destruction to make sure that when we try to close a parent
1008 // window, we also destroy all child windows.
1009 if (params.parent && params.parent->GetDispatcher()) {
1010 XID parent_xid = params.parent->GetDispatcher()->GetAcceleratedWidget();
1011 window_parent_ = GetHostForXID(parent_xid);
1012 DCHECK(window_parent_);
1013 window_parent_->window_children_.insert(this);
1017 bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
1018 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
1019 // of WM_Sn selections (where n is a screen number).
1020 return XGetSelectionOwner(
1021 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1024 void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
1028 memset(&xclient, 0, sizeof(xclient));
1029 xclient.type = ClientMessage;
1030 xclient.xclient.window = xwindow_;
1031 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1032 xclient.xclient.format = 32;
1033 xclient.xclient.data.l[0] =
1034 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1035 xclient.xclient.data.l[1] = state1;
1036 xclient.xclient.data.l[2] = state2;
1037 xclient.xclient.data.l[3] = 1;
1038 xclient.xclient.data.l[4] = 0;
1040 XSendEvent(xdisplay_, x_root_window_, False,
1041 SubstructureRedirectMask | SubstructureNotifyMask,
1045 bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
1046 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1047 window_properties_.end();
1050 void DesktopRootWindowHostX11::OnCaptureReleased() {
1051 g_current_capture = NULL;
1052 root_window_host_delegate_->OnHostLostWindowCapture();
1053 native_widget_delegate_->OnMouseCaptureLost();
1056 void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1057 if (!g_current_capture || g_current_capture == this) {
1058 root_window_host_delegate_->OnHostMouseEvent(event);
1060 // Another DesktopRootWindowHostX11 has installed itself as
1061 // capture. Translate the event's location and dispatch to the other.
1062 event->ConvertLocationToTarget(root_window_,
1063 g_current_capture->root_window_);
1064 g_current_capture->root_window_host_delegate_->OnHostMouseEvent(event);
1068 void DesktopRootWindowHostX11::ResetWindowRegion() {
1069 if (!IsMaximized()) {
1070 gfx::Path window_mask;
1071 views::Widget* widget = native_widget_delegate_->AsWidget();
1072 if (widget->non_client_view()) {
1073 // Some frame views define a custom (non-rectangular) window mask. If
1074 // so, use it to define the window shape. If not, fall through.
1075 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1076 if (window_mask.countPoints() > 0) {
1077 Region region = gfx::CreateRegionFromSkPath(window_mask);
1078 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1079 0, 0, region, false);
1080 XDestroyRegion(region);
1086 // If we didn't set the shape for any reason, reset the shaping information
1087 // by ShapeSet-ing with our bounds rect.
1088 XRectangle r = { 0, 0, static_cast<unsigned short>(bounds_.width()),
1089 static_cast<unsigned short>(bounds_.height()) };
1090 XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding,
1091 0, 0, &r, 1, ShapeSet, YXBanded);
1094 std::list<XID>& DesktopRootWindowHostX11::open_windows() {
1096 open_windows_ = new std::list<XID>();
1097 return *open_windows_;
1100 ////////////////////////////////////////////////////////////////////////////////
1101 // DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
1103 bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
1104 XEvent* xev = event;
1106 // May want to factor CheckXEventForConsistency(xev); into a common location
1107 // since it is called here.
1108 switch (xev->type) {
1111 ui::MouseEvent mouse_event(xev);
1112 DispatchMouseEvent(&mouse_event);
1116 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1117 xev->xexpose.width, xev->xexpose.height);
1118 root_window_host_delegate_->OnHostPaint(damage_rect);
1122 ui::KeyEvent keydown_event(xev, false);
1123 root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
1127 ui::KeyEvent keyup_event(xev, false);
1128 root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
1132 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
1133 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
1134 aura::client::UserActionClient* gesture_client =
1135 aura::client::GetUserActionClient(root_window_);
1136 if (gesture_client) {
1137 gesture_client->OnUserAction(
1138 static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
1139 aura::client::UserActionClient::BACK :
1140 aura::client::UserActionClient::FORWARD);
1145 case ButtonRelease: {
1146 ui::MouseEvent mouseev(xev);
1147 DispatchMouseEvent(&mouseev);
1151 if (xev->xfocus.mode != NotifyGrab) {
1153 root_window_host_delegate_->OnHostLostWindowCapture();
1155 root_window_host_delegate_->OnHostLostMouseGrab();
1158 case ConfigureNotify: {
1159 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1160 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1161 // It's possible that the X window may be resized by some other means than
1162 // from within aura (e.g. the X window manager can change the size). Make
1163 // sure the root window size is maintained properly.
1164 int translated_x = xev->xconfigure.x;
1165 int translated_y = xev->xconfigure.y;
1166 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1168 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1169 0, 0, &translated_x, &translated_y, &unused);
1171 gfx::Rect bounds(translated_x, translated_y,
1172 xev->xconfigure.width, xev->xconfigure.height);
1173 bool size_changed = bounds_.size() != bounds.size();
1174 bool origin_changed = bounds_.origin() != bounds.origin();
1175 previous_bounds_ = bounds_;
1178 root_window_host_delegate_->OnHostResized(bounds.size());
1180 root_window_host_delegate_->OnHostMoved(bounds_.origin());
1181 ResetWindowRegion();
1184 case GenericEvent: {
1185 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1186 if (!factory->ShouldProcessXI2Event(xev))
1189 ui::EventType type = ui::EventTypeFromNative(xev);
1191 int num_coalesced = 0;
1194 case ui::ET_TOUCH_MOVED:
1195 case ui::ET_TOUCH_PRESSED:
1196 case ui::ET_TOUCH_RELEASED: {
1197 ui::TouchEvent touchev(xev);
1198 root_window_host_delegate_->OnHostTouchEvent(&touchev);
1201 case ui::ET_MOUSE_MOVED:
1202 case ui::ET_MOUSE_DRAGGED:
1203 case ui::ET_MOUSE_PRESSED:
1204 case ui::ET_MOUSE_RELEASED:
1205 case ui::ET_MOUSE_ENTERED:
1206 case ui::ET_MOUSE_EXITED: {
1207 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1208 // If this is a motion event, we want to coalesce all pending motion
1209 // events that are at the top of the queue.
1210 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1211 if (num_coalesced > 0)
1213 } else if (type == ui::ET_MOUSE_PRESSED) {
1214 XIDeviceEvent* xievent =
1215 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1216 int button = xievent->detail;
1217 if (button == kBackMouseButton || button == kForwardMouseButton) {
1218 aura::client::UserActionClient* gesture_client =
1219 aura::client::GetUserActionClient(
1220 root_window_host_delegate_->AsRootWindow());
1221 if (gesture_client) {
1222 bool reverse_direction =
1223 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
1224 gesture_client->OnUserAction(
1225 (button == kBackMouseButton && !reverse_direction) ||
1226 (button == kForwardMouseButton && reverse_direction) ?
1227 aura::client::UserActionClient::BACK :
1228 aura::client::UserActionClient::FORWARD);
1232 } else if (type == ui::ET_MOUSE_RELEASED) {
1233 XIDeviceEvent* xievent =
1234 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1235 int button = xievent->detail;
1236 if (button == kBackMouseButton || button == kForwardMouseButton) {
1237 // We've already passed the back/forward mouse down to the user
1238 // action client; we want to swallow the corresponding release.
1242 ui::MouseEvent mouseev(xev);
1243 DispatchMouseEvent(&mouseev);
1246 case ui::ET_MOUSEWHEEL: {
1247 ui::MouseWheelEvent mouseev(xev);
1248 DispatchMouseEvent(&mouseev);
1251 case ui::ET_SCROLL_FLING_START:
1252 case ui::ET_SCROLL_FLING_CANCEL:
1253 case ui::ET_SCROLL: {
1254 ui::ScrollEvent scrollev(xev);
1255 root_window_host_delegate_->OnHostScrollEvent(&scrollev);
1258 case ui::ET_UNKNOWN:
1264 // If we coalesced an event we need to free its cookie.
1265 if (num_coalesced > 0)
1266 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1270 // If there's no window manager running, we need to assign the X input
1271 // focus to our host window.
1272 if (!IsWindowManagerPresent() && focus_when_shown_)
1273 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
1275 FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
1277 OnWindowMapped(xwindow_));
1281 FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
1283 OnWindowUnmapped(xwindow_));
1286 case ClientMessage: {
1287 Atom message_type = xev->xclient.message_type;
1288 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1289 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1290 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1291 // We have received a close message from the window manager.
1292 root_window_->OnRootWindowHostCloseRequested();
1293 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1294 XEvent reply_event = *xev;
1295 reply_event.xclient.window = x_root_window_;
1297 XSendEvent(xdisplay_,
1298 reply_event.xclient.window,
1300 SubstructureRedirectMask | SubstructureNotifyMask,
1303 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1304 drag_drop_client_->OnXdndEnter(xev->xclient);
1305 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1306 drag_drop_client_->OnXdndLeave(xev->xclient);
1307 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1308 drag_drop_client_->OnXdndPosition(xev->xclient);
1309 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1310 drag_drop_client_->OnXdndStatus(xev->xclient);
1311 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1312 drag_drop_client_->OnXdndFinished(xev->xclient);
1313 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1314 drag_drop_client_->OnXdndDrop(xev->xclient);
1318 case MappingNotify: {
1319 switch (xev->xmapping.request) {
1320 case MappingModifier:
1321 case MappingKeyboard:
1322 XRefreshKeyboardMapping(&xev->xmapping);
1323 root_window_->OnKeyboardMappingChanged();
1325 case MappingPointer:
1326 ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1329 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1334 case MotionNotify: {
1335 // Discard all but the most recent motion event that targets the same
1336 // window with unchanged state.
1338 while (XPending(xev->xany.display)) {
1340 XPeekEvent(xev->xany.display, &next_event);
1341 if (next_event.type == MotionNotify &&
1342 next_event.xmotion.window == xev->xmotion.window &&
1343 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1344 next_event.xmotion.state == xev->xmotion.state) {
1345 XNextEvent(xev->xany.display, &last_event);
1352 ui::MouseEvent mouseev(xev);
1353 DispatchMouseEvent(&mouseev);
1356 case PropertyNotify: {
1357 // Get our new window property state if the WM has told us its changed.
1358 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1360 std::vector< ::Atom> atom_list;
1361 if (xev->xproperty.atom == state &&
1362 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1363 window_properties_.clear();
1364 std::copy(atom_list.begin(), atom_list.end(),
1365 inserter(window_properties_, window_properties_.begin()));
1367 if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
1368 // If we have restored bounds, but WM_STATE no longer claims to be
1369 // maximized, we should clear our restored bounds.
1370 restored_bounds_ = gfx::Rect();
1371 } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
1372 // The request that we become maximized originated from a different
1373 // process. |bounds_| already contains our maximized bounds. Do a
1374 // best effort attempt to get restored bounds by setting it to our
1375 // previously set bounds (and if we get this wrong, we aren't any
1376 // worse off since we'd otherwise be returning our maximized bounds).
1377 restored_bounds_ = previous_bounds_;
1380 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
1381 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1383 // Now that we have different window properties, we may need to
1384 // relayout the window. (The windows code doesn't need this because
1385 // their window change is synchronous.)
1387 // TODO(erg): While this does work, there's a quick flash showing the
1388 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
1389 // those parts of the UI because we receive the sizing event from the
1390 // window manager before we receive the event that changes the
1391 // fullscreen state. Unsure what to do about that.
1392 Widget* widget = native_widget_delegate_->AsWidget();
1393 NonClientView* non_client_view = widget->non_client_view();
1394 // non_client_view may be NULL, especially during creation.
1395 if (non_client_view) {
1396 non_client_view->client_view()->InvalidateLayout();
1397 non_client_view->InvalidateLayout();
1399 widget->GetRootView()->Layout();
1403 case SelectionNotify: {
1404 drag_drop_client_->OnSelectionNotify(xev->xselection);
1411 ////////////////////////////////////////////////////////////////////////////////
1412 // DesktopRootWindowHost, public:
1415 DesktopRootWindowHost* DesktopRootWindowHost::Create(
1416 internal::NativeWidgetDelegate* native_widget_delegate,
1417 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1418 return new DesktopRootWindowHostX11(native_widget_delegate,
1419 desktop_native_widget_aura);
1423 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
1424 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1426 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
1428 return native_theme;
1431 return ui::NativeTheme::instance();
1434 } // namespace views