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_window_tree_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/debug/trace_event.h"
15 #include "base/message_loop/message_pump_x11.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/x/device_data_manager.h"
29 #include "ui/events/x/device_list_cache_x.h"
30 #include "ui/events/x/touch_factory_x11.h"
31 #include "ui/gfx/image/image_skia.h"
32 #include "ui/gfx/image/image_skia_rep.h"
33 #include "ui/gfx/insets.h"
34 #include "ui/gfx/path.h"
35 #include "ui/gfx/path_x11.h"
36 #include "ui/gfx/screen.h"
37 #include "ui/native_theme/native_theme.h"
38 #include "ui/views/corewm/tooltip_aura.h"
39 #include "ui/views/ime/input_method.h"
40 #include "ui/views/linux_ui/linux_ui.h"
41 #include "ui/views/views_delegate.h"
42 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
43 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
44 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
45 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
46 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
47 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
48 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
49 #include "ui/views/widget/desktop_aura/x11_scoped_capture.h"
50 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
51 #include "ui/wm/core/compound_event_filter.h"
52 #include "ui/wm/core/window_util.h"
56 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
58 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
60 DEFINE_WINDOW_PROPERTY_KEY(
61 aura::Window*, kViewsWindowForRootWindow, NULL);
63 DEFINE_WINDOW_PROPERTY_KEY(
64 DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
68 // Constants that are part of EWMH.
69 const int k_NET_WM_STATE_ADD = 1;
70 const int k_NET_WM_STATE_REMOVE = 0;
72 const char* kAtomsToCache[] = {
82 "_NET_WM_STATE_ABOVE",
83 "_NET_WM_STATE_FULLSCREEN",
84 "_NET_WM_STATE_HIDDEN",
85 "_NET_WM_STATE_MAXIMIZED_HORZ",
86 "_NET_WM_STATE_MAXIMIZED_VERT",
87 "_NET_WM_STATE_SKIP_TASKBAR",
88 "_NET_WM_STATE_STICKY",
90 "_NET_WM_WINDOW_OPACITY",
91 "_NET_WM_WINDOW_TYPE",
92 "_NET_WM_WINDOW_TYPE_DND",
93 "_NET_WM_WINDOW_TYPE_MENU",
94 "_NET_WM_WINDOW_TYPE_NORMAL",
95 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
96 "_NET_WM_WINDOW_TYPE_TOOLTIP",
109 "XdndProxy", // Proxy windows?
118 ////////////////////////////////////////////////////////////////////////////////
119 // DesktopWindowTreeHostX11, public:
121 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
122 internal::NativeWidgetDelegate* native_widget_delegate,
123 DesktopNativeWidgetAura* desktop_native_widget_aura)
124 : close_widget_factory_(this),
125 xdisplay_(gfx::GetXDisplay()),
127 x_root_window_(DefaultRootWindow(xdisplay_)),
128 atom_cache_(xdisplay_, kAtomsToCache),
129 window_mapped_(false),
130 is_fullscreen_(false),
131 is_always_on_top_(false),
132 use_native_frame_(false),
133 drag_drop_client_(NULL),
134 current_cursor_(ui::kCursorNull),
135 native_widget_delegate_(native_widget_delegate),
136 desktop_native_widget_aura_(desktop_native_widget_aura),
137 content_window_(NULL),
138 window_parent_(NULL),
139 custom_window_shape_(NULL),
140 urgency_hint_set_(false) {
143 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
144 window()->ClearProperty(kHostForRootWindow);
145 aura::client::SetWindowMoveClient(window(), NULL);
146 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
147 if (custom_window_shape_)
148 XDestroyRegion(custom_window_shape_);
153 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
154 aura::WindowTreeHost* host =
155 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
156 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
160 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
161 aura::WindowTreeHost* host =
162 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
163 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
167 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
168 std::vector<aura::Window*> windows(open_windows().size());
169 std::transform(open_windows().begin(),
170 open_windows().end(),
172 GetContentWindowForXID);
176 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
180 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
185 open_windows().remove(xwindow_);
186 open_windows().insert(open_windows().begin(), xwindow_);
189 desktop_native_widget_aura_->HandleActivationChanged(active);
191 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
194 void DesktopWindowTreeHostX11::AddObserver(
195 views::DesktopWindowTreeHostObserverX11* observer) {
196 observer_list_.AddObserver(observer);
199 void DesktopWindowTreeHostX11::RemoveObserver(
200 views::DesktopWindowTreeHostObserverX11* observer) {
201 observer_list_.RemoveObserver(observer);
204 void DesktopWindowTreeHostX11::CleanUpWindowList() {
205 delete open_windows_;
206 open_windows_ = NULL;
209 ////////////////////////////////////////////////////////////////////////////////
210 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
212 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
213 const Widget::InitParams& params) {
214 content_window_ = content_window;
216 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
217 // whether we should be proxying requests to another DRWHL.
219 // In some situations, views tries to make a zero sized window, and that
220 // makes us crash. Make sure we have valid sizes.
221 Widget::InitParams sanitized_params = params;
222 if (sanitized_params.bounds.width() == 0)
223 sanitized_params.bounds.set_width(100);
224 if (sanitized_params.bounds.height() == 0)
225 sanitized_params.bounds.set_height(100);
227 InitX11Window(sanitized_params);
230 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
231 const Widget::InitParams& params) {
232 window()->SetProperty(kViewsWindowForRootWindow, content_window_);
233 window()->SetProperty(kHostForRootWindow, this);
235 // Ensure that the X11DesktopHandler exists so that it dispatches activation
237 X11DesktopHandler::get();
239 // TODO(erg): Unify this code once the other consumer goes away.
240 x11_window_event_filter_.reset(new X11WindowEventFilter(this));
241 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
242 !params.remove_standard_frame);
243 desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
244 x11_window_event_filter_.get());
246 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
247 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
249 native_widget_delegate_->OnNativeWidgetCreated(true);
252 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
253 return scoped_ptr<corewm::Tooltip>(
254 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
257 scoped_ptr<aura::client::DragDropClient>
258 DesktopWindowTreeHostX11::CreateDragDropClient(
259 DesktopNativeCursorManager* cursor_manager) {
260 drag_drop_client_ = new DesktopDragDropClientAuraX11(
261 window(), cursor_manager, xdisplay_, xwindow_);
262 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
265 void DesktopWindowTreeHostX11::Close() {
266 // TODO(erg): Might need to do additional hiding tasks here.
268 if (!close_widget_factory_.HasWeakPtrs()) {
269 // And we delay the close so that if we are called from an ATL callback,
270 // we don't destroy the window before the callback returned (as the caller
271 // may delete ourselves on destroy and the ATL callback would still
272 // dereference us when the callback returns).
273 base::MessageLoop::current()->PostTask(
275 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
276 close_widget_factory_.GetWeakPtr()));
280 void DesktopWindowTreeHostX11::CloseNow() {
281 if (xwindow_ == None)
284 x11_capture_.reset();
285 native_widget_delegate_->OnNativeWidgetDestroying();
287 // If we have children, close them. Use a copy for iteration because they'll
288 // remove themselves.
289 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
290 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
291 window_children_copy.begin(); it != window_children_copy.end();
295 DCHECK(window_children_.empty());
297 // If we have a parent, remove ourselves from its children list.
298 if (window_parent_) {
299 window_parent_->window_children_.erase(this);
300 window_parent_ = NULL;
303 // Remove the event listeners we've installed. We need to remove these
304 // because otherwise we get assert during ~WindowEventDispatcher().
305 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
306 x11_window_event_filter_.get());
308 // Destroy the compositor before destroying the |xwindow_| since shutdown
309 // may try to swap, and the swap without a window causes an X error, which
310 // causes a crash with in-process renderer.
313 open_windows().remove(xwindow_);
314 // Actually free our native resources.
315 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
316 XDestroyWindow(xdisplay_, xwindow_);
319 desktop_native_widget_aura_->OnHostClosed();
322 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
326 void DesktopWindowTreeHostX11::ShowWindowWithState(
327 ui::WindowShowState show_state) {
329 MapWindow(show_state);
331 if (show_state == ui::SHOW_STATE_NORMAL ||
332 show_state == ui::SHOW_STATE_MAXIMIZED) {
333 // Note: XFCE ignores a maximize hint given before mapping the window.
334 if (show_state == ui::SHOW_STATE_MAXIMIZED)
339 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
342 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
343 const gfx::Rect& restored_bounds) {
344 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
345 // Enforce |restored_bounds_| since calling Maximize() could have reset it.
346 restored_bounds_ = restored_bounds;
349 bool DesktopWindowTreeHostX11::IsVisible() const {
350 return window_mapped_;
353 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) {
354 bool size_changed = bounds_.size() != size;
355 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
356 bounds_.set_size(size);
363 void DesktopWindowTreeHostX11::StackAtTop() {
364 XRaiseWindow(xdisplay_, xwindow_);
367 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
368 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
370 // If |window_|'s transient parent bounds are big enough to contain |size|,
372 if (wm::GetTransientParent(content_window_)) {
373 gfx::Rect transient_parent_rect =
374 wm::GetTransientParent(content_window_)->GetBoundsInScreen();
375 if (transient_parent_rect.height() >= size.height() &&
376 transient_parent_rect.width() >= size.width()) {
377 parent_bounds = transient_parent_rect;
381 gfx::Rect window_bounds(
382 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
383 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
386 // Don't size the window bigger than the parent, otherwise the user may not be
387 // able to close or move it.
388 window_bounds.AdjustToFit(parent_bounds);
390 SetBounds(window_bounds);
393 void DesktopWindowTreeHostX11::GetWindowPlacement(
395 ui::WindowShowState* show_state) const {
398 if (IsFullscreen()) {
399 *show_state = ui::SHOW_STATE_FULLSCREEN;
400 } else if (IsMinimized()) {
401 *show_state = ui::SHOW_STATE_MINIMIZED;
402 } else if (IsMaximized()) {
403 *show_state = ui::SHOW_STATE_MAXIMIZED;
404 } else if (!IsActive()) {
405 *show_state = ui::SHOW_STATE_INACTIVE;
407 *show_state = ui::SHOW_STATE_NORMAL;
411 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
415 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
416 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
417 // needed for View::ConvertPointToScreen() to work
418 // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
419 // asks windows what it thinks the client rect is.
421 // Attempts to calculate the rect by asking the NonClientFrameView what it
422 // thought its GetBoundsForClientView() were broke combobox drop down
427 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
428 // We can't reliably track the restored bounds of a window, but we can get
429 // the 90% case down. When *chrome* is the process that requests maximizing
430 // or restoring bounds, we can record the current bounds before we request
431 // maximization, and clear it when we detect a state change.
432 if (!restored_bounds_.IsEmpty())
433 return restored_bounds_;
435 return GetWindowBoundsInScreen();
438 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
439 std::vector<int> value;
440 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
442 return gfx::Rect(value[0], value[1], value[2], value[3]);
445 // Fetch the geometry of the root window.
448 unsigned int width, height;
449 unsigned int border_width, depth;
450 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
451 &width, &height, &border_width, &depth)) {
453 return gfx::Rect(0, 0, 10, 10);
456 return gfx::Rect(x, y, width, height);
459 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
460 if (custom_window_shape_)
461 XDestroyRegion(custom_window_shape_);
462 custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
464 delete native_region;
467 void DesktopWindowTreeHostX11::Activate() {
471 X11DesktopHandler::get()->ActivateWindow(xwindow_);
474 void DesktopWindowTreeHostX11::Deactivate() {
478 x11_capture_.reset();
479 XLowerWindow(xdisplay_, xwindow_);
482 bool DesktopWindowTreeHostX11::IsActive() const {
483 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
486 void DesktopWindowTreeHostX11::Maximize() {
487 // When we are in the process of requesting to maximize a window, we can
488 // accurately keep track of our restored bounds instead of relying on the
489 // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
490 restored_bounds_ = bounds_;
493 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
494 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
497 void DesktopWindowTreeHostX11::Minimize() {
498 x11_capture_.reset();
499 XIconifyWindow(xdisplay_, xwindow_, 0);
502 void DesktopWindowTreeHostX11::Restore() {
503 SetWMSpecState(false,
504 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
505 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
508 bool DesktopWindowTreeHostX11::IsMaximized() const {
509 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
510 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
513 bool DesktopWindowTreeHostX11::IsMinimized() const {
514 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
517 bool DesktopWindowTreeHostX11::HasCapture() const {
518 return g_current_capture == this;
521 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
522 is_always_on_top_ = always_on_top;
523 SetWMSpecState(always_on_top,
524 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
528 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
529 return is_always_on_top_;
532 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
533 SetWMSpecState(always_visible,
534 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
538 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
539 if (window_title_ == title)
541 window_title_ = title;
542 std::string utf8str = base::UTF16ToUTF8(title);
543 XChangeProperty(xdisplay_,
545 atom_cache_.GetAtom("_NET_WM_NAME"),
546 atom_cache_.GetAtom("UTF8_STRING"),
549 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
551 // TODO(erg): This is technically wrong. So XStoreName and friends expect
552 // this in Host Portable Character Encoding instead of UTF-8, which I believe
553 // is Compound Text. This shouldn't matter 90% of the time since this is the
554 // fallback to the UTF8 property above.
555 XStoreName(xdisplay_, xwindow_, utf8str.c_str());
559 void DesktopWindowTreeHostX11::ClearNativeFocus() {
560 // This method is weird and misnamed. Instead of clearing the native focus,
561 // it sets the focus to our |content_window_|, which will trigger a cascade
562 // of focus changes into views.
563 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
564 content_window_->Contains(
565 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
566 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
570 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
571 const gfx::Vector2d& drag_offset,
572 Widget::MoveLoopSource source,
573 Widget::MoveLoopEscapeBehavior escape_behavior) {
574 aura::client::WindowMoveSource window_move_source =
575 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
576 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
577 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
578 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
579 window_move_source) == aura::client::MOVE_SUCCESSFUL)
580 return Widget::MOVE_LOOP_SUCCESSFUL;
582 return Widget::MOVE_LOOP_CANCELED;
585 void DesktopWindowTreeHostX11::EndMoveLoop() {
586 x11_window_move_client_->EndMoveLoop();
589 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
591 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
594 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
595 return use_native_frame_;
598 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
602 void DesktopWindowTreeHostX11::FrameTypeChanged() {
603 Widget::FrameType new_type =
604 native_widget_delegate_->AsWidget()->frame_type();
605 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
606 // Replace the frame and layout the contents. Even though we don't have a
607 // swapable glass frame like on Windows, we still replace the frame because
608 // the button assets don't update otherwise.
609 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
612 NonClientFrameView* DesktopWindowTreeHostX11::CreateNonClientFrameView() {
616 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
617 if (is_fullscreen_ == fullscreen)
619 is_fullscreen_ = fullscreen;
620 SetWMSpecState(fullscreen,
621 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
623 // Try to guess the size we will have after the switch to/from fullscreen:
624 // - (may) avoid transient states
625 // - works around Flash content which expects to have the size updated
627 // See https://crbug.com/361408
629 restored_bounds_ = bounds_;
630 const gfx::Display display =
631 gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
632 bounds_ = display.bounds();
634 bounds_ = restored_bounds_;
636 OnHostMoved(bounds_.origin());
637 OnHostResized(bounds_.size());
640 bool DesktopWindowTreeHostX11::IsFullscreen() const {
641 return is_fullscreen_;
644 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
645 // X server opacity is in terms of 32 bit unsigned int space, and counts from
646 // the opposite direction.
647 // XChangeProperty() expects "cardinality" to be long.
648 unsigned long cardinality = opacity * 0x1010101;
650 if (cardinality == 0xffffffff) {
651 XDeleteProperty(xdisplay_, xwindow_,
652 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
654 XChangeProperty(xdisplay_, xwindow_,
655 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
658 reinterpret_cast<unsigned char*>(&cardinality), 1);
662 void DesktopWindowTreeHostX11::SetWindowIcons(
663 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
664 // TODO(erg): The way we handle icons across different versions of chrome
665 // could be substantially improved. The Windows version does its own thing
666 // and only sometimes comes down this code path. The icon stuff in
667 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
668 // coded to be given two images instead of an arbitrary collection of images
669 // so that we can pass to the WM.
671 // All of this could be made much, much better.
672 std::vector<unsigned long> data;
674 if (window_icon.HasRepresentation(1.0f))
675 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
677 if (app_icon.HasRepresentation(1.0f))
678 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
681 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
683 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
686 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
687 switch (modal_type) {
688 case ui::MODAL_TYPE_NONE:
691 // TODO(erg): Figure out under what situations |modal_type| isn't
692 // none. The comment in desktop_native_widget_aura.cc suggests that this
698 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
699 if (urgency_hint_set_ == flash_frame)
702 XWMHints* hints = XGetWMHints(xdisplay_, xwindow_);
704 // The window hasn't had its hints set yet.
705 hints = XAllocWMHints();
709 hints->flags |= XUrgencyHint;
711 hints->flags &= ~XUrgencyHint;
713 XSetWMHints(xdisplay_, xwindow_, hints);
716 urgency_hint_set_ = flash_frame;
719 void DesktopWindowTreeHostX11::OnRootViewLayout() const {
724 long supplied_return;
725 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
727 gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
728 if (minimum.IsEmpty()) {
729 hints.flags &= ~PMinSize;
731 hints.flags |= PMinSize;
732 hints.min_width = minimum.width();
733 hints.min_height = minimum.height();
736 gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
737 if (maximum.IsEmpty()) {
738 hints.flags &= ~PMaxSize;
740 hints.flags |= PMaxSize;
741 hints.max_width = maximum.width();
742 hints.max_height = maximum.height();
745 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
748 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
749 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
752 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
754 x11_capture_.reset();
755 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
759 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
763 ////////////////////////////////////////////////////////////////////////////////
764 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
766 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
770 void DesktopWindowTreeHostX11::Show() {
771 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
774 void DesktopWindowTreeHostX11::Hide() {
775 if (window_mapped_) {
776 XWithdrawWindow(xdisplay_, xwindow_, 0);
777 window_mapped_ = false;
781 void DesktopWindowTreeHostX11::ToggleFullScreen() {
785 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
789 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
790 bool origin_changed = bounds_.origin() != bounds.origin();
791 bool size_changed = bounds_.size() != bounds.size();
792 XWindowChanges changes = {0};
793 unsigned value_mask = 0;
796 // X11 will send an XError at our process if have a 0 sized window.
797 DCHECK_GT(bounds.width(), 0);
798 DCHECK_GT(bounds.height(), 0);
800 changes.width = bounds.width();
801 changes.height = bounds.height();
802 value_mask |= CWHeight | CWWidth;
805 if (origin_changed) {
806 changes.x = bounds.x();
807 changes.y = bounds.y();
808 value_mask |= CWX | CWY;
811 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
813 // Assume that the resize will go through as requested, which should be the
814 // case if we're running without a window manager. If there's a window
815 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
816 // (possibly synthetic) ConfigureNotify about the actual size and correct
821 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
823 OnHostResized(bounds.size());
826 compositor()->ScheduleRedrawRect(gfx::Rect(bounds.size()));
830 gfx::Insets DesktopWindowTreeHostX11::GetInsets() const {
831 return gfx::Insets();
834 void DesktopWindowTreeHostX11::SetInsets(const gfx::Insets& insets) {
837 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
838 return bounds_.origin();
841 void DesktopWindowTreeHostX11::SetCapture() {
842 // This is vaguely based on the old NativeWidgetGtk implementation.
844 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
845 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
846 // a grab that wasn't the X11 pointer grab, but was instead a manual
847 // redirection of the event. (You need to drop into GDK if you want to
848 // perform a raw X11 grab).
850 if (g_current_capture)
851 g_current_capture->OnCaptureReleased();
853 g_current_capture = this;
854 x11_capture_.reset(new X11ScopedCapture(xwindow_));
857 void DesktopWindowTreeHostX11::ReleaseCapture() {
858 if (g_current_capture == this)
859 g_current_capture->OnCaptureReleased();
862 bool DesktopWindowTreeHostX11::QueryMouseLocation(
863 gfx::Point* location_return) {
864 aura::client::CursorClient* cursor_client =
865 aura::client::GetCursorClient(window());
866 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
867 *location_return = gfx::Point(0, 0);
871 ::Window root_return, child_return;
872 int root_x_return, root_y_return, win_x_return, win_y_return;
873 unsigned int mask_return;
874 XQueryPointer(xdisplay_,
878 &root_x_return, &root_y_return,
879 &win_x_return, &win_y_return,
881 *location_return = gfx::Point(
882 std::max(0, std::min(bounds_.width(), win_x_return)),
883 std::max(0, std::min(bounds_.height(), win_y_return)));
884 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
885 win_y_return >= 0 && win_y_return < bounds_.height());
888 bool DesktopWindowTreeHostX11::ConfineCursorToRootWindow() {
893 void DesktopWindowTreeHostX11::UnConfineCursor() {
897 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
898 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
901 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
902 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
903 bounds_.x() + location.x(), bounds_.y() + location.y());
906 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
907 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
908 // the same tap-to-click disabling here that chromeos does.
911 void DesktopWindowTreeHostX11::PostNativeEvent(
912 const base::NativeEvent& native_event) {
915 XEvent xevent = *native_event;
916 xevent.xany.display = xdisplay_;
917 xevent.xany.window = xwindow_;
919 switch (xevent.type) {
926 case ButtonRelease: {
927 // The fields used below are in the same place for all of events
928 // above. Using xmotion from XEvent's unions to avoid repeating
930 xevent.xmotion.root = x_root_window_;
931 xevent.xmotion.time = CurrentTime;
933 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
934 ConvertPointToNativeScreen(&point);
935 xevent.xmotion.x_root = point.x();
936 xevent.xmotion.y_root = point.y();
941 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
944 void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged(
945 float device_scale_factor) {
948 ////////////////////////////////////////////////////////////////////////////////
949 // DesktopWindowTreeHostX11, ui::EventSource implementation:
951 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
955 ////////////////////////////////////////////////////////////////////////////////
956 // DesktopWindowTreeHostX11, private:
958 void DesktopWindowTreeHostX11::InitX11Window(
959 const Widget::InitParams& params) {
960 unsigned long attribute_mask = CWBackPixmap;
961 XSetWindowAttributes swa;
962 memset(&swa, 0, sizeof(swa));
963 swa.background_pixmap = None;
966 switch (params.type) {
967 case Widget::InitParams::TYPE_MENU:
968 swa.override_redirect = True;
969 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
971 case Widget::InitParams::TYPE_TOOLTIP:
972 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
974 case Widget::InitParams::TYPE_POPUP:
975 swa.override_redirect = True;
976 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
978 case Widget::InitParams::TYPE_DRAG:
979 swa.override_redirect = True;
980 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
983 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
986 if (swa.override_redirect)
987 attribute_mask |= CWOverrideRedirect;
989 bounds_ = params.bounds;
990 xwindow_ = XCreateWindow(
991 xdisplay_, x_root_window_,
992 bounds_.x(), bounds_.y(),
993 bounds_.width(), bounds_.height(),
995 CopyFromParent, // depth
997 CopyFromParent, // visual
1000 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
1001 open_windows().push_back(xwindow_);
1003 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1005 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
1006 KeyPressMask | KeyReleaseMask |
1007 EnterWindowMask | LeaveWindowMask |
1008 ExposureMask | VisibilityChangeMask |
1009 StructureNotifyMask | PropertyChangeMask |
1011 XSelectInput(xdisplay_, xwindow_, event_mask);
1014 if (ui::IsXInput2Available())
1015 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
1017 // TODO(erg): We currently only request window deletion events. We also
1018 // should listen for activation events and anything else that GTK+ listens
1019 // for, and do something useful.
1020 ::Atom protocols[2];
1021 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
1022 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1023 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1025 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1026 // the desktop environment.
1027 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1029 // Likewise, the X server needs to know this window's pid so it knows which
1030 // program to kill if the window hangs.
1031 // XChangeProperty() expects "pid" to be long.
1032 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
1033 long pid = params.net_wm_pid;
1036 XChangeProperty(xdisplay_,
1038 atom_cache_.GetAtom("_NET_WM_PID"),
1042 reinterpret_cast<unsigned char*>(&pid), 1);
1044 XChangeProperty(xdisplay_,
1046 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1050 reinterpret_cast<unsigned char*>(&window_type), 1);
1052 // List of window state properties (_NET_WM_STATE) to set, if any.
1053 std::vector< ::Atom> state_atom_list;
1055 // Remove popup windows from taskbar unless overridden.
1056 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1057 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1058 !params.force_show_in_taskbar) {
1059 state_atom_list.push_back(
1060 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1063 // If the window should stay on top of other windows, add the
1064 // _NET_WM_STATE_ABOVE property.
1065 is_always_on_top_ = params.keep_on_top;
1066 if (is_always_on_top_)
1067 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1069 if (params.visible_on_all_workspaces)
1070 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1072 // Setting _NET_WM_STATE by sending a message to the root_window (with
1073 // SetWMSpecState) has no effect here since the window has not yet been
1074 // mapped. So we manually change the state.
1075 if (!state_atom_list.empty()) {
1076 ui::SetAtomArrayProperty(xwindow_,
1082 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1083 ui::SetWindowClassHint(
1084 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1086 if (!params.wm_role_name.empty() ||
1087 params.type == Widget::InitParams::TYPE_POPUP) {
1088 const char kX11WindowRolePopup[] = "popup";
1089 ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1090 std::string(kX11WindowRolePopup) : params.wm_role_name);
1093 if (params.remove_standard_frame) {
1094 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1095 // fullscreen on the window when it matches the desktop size.
1096 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1097 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1100 // If we have a parent, record the parent/child relationship. We use this
1101 // data during destruction to make sure that when we try to close a parent
1102 // window, we also destroy all child windows.
1103 if (params.parent && params.parent->GetHost()) {
1105 params.parent->GetHost()->GetAcceleratedWidget();
1106 window_parent_ = GetHostForXID(parent_xid);
1107 DCHECK(window_parent_);
1108 window_parent_->window_children_.insert(this);
1111 // If we have a delegate which is providing a default window icon, use that
1113 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1114 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1116 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1118 CreateCompositor(GetAcceleratedWidget());
1121 bool DesktopWindowTreeHostX11::IsWindowManagerPresent() {
1122 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
1123 // of WM_Sn selections (where n is a screen number).
1124 return XGetSelectionOwner(
1125 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1128 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1132 memset(&xclient, 0, sizeof(xclient));
1133 xclient.type = ClientMessage;
1134 xclient.xclient.window = xwindow_;
1135 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1136 xclient.xclient.format = 32;
1137 xclient.xclient.data.l[0] =
1138 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1139 xclient.xclient.data.l[1] = state1;
1140 xclient.xclient.data.l[2] = state2;
1141 xclient.xclient.data.l[3] = 1;
1142 xclient.xclient.data.l[4] = 0;
1144 XSendEvent(xdisplay_, x_root_window_, False,
1145 SubstructureRedirectMask | SubstructureNotifyMask,
1149 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1150 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1151 window_properties_.end();
1154 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1155 use_native_frame_ = use_native_frame;
1156 x11_window_event_filter_->SetUseHostWindowBorders(use_native_frame);
1159 void DesktopWindowTreeHostX11::OnCaptureReleased() {
1160 x11_capture_.reset();
1161 g_current_capture = NULL;
1162 OnHostLostWindowCapture();
1163 native_widget_delegate_->OnMouseCaptureLost();
1166 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1167 // In Windows, the native events sent to chrome are separated into client
1168 // and non-client versions of events, which we record on our LocatedEvent
1169 // structures. On X11, we emulate the concept of non-client. Before we pass
1170 // this event to the cross platform event handling framework, we need to
1171 // make sure it is appropriately marked as non-client if it's in the non
1172 // client area, or otherwise, we can get into a state where the a window is
1173 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1174 // despite the mouse button being released.
1176 // We can't do this later in the dispatch process because we share that
1177 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1178 // events, since ash doesn't expect this bit to be set, because it's never
1179 // been set before. (This works on ash on Windows because none of the mouse
1180 // events on the ash desktop are clicking in what Windows considers to be a
1181 // non client area.) Likewise, we won't want to do the following in any
1182 // WindowTreeHost that hosts ash.
1183 if (content_window_ && content_window_->delegate()) {
1184 int flags = event->flags();
1186 content_window_->delegate()->GetNonClientComponent(event->location());
1187 if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1188 flags |= ui::EF_IS_NON_CLIENT;
1189 event->set_flags(flags);
1192 // While we unset the urgency hint when we gain focus, we also must remove it
1193 // on mouse clicks because we can call FlashFrame() on an active window.
1194 if (event->IsAnyButton() || event->IsMouseWheelEvent())
1197 if (!g_current_capture || g_current_capture == this) {
1198 SendEventToProcessor(event);
1200 // Another DesktopWindowTreeHostX11 has installed itself as
1201 // capture. Translate the event's location and dispatch to the other.
1202 event->ConvertLocationToTarget(window(), g_current_capture->window());
1203 g_current_capture->SendEventToProcessor(event);
1207 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1208 if (g_current_capture && g_current_capture != this &&
1209 event->type() == ui::ET_TOUCH_PRESSED) {
1210 event->ConvertLocationToTarget(window(), g_current_capture->window());
1211 g_current_capture->SendEventToProcessor(event);
1213 SendEventToProcessor(event);
1217 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1218 // If a custom window shape was supplied then apply it.
1219 if (custom_window_shape_) {
1220 XShapeCombineRegion(
1221 xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false);
1225 if (!IsMaximized()) {
1226 gfx::Path window_mask;
1227 views::Widget* widget = native_widget_delegate_->AsWidget();
1228 if (widget->non_client_view()) {
1229 // Some frame views define a custom (non-rectangular) window mask. If
1230 // so, use it to define the window shape. If not, fall through.
1231 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1232 if (window_mask.countPoints() > 0) {
1233 Region region = gfx::CreateRegionFromSkPath(window_mask);
1234 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1235 0, 0, region, false);
1236 XDestroyRegion(region);
1242 // If we didn't set the shape for any reason, reset the shaping information.
1243 // How this is done depends on the border style, due to quirks and bugs in
1244 // various window managers.
1245 if (ShouldUseNativeFrame()) {
1246 // If the window has system borders, the mask must be set to null (not a
1247 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1248 // not put borders on a window with a custom shape.
1249 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1251 // Conversely, if the window does not have system borders, the mask must be
1252 // manually set to a rectangle that covers the whole window (not null). This
1253 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1254 // shape causes the hint to disable system borders to be ignored (resulting
1255 // in a double border).
1256 XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
1257 static_cast<unsigned short>(bounds_.height())};
1258 XShapeCombineRectangles(
1259 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1263 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1264 const gfx::ImageSkiaRep& rep,
1265 std::vector<unsigned long>* data) {
1266 int width = rep.GetWidth();
1267 data->push_back(width);
1269 int height = rep.GetHeight();
1270 data->push_back(height);
1272 const SkBitmap& bitmap = rep.sk_bitmap();
1273 SkAutoLockPixels locker(bitmap);
1275 for (int y = 0; y < height; ++y)
1276 for (int x = 0; x < width; ++x)
1277 data->push_back(bitmap.getColor(x, y));
1280 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1282 open_windows_ = new std::list<XID>();
1283 return *open_windows_;
1286 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1287 if (show_state != ui::SHOW_STATE_DEFAULT &&
1288 show_state != ui::SHOW_STATE_NORMAL &&
1289 show_state != ui::SHOW_STATE_INACTIVE) {
1290 // It will behave like SHOW_STATE_NORMAL.
1294 // Before we map the window, set size hints. Otherwise, some window managers
1295 // will ignore toplevel XMoveWindow commands.
1296 XSizeHints size_hints;
1297 size_hints.flags = PPosition;
1298 size_hints.x = bounds_.x();
1299 size_hints.y = bounds_.y();
1300 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1302 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1303 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1304 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1305 if (show_state == ui::SHOW_STATE_INACTIVE) {
1306 unsigned long value = 0;
1307 XChangeProperty(xdisplay_,
1309 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1313 reinterpret_cast<const unsigned char *>(&value),
1316 // TODO(piman): if this window was created in response to an X event, we
1317 // should set the time to the server time of the event that caused this.
1318 // https://crbug.com/355667
1320 xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_USER_TIME"));
1323 XMapWindow(xdisplay_, xwindow_);
1325 // We now block until our window is mapped. Some X11 APIs will crash and
1326 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1328 base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
1329 window_mapped_ = true;
1332 ////////////////////////////////////////////////////////////////////////////////
1333 // DesktopWindowTreeHostX11, MessagePumpDispatcher implementation:
1335 uint32_t DesktopWindowTreeHostX11::Dispatch(const base::NativeEvent& event) {
1336 XEvent* xev = event;
1338 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1339 "event->type", event->type);
1341 // May want to factor CheckXEventForConsistency(xev); into a common location
1342 // since it is called here.
1343 switch (xev->type) {
1346 ui::MouseEvent mouse_event(xev);
1347 DispatchMouseEvent(&mouse_event);
1351 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1352 xev->xexpose.width, xev->xexpose.height);
1353 compositor()->ScheduleRedrawRect(damage_rect);
1357 ui::KeyEvent keydown_event(xev, false);
1358 SendEventToProcessor(&keydown_event);
1362 ui::KeyEvent keyup_event(xev, false);
1363 SendEventToProcessor(&keyup_event);
1367 case ButtonRelease: {
1368 ui::EventType event_type = ui::EventTypeFromNative(xev);
1369 switch (event_type) {
1370 case ui::ET_MOUSEWHEEL: {
1371 ui::MouseWheelEvent mouseev(xev);
1372 DispatchMouseEvent(&mouseev);
1375 case ui::ET_MOUSE_PRESSED:
1376 case ui::ET_MOUSE_RELEASED: {
1377 ui::MouseEvent mouseev(xev);
1378 DispatchMouseEvent(&mouseev);
1381 case ui::ET_UNKNOWN:
1382 // No event is created for X11-release events for mouse-wheel buttons.
1385 NOTREACHED() << event_type;
1390 if (xev->xfocus.mode != NotifyGrab) {
1392 OnHostLostWindowCapture();
1393 X11DesktopHandler::get()->ProcessXEvent(xev);
1395 dispatcher()->OnHostLostMouseGrab();
1399 X11DesktopHandler::get()->ProcessXEvent(xev);
1401 case ConfigureNotify: {
1402 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1403 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1404 // It's possible that the X window may be resized by some other means than
1405 // from within aura (e.g. the X window manager can change the size). Make
1406 // sure the root window size is maintained properly.
1407 int translated_x = xev->xconfigure.x;
1408 int translated_y = xev->xconfigure.y;
1409 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1411 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1412 0, 0, &translated_x, &translated_y, &unused);
1414 gfx::Rect bounds(translated_x, translated_y,
1415 xev->xconfigure.width, xev->xconfigure.height);
1416 bool size_changed = bounds_.size() != bounds.size();
1417 bool origin_changed = bounds_.origin() != bounds.origin();
1418 previous_bounds_ = bounds_;
1421 OnHostResized(bounds.size());
1423 OnHostMoved(bounds_.origin());
1425 ResetWindowRegion();
1428 case GenericEvent: {
1429 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1430 if (!factory->ShouldProcessXI2Event(xev))
1433 ui::EventType type = ui::EventTypeFromNative(xev);
1435 int num_coalesced = 0;
1438 case ui::ET_TOUCH_MOVED:
1439 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1440 if (num_coalesced > 0)
1443 case ui::ET_TOUCH_PRESSED:
1444 case ui::ET_TOUCH_RELEASED: {
1445 ui::TouchEvent touchev(xev);
1446 DispatchTouchEvent(&touchev);
1449 case ui::ET_MOUSE_MOVED:
1450 case ui::ET_MOUSE_DRAGGED:
1451 case ui::ET_MOUSE_PRESSED:
1452 case ui::ET_MOUSE_RELEASED:
1453 case ui::ET_MOUSE_ENTERED:
1454 case ui::ET_MOUSE_EXITED: {
1455 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1456 // If this is a motion event, we want to coalesce all pending motion
1457 // events that are at the top of the queue.
1458 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1459 if (num_coalesced > 0)
1462 ui::MouseEvent mouseev(xev);
1463 DispatchMouseEvent(&mouseev);
1466 case ui::ET_MOUSEWHEEL: {
1467 ui::MouseWheelEvent mouseev(xev);
1468 DispatchMouseEvent(&mouseev);
1471 case ui::ET_SCROLL_FLING_START:
1472 case ui::ET_SCROLL_FLING_CANCEL:
1473 case ui::ET_SCROLL: {
1474 ui::ScrollEvent scrollev(xev);
1475 SendEventToProcessor(&scrollev);
1478 case ui::ET_UNKNOWN:
1484 // If we coalesced an event we need to free its cookie.
1485 if (num_coalesced > 0)
1486 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1490 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1492 OnWindowMapped(xwindow_));
1496 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1498 OnWindowUnmapped(xwindow_));
1501 case ClientMessage: {
1502 Atom message_type = xev->xclient.message_type;
1503 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1504 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1505 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1506 // We have received a close message from the window manager.
1507 OnHostCloseRequested();
1508 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1509 XEvent reply_event = *xev;
1510 reply_event.xclient.window = x_root_window_;
1512 XSendEvent(xdisplay_,
1513 reply_event.xclient.window,
1515 SubstructureRedirectMask | SubstructureNotifyMask,
1518 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1519 drag_drop_client_->OnXdndEnter(xev->xclient);
1520 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1521 drag_drop_client_->OnXdndLeave(xev->xclient);
1522 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1523 drag_drop_client_->OnXdndPosition(xev->xclient);
1524 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1525 drag_drop_client_->OnXdndStatus(xev->xclient);
1526 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1527 drag_drop_client_->OnXdndFinished(xev->xclient);
1528 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1529 drag_drop_client_->OnXdndDrop(xev->xclient);
1533 case MappingNotify: {
1534 switch (xev->xmapping.request) {
1535 case MappingModifier:
1536 case MappingKeyboard:
1537 XRefreshKeyboardMapping(&xev->xmapping);
1539 case MappingPointer:
1540 ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1543 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1548 case MotionNotify: {
1549 // Discard all but the most recent motion event that targets the same
1550 // window with unchanged state.
1552 while (XPending(xev->xany.display)) {
1554 XPeekEvent(xev->xany.display, &next_event);
1555 if (next_event.type == MotionNotify &&
1556 next_event.xmotion.window == xev->xmotion.window &&
1557 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1558 next_event.xmotion.state == xev->xmotion.state) {
1559 XNextEvent(xev->xany.display, &last_event);
1566 ui::MouseEvent mouseev(xev);
1567 DispatchMouseEvent(&mouseev);
1570 case PropertyNotify: {
1571 // Get our new window property state if the WM has told us its changed.
1572 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1574 std::vector< ::Atom> atom_list;
1575 if (xev->xproperty.atom == state &&
1576 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1577 window_properties_.clear();
1578 std::copy(atom_list.begin(), atom_list.end(),
1579 inserter(window_properties_, window_properties_.begin()));
1581 if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
1582 // If we have restored bounds, but WM_STATE no longer claims to be
1583 // maximized, we should clear our restored bounds.
1584 restored_bounds_ = gfx::Rect();
1585 } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
1586 // The request that we become maximized originated from a different
1587 // process. |bounds_| already contains our maximized bounds. Do a
1588 // best effort attempt to get restored bounds by setting it to our
1589 // previously set bounds (and if we get this wrong, we aren't any
1590 // worse off since we'd otherwise be returning our maximized bounds).
1591 restored_bounds_ = previous_bounds_;
1594 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
1595 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1597 // Now that we have different window properties, we may need to
1598 // relayout the window. (The windows code doesn't need this because
1599 // their window change is synchronous.)
1601 // TODO(erg): While this does work, there's a quick flash showing the
1602 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
1603 // those parts of the UI because we receive the sizing event from the
1604 // window manager before we receive the event that changes the
1605 // fullscreen state. Unsure what to do about that.
1606 Widget* widget = native_widget_delegate_->AsWidget();
1607 NonClientView* non_client_view = widget->non_client_view();
1608 // non_client_view may be NULL, especially during creation.
1609 if (non_client_view) {
1610 non_client_view->client_view()->InvalidateLayout();
1611 non_client_view->InvalidateLayout();
1613 widget->GetRootView()->Layout();
1614 // Refresh the window's border, which may need to be updated if we have
1615 // changed the window's maximization state.
1616 ResetWindowRegion();
1620 case SelectionNotify: {
1621 drag_drop_client_->OnSelectionNotify(xev->xselection);
1625 return POST_DISPATCH_NONE;
1628 ////////////////////////////////////////////////////////////////////////////////
1629 // DesktopWindowTreeHost, public:
1632 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1633 internal::NativeWidgetDelegate* native_widget_delegate,
1634 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1635 return new DesktopWindowTreeHostX11(native_widget_delegate,
1636 desktop_native_widget_aura);
1640 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1641 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1643 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
1645 return native_theme;
1648 return ui::NativeTheme::instance();
1651 } // namespace views