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/native_theme/native_theme.h"
37 #include "ui/views/corewm/tooltip_aura.h"
38 #include "ui/views/ime/input_method.h"
39 #include "ui/views/linux_ui/linux_ui.h"
40 #include "ui/views/views_delegate.h"
41 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
42 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
43 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
44 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
45 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
46 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
47 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
48 #include "ui/views/widget/desktop_aura/x11_scoped_capture.h"
49 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
50 #include "ui/wm/core/compound_event_filter.h"
51 #include "ui/wm/core/window_util.h"
55 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
57 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
59 DEFINE_WINDOW_PROPERTY_KEY(
60 aura::Window*, kViewsWindowForRootWindow, NULL);
62 DEFINE_WINDOW_PROPERTY_KEY(
63 DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
67 // Constants that are part of EWMH.
68 const int k_NET_WM_STATE_ADD = 1;
69 const int k_NET_WM_STATE_REMOVE = 0;
71 const char* kAtomsToCache[] = {
81 "_NET_WM_STATE_ABOVE",
82 "_NET_WM_STATE_FULLSCREEN",
83 "_NET_WM_STATE_HIDDEN",
84 "_NET_WM_STATE_MAXIMIZED_HORZ",
85 "_NET_WM_STATE_MAXIMIZED_VERT",
86 "_NET_WM_STATE_SKIP_TASKBAR",
87 "_NET_WM_STATE_STICKY",
89 "_NET_WM_WINDOW_OPACITY",
90 "_NET_WM_WINDOW_TYPE",
91 "_NET_WM_WINDOW_TYPE_DND",
92 "_NET_WM_WINDOW_TYPE_MENU",
93 "_NET_WM_WINDOW_TYPE_NORMAL",
94 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
95 "_NET_WM_WINDOW_TYPE_TOOLTIP",
108 "XdndProxy", // Proxy windows?
117 ////////////////////////////////////////////////////////////////////////////////
118 // DesktopWindowTreeHostX11, public:
120 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
121 internal::NativeWidgetDelegate* native_widget_delegate,
122 DesktopNativeWidgetAura* desktop_native_widget_aura)
123 : close_widget_factory_(this),
124 xdisplay_(gfx::GetXDisplay()),
126 x_root_window_(DefaultRootWindow(xdisplay_)),
127 atom_cache_(xdisplay_, kAtomsToCache),
128 window_mapped_(false),
129 is_fullscreen_(false),
130 is_always_on_top_(false),
131 use_native_frame_(false),
132 drag_drop_client_(NULL),
133 current_cursor_(ui::kCursorNull),
134 native_widget_delegate_(native_widget_delegate),
135 desktop_native_widget_aura_(desktop_native_widget_aura),
136 content_window_(NULL),
137 window_parent_(NULL),
138 custom_window_shape_(NULL),
139 urgency_hint_set_(false) {
142 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
143 window()->ClearProperty(kHostForRootWindow);
144 aura::client::SetWindowMoveClient(window(), NULL);
145 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
146 if (custom_window_shape_)
147 XDestroyRegion(custom_window_shape_);
152 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
153 aura::WindowTreeHost* host =
154 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
155 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
159 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
160 aura::WindowTreeHost* host =
161 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
162 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
166 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
167 std::vector<aura::Window*> windows(open_windows().size());
168 std::transform(open_windows().begin(),
169 open_windows().end(),
171 GetContentWindowForXID);
175 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
179 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
184 open_windows().remove(xwindow_);
185 open_windows().insert(open_windows().begin(), xwindow_);
188 desktop_native_widget_aura_->HandleActivationChanged(active);
190 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
193 void DesktopWindowTreeHostX11::AddObserver(
194 views::DesktopWindowTreeHostObserverX11* observer) {
195 observer_list_.AddObserver(observer);
198 void DesktopWindowTreeHostX11::RemoveObserver(
199 views::DesktopWindowTreeHostObserverX11* observer) {
200 observer_list_.RemoveObserver(observer);
203 void DesktopWindowTreeHostX11::CleanUpWindowList() {
204 delete open_windows_;
205 open_windows_ = NULL;
208 ////////////////////////////////////////////////////////////////////////////////
209 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
211 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
212 const Widget::InitParams& params) {
213 content_window_ = content_window;
215 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
216 // whether we should be proxying requests to another DRWHL.
218 // In some situations, views tries to make a zero sized window, and that
219 // makes us crash. Make sure we have valid sizes.
220 Widget::InitParams sanitized_params = params;
221 if (sanitized_params.bounds.width() == 0)
222 sanitized_params.bounds.set_width(100);
223 if (sanitized_params.bounds.height() == 0)
224 sanitized_params.bounds.set_height(100);
226 InitX11Window(sanitized_params);
229 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
230 const Widget::InitParams& params) {
231 window()->SetProperty(kViewsWindowForRootWindow, content_window_);
232 window()->SetProperty(kHostForRootWindow, this);
234 // Ensure that the X11DesktopHandler exists so that it dispatches activation
236 X11DesktopHandler::get();
238 // TODO(erg): Unify this code once the other consumer goes away.
239 x11_window_event_filter_.reset(new X11WindowEventFilter(this));
240 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
241 !params.remove_standard_frame);
242 desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
243 x11_window_event_filter_.get());
245 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
246 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
248 native_widget_delegate_->OnNativeWidgetCreated(true);
251 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
252 return scoped_ptr<corewm::Tooltip>(
253 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
256 scoped_ptr<aura::client::DragDropClient>
257 DesktopWindowTreeHostX11::CreateDragDropClient(
258 DesktopNativeCursorManager* cursor_manager) {
259 drag_drop_client_ = new DesktopDragDropClientAuraX11(
260 window(), cursor_manager, xdisplay_, xwindow_);
261 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
264 void DesktopWindowTreeHostX11::Close() {
265 // TODO(erg): Might need to do additional hiding tasks here.
267 if (!close_widget_factory_.HasWeakPtrs()) {
268 // And we delay the close so that if we are called from an ATL callback,
269 // we don't destroy the window before the callback returned (as the caller
270 // may delete ourselves on destroy and the ATL callback would still
271 // dereference us when the callback returns).
272 base::MessageLoop::current()->PostTask(
274 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
275 close_widget_factory_.GetWeakPtr()));
279 void DesktopWindowTreeHostX11::CloseNow() {
280 if (xwindow_ == None)
283 x11_capture_.reset();
284 native_widget_delegate_->OnNativeWidgetDestroying();
286 // If we have children, close them. Use a copy for iteration because they'll
287 // remove themselves.
288 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
289 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
290 window_children_copy.begin(); it != window_children_copy.end();
294 DCHECK(window_children_.empty());
296 // If we have a parent, remove ourselves from its children list.
297 if (window_parent_) {
298 window_parent_->window_children_.erase(this);
299 window_parent_ = NULL;
302 // Remove the event listeners we've installed. We need to remove these
303 // because otherwise we get assert during ~WindowEventDispatcher().
304 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
305 x11_window_event_filter_.get());
307 // Destroy the compositor before destroying the |xwindow_| since shutdown
308 // may try to swap, and the swap without a window causes an X error, which
309 // causes a crash with in-process renderer.
312 open_windows().remove(xwindow_);
313 // Actually free our native resources.
314 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
315 XDestroyWindow(xdisplay_, xwindow_);
318 desktop_native_widget_aura_->OnHostClosed();
321 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
325 void DesktopWindowTreeHostX11::ShowWindowWithState(
326 ui::WindowShowState show_state) {
328 MapWindow(show_state);
330 if (show_state == ui::SHOW_STATE_NORMAL ||
331 show_state == ui::SHOW_STATE_MAXIMIZED) {
332 // Note: XFCE ignores a maximize hint given before mapping the window.
333 if (show_state == ui::SHOW_STATE_MAXIMIZED)
338 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
341 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
342 const gfx::Rect& restored_bounds) {
343 restored_bounds_ = restored_bounds;
344 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
347 bool DesktopWindowTreeHostX11::IsVisible() const {
348 return window_mapped_;
351 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) {
352 bool size_changed = bounds_.size() != size;
353 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
354 bounds_.set_size(size);
359 void DesktopWindowTreeHostX11::StackAtTop() {
360 XRaiseWindow(xdisplay_, xwindow_);
363 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
364 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
366 // If |window_|'s transient parent bounds are big enough to contain |size|,
368 if (wm::GetTransientParent(content_window_)) {
369 gfx::Rect transient_parent_rect =
370 wm::GetTransientParent(content_window_)->GetBoundsInScreen();
371 if (transient_parent_rect.height() >= size.height() &&
372 transient_parent_rect.width() >= size.width()) {
373 parent_bounds = transient_parent_rect;
377 gfx::Rect window_bounds(
378 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
379 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
382 // Don't size the window bigger than the parent, otherwise the user may not be
383 // able to close or move it.
384 window_bounds.AdjustToFit(parent_bounds);
386 SetBounds(window_bounds);
389 void DesktopWindowTreeHostX11::GetWindowPlacement(
391 ui::WindowShowState* show_state) const {
394 if (IsFullscreen()) {
395 *show_state = ui::SHOW_STATE_FULLSCREEN;
396 } else if (IsMinimized()) {
397 *show_state = ui::SHOW_STATE_MINIMIZED;
398 } else if (IsMaximized()) {
399 *show_state = ui::SHOW_STATE_MAXIMIZED;
400 } else if (!IsActive()) {
401 *show_state = ui::SHOW_STATE_INACTIVE;
403 *show_state = ui::SHOW_STATE_NORMAL;
407 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
411 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
412 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
413 // needed for View::ConvertPointToScreen() to work
414 // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
415 // asks windows what it thinks the client rect is.
417 // Attempts to calculate the rect by asking the NonClientFrameView what it
418 // thought its GetBoundsForClientView() were broke combobox drop down
423 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
424 // We can't reliably track the restored bounds of a window, but we can get
425 // the 90% case down. When *chrome* is the process that requests maximizing
426 // or restoring bounds, we can record the current bounds before we request
427 // maximization, and clear it when we detect a state change.
428 if (!restored_bounds_.IsEmpty())
429 return restored_bounds_;
431 return GetWindowBoundsInScreen();
434 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
435 std::vector<int> value;
436 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
438 return gfx::Rect(value[0], value[1], value[2], value[3]);
441 // Fetch the geometry of the root window.
444 unsigned int width, height;
445 unsigned int border_width, depth;
446 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
447 &width, &height, &border_width, &depth)) {
449 return gfx::Rect(0, 0, 10, 10);
452 return gfx::Rect(x, y, width, height);
455 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
456 if (custom_window_shape_)
457 XDestroyRegion(custom_window_shape_);
458 custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
460 delete native_region;
463 void DesktopWindowTreeHostX11::Activate() {
467 X11DesktopHandler::get()->ActivateWindow(xwindow_);
470 void DesktopWindowTreeHostX11::Deactivate() {
474 x11_capture_.reset();
475 XLowerWindow(xdisplay_, xwindow_);
478 bool DesktopWindowTreeHostX11::IsActive() const {
479 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
482 void DesktopWindowTreeHostX11::Maximize() {
483 // When we're the process requesting the maximizing, we can accurately keep
484 // track of our restored bounds instead of relying on the heuristics that are
485 // in the PropertyNotify and ConfigureNotify handlers.
486 restored_bounds_ = bounds_;
489 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
490 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
493 void DesktopWindowTreeHostX11::Minimize() {
494 x11_capture_.reset();
495 XIconifyWindow(xdisplay_, xwindow_, 0);
498 void DesktopWindowTreeHostX11::Restore() {
499 SetWMSpecState(false,
500 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
501 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
504 bool DesktopWindowTreeHostX11::IsMaximized() const {
505 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
506 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
509 bool DesktopWindowTreeHostX11::IsMinimized() const {
510 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
513 bool DesktopWindowTreeHostX11::HasCapture() const {
514 return g_current_capture == this;
517 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
518 is_always_on_top_ = always_on_top;
519 SetWMSpecState(always_on_top,
520 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
524 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
525 return is_always_on_top_;
528 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
529 SetWMSpecState(always_visible,
530 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
534 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
535 if (window_title_ == title)
537 window_title_ = title;
538 std::string utf8str = base::UTF16ToUTF8(title);
539 XChangeProperty(xdisplay_,
541 atom_cache_.GetAtom("_NET_WM_NAME"),
542 atom_cache_.GetAtom("UTF8_STRING"),
545 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
547 // TODO(erg): This is technically wrong. So XStoreName and friends expect
548 // this in Host Portable Character Encoding instead of UTF-8, which I believe
549 // is Compound Text. This shouldn't matter 90% of the time since this is the
550 // fallback to the UTF8 property above.
551 XStoreName(xdisplay_, xwindow_, utf8str.c_str());
555 void DesktopWindowTreeHostX11::ClearNativeFocus() {
556 // This method is weird and misnamed. Instead of clearing the native focus,
557 // it sets the focus to our |content_window_|, which will trigger a cascade
558 // of focus changes into views.
559 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
560 content_window_->Contains(
561 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
562 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
566 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
567 const gfx::Vector2d& drag_offset,
568 Widget::MoveLoopSource source,
569 Widget::MoveLoopEscapeBehavior escape_behavior) {
570 aura::client::WindowMoveSource window_move_source =
571 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
572 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
573 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
574 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
575 window_move_source) == aura::client::MOVE_SUCCESSFUL)
576 return Widget::MOVE_LOOP_SUCCESSFUL;
578 return Widget::MOVE_LOOP_CANCELED;
581 void DesktopWindowTreeHostX11::EndMoveLoop() {
582 x11_window_move_client_->EndMoveLoop();
585 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
587 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
590 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
591 return use_native_frame_;
594 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
598 void DesktopWindowTreeHostX11::FrameTypeChanged() {
599 Widget::FrameType new_type =
600 native_widget_delegate_->AsWidget()->frame_type();
601 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
602 // Replace the frame and layout the contents. Even though we don't have a
603 // swapable glass frame like on Windows, we still replace the frame because
604 // the button assets don't update otherwise.
605 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
608 NonClientFrameView* DesktopWindowTreeHostX11::CreateNonClientFrameView() {
612 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
613 is_fullscreen_ = fullscreen;
614 SetWMSpecState(fullscreen,
615 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
619 bool DesktopWindowTreeHostX11::IsFullscreen() const {
620 return is_fullscreen_;
623 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
624 // X server opacity is in terms of 32 bit unsigned int space, and counts from
625 // the opposite direction.
626 // XChangeProperty() expects "cardinality" to be long.
627 unsigned long cardinality = opacity * 0x1010101;
629 if (cardinality == 0xffffffff) {
630 XDeleteProperty(xdisplay_, xwindow_,
631 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
633 XChangeProperty(xdisplay_, xwindow_,
634 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
637 reinterpret_cast<unsigned char*>(&cardinality), 1);
641 void DesktopWindowTreeHostX11::SetWindowIcons(
642 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
643 // TODO(erg): The way we handle icons across different versions of chrome
644 // could be substantially improved. The Windows version does its own thing
645 // and only sometimes comes down this code path. The icon stuff in
646 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
647 // coded to be given two images instead of an arbitrary collection of images
648 // so that we can pass to the WM.
650 // All of this could be made much, much better.
651 std::vector<unsigned long> data;
653 if (window_icon.HasRepresentation(1.0f))
654 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
656 if (app_icon.HasRepresentation(1.0f))
657 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
660 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
662 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
665 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
666 switch (modal_type) {
667 case ui::MODAL_TYPE_NONE:
670 // TODO(erg): Figure out under what situations |modal_type| isn't
671 // none. The comment in desktop_native_widget_aura.cc suggests that this
677 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
678 if (urgency_hint_set_ == flash_frame)
681 XWMHints* hints = XGetWMHints(xdisplay_, xwindow_);
683 // The window hasn't had its hints set yet.
684 hints = XAllocWMHints();
688 hints->flags |= XUrgencyHint;
690 hints->flags &= ~XUrgencyHint;
692 XSetWMHints(xdisplay_, xwindow_, hints);
695 urgency_hint_set_ = flash_frame;
698 void DesktopWindowTreeHostX11::OnRootViewLayout() const {
703 long supplied_return;
704 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
706 gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
707 if (minimum.IsEmpty()) {
708 hints.flags &= ~PMinSize;
710 hints.flags |= PMinSize;
711 hints.min_width = minimum.width();
712 hints.min_height = minimum.height();
715 gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
716 if (maximum.IsEmpty()) {
717 hints.flags &= ~PMaxSize;
719 hints.flags |= PMaxSize;
720 hints.max_width = maximum.width();
721 hints.max_height = maximum.height();
724 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
727 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
728 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
731 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
733 x11_capture_.reset();
734 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
738 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
742 ////////////////////////////////////////////////////////////////////////////////
743 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
745 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
749 void DesktopWindowTreeHostX11::Show() {
750 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
753 void DesktopWindowTreeHostX11::Hide() {
754 if (window_mapped_) {
755 XWithdrawWindow(xdisplay_, xwindow_, 0);
756 window_mapped_ = false;
760 void DesktopWindowTreeHostX11::ToggleFullScreen() {
764 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
768 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
769 bool origin_changed = bounds_.origin() != bounds.origin();
770 bool size_changed = bounds_.size() != bounds.size();
771 XWindowChanges changes = {0};
772 unsigned value_mask = 0;
775 // X11 will send an XError at our process if have a 0 sized window.
776 DCHECK_GT(bounds.width(), 0);
777 DCHECK_GT(bounds.height(), 0);
779 changes.width = bounds.width();
780 changes.height = bounds.height();
781 value_mask |= CWHeight | CWWidth;
784 if (origin_changed) {
785 changes.x = bounds.x();
786 changes.y = bounds.y();
787 value_mask |= CWX | CWY;
790 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
792 // Assume that the resize will go through as requested, which should be the
793 // case if we're running without a window manager. If there's a window
794 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
795 // (possibly synthetic) ConfigureNotify about the actual size and correct
800 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
802 OnHostResized(bounds.size());
804 compositor()->ScheduleRedrawRect(gfx::Rect(bounds.size()));
807 gfx::Insets DesktopWindowTreeHostX11::GetInsets() const {
808 return gfx::Insets();
811 void DesktopWindowTreeHostX11::SetInsets(const gfx::Insets& insets) {
814 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
815 return bounds_.origin();
818 void DesktopWindowTreeHostX11::SetCapture() {
819 // This is vaguely based on the old NativeWidgetGtk implementation.
821 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
822 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
823 // a grab that wasn't the X11 pointer grab, but was instead a manual
824 // redirection of the event. (You need to drop into GDK if you want to
825 // perform a raw X11 grab).
827 if (g_current_capture)
828 g_current_capture->OnCaptureReleased();
830 g_current_capture = this;
831 x11_capture_.reset(new X11ScopedCapture(xwindow_));
834 void DesktopWindowTreeHostX11::ReleaseCapture() {
835 if (g_current_capture == this)
836 g_current_capture->OnCaptureReleased();
839 bool DesktopWindowTreeHostX11::QueryMouseLocation(
840 gfx::Point* location_return) {
841 aura::client::CursorClient* cursor_client =
842 aura::client::GetCursorClient(window());
843 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
844 *location_return = gfx::Point(0, 0);
848 ::Window root_return, child_return;
849 int root_x_return, root_y_return, win_x_return, win_y_return;
850 unsigned int mask_return;
851 XQueryPointer(xdisplay_,
855 &root_x_return, &root_y_return,
856 &win_x_return, &win_y_return,
858 *location_return = gfx::Point(
859 std::max(0, std::min(bounds_.width(), win_x_return)),
860 std::max(0, std::min(bounds_.height(), win_y_return)));
861 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
862 win_y_return >= 0 && win_y_return < bounds_.height());
865 bool DesktopWindowTreeHostX11::ConfineCursorToRootWindow() {
870 void DesktopWindowTreeHostX11::UnConfineCursor() {
874 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
875 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
878 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
879 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
880 bounds_.x() + location.x(), bounds_.y() + location.y());
883 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
884 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
885 // the same tap-to-click disabling here that chromeos does.
888 void DesktopWindowTreeHostX11::PostNativeEvent(
889 const base::NativeEvent& native_event) {
892 XEvent xevent = *native_event;
893 xevent.xany.display = xdisplay_;
894 xevent.xany.window = xwindow_;
896 switch (xevent.type) {
903 case ButtonRelease: {
904 // The fields used below are in the same place for all of events
905 // above. Using xmotion from XEvent's unions to avoid repeating
907 xevent.xmotion.root = x_root_window_;
908 xevent.xmotion.time = CurrentTime;
910 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
911 ConvertPointToNativeScreen(&point);
912 xevent.xmotion.x_root = point.x();
913 xevent.xmotion.y_root = point.y();
918 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
921 void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged(
922 float device_scale_factor) {
925 ////////////////////////////////////////////////////////////////////////////////
926 // DesktopWindowTreeHostX11, ui::EventSource implementation:
928 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
932 ////////////////////////////////////////////////////////////////////////////////
933 // DesktopWindowTreeHostX11, private:
935 void DesktopWindowTreeHostX11::InitX11Window(
936 const Widget::InitParams& params) {
937 unsigned long attribute_mask = CWBackPixmap;
938 XSetWindowAttributes swa;
939 memset(&swa, 0, sizeof(swa));
940 swa.background_pixmap = None;
943 switch (params.type) {
944 case Widget::InitParams::TYPE_MENU:
945 swa.override_redirect = True;
946 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
948 case Widget::InitParams::TYPE_TOOLTIP:
949 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
951 case Widget::InitParams::TYPE_POPUP:
952 swa.override_redirect = True;
953 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
955 case Widget::InitParams::TYPE_DRAG:
956 swa.override_redirect = True;
957 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
960 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
963 if (swa.override_redirect)
964 attribute_mask |= CWOverrideRedirect;
966 bounds_ = params.bounds;
967 xwindow_ = XCreateWindow(
968 xdisplay_, x_root_window_,
969 bounds_.x(), bounds_.y(),
970 bounds_.width(), bounds_.height(),
972 CopyFromParent, // depth
974 CopyFromParent, // visual
977 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
978 open_windows().push_back(xwindow_);
980 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
982 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
983 KeyPressMask | KeyReleaseMask |
984 EnterWindowMask | LeaveWindowMask |
985 ExposureMask | VisibilityChangeMask |
986 StructureNotifyMask | PropertyChangeMask |
988 XSelectInput(xdisplay_, xwindow_, event_mask);
991 if (ui::IsXInput2Available())
992 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
994 // TODO(erg): We currently only request window deletion events. We also
995 // should listen for activation events and anything else that GTK+ listens
996 // for, and do something useful.
998 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
999 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1000 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1002 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1003 // the desktop environment.
1004 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1006 // Likewise, the X server needs to know this window's pid so it knows which
1007 // program to kill if the window hangs.
1008 // XChangeProperty() expects "pid" to be long.
1009 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
1010 long pid = params.net_wm_pid;
1013 XChangeProperty(xdisplay_,
1015 atom_cache_.GetAtom("_NET_WM_PID"),
1019 reinterpret_cast<unsigned char*>(&pid), 1);
1021 XChangeProperty(xdisplay_,
1023 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1027 reinterpret_cast<unsigned char*>(&window_type), 1);
1029 // List of window state properties (_NET_WM_STATE) to set, if any.
1030 std::vector< ::Atom> state_atom_list;
1032 // Remove popup windows from taskbar unless overridden.
1033 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1034 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1035 !params.force_show_in_taskbar) {
1036 state_atom_list.push_back(
1037 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1040 // If the window should stay on top of other windows, add the
1041 // _NET_WM_STATE_ABOVE property.
1042 is_always_on_top_ = params.keep_on_top;
1043 if (is_always_on_top_)
1044 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1046 if (params.visible_on_all_workspaces)
1047 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1049 // Setting _NET_WM_STATE by sending a message to the root_window (with
1050 // SetWMSpecState) has no effect here since the window has not yet been
1051 // mapped. So we manually change the state.
1052 if (!state_atom_list.empty()) {
1053 ui::SetAtomArrayProperty(xwindow_,
1059 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1060 ui::SetWindowClassHint(
1061 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1063 if (!params.wm_role_name.empty() ||
1064 params.type == Widget::InitParams::TYPE_POPUP) {
1065 const char kX11WindowRolePopup[] = "popup";
1066 ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1067 std::string(kX11WindowRolePopup) : params.wm_role_name);
1070 if (params.remove_standard_frame) {
1071 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1072 // fullscreen on the window when it matches the desktop size.
1073 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1074 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1077 // If we have a parent, record the parent/child relationship. We use this
1078 // data during destruction to make sure that when we try to close a parent
1079 // window, we also destroy all child windows.
1080 if (params.parent && params.parent->GetHost()) {
1082 params.parent->GetHost()->GetAcceleratedWidget();
1083 window_parent_ = GetHostForXID(parent_xid);
1084 DCHECK(window_parent_);
1085 window_parent_->window_children_.insert(this);
1088 // If we have a delegate which is providing a default window icon, use that
1090 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1091 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1093 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1095 CreateCompositor(GetAcceleratedWidget());
1098 bool DesktopWindowTreeHostX11::IsWindowManagerPresent() {
1099 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
1100 // of WM_Sn selections (where n is a screen number).
1101 return XGetSelectionOwner(
1102 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1105 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1109 memset(&xclient, 0, sizeof(xclient));
1110 xclient.type = ClientMessage;
1111 xclient.xclient.window = xwindow_;
1112 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1113 xclient.xclient.format = 32;
1114 xclient.xclient.data.l[0] =
1115 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1116 xclient.xclient.data.l[1] = state1;
1117 xclient.xclient.data.l[2] = state2;
1118 xclient.xclient.data.l[3] = 1;
1119 xclient.xclient.data.l[4] = 0;
1121 XSendEvent(xdisplay_, x_root_window_, False,
1122 SubstructureRedirectMask | SubstructureNotifyMask,
1126 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1127 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1128 window_properties_.end();
1131 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1132 use_native_frame_ = use_native_frame;
1133 x11_window_event_filter_->SetUseHostWindowBorders(use_native_frame);
1136 void DesktopWindowTreeHostX11::OnCaptureReleased() {
1137 x11_capture_.reset();
1138 g_current_capture = NULL;
1139 OnHostLostWindowCapture();
1140 native_widget_delegate_->OnMouseCaptureLost();
1143 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1144 // In Windows, the native events sent to chrome are separated into client
1145 // and non-client versions of events, which we record on our LocatedEvent
1146 // structures. On X11, we emulate the concept of non-client. Before we pass
1147 // this event to the cross platform event handling framework, we need to
1148 // make sure it is appropriately marked as non-client if it's in the non
1149 // client area, or otherwise, we can get into a state where the a window is
1150 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1151 // despite the mouse button being released.
1153 // We can't do this later in the dispatch process because we share that
1154 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1155 // events, since ash doesn't expect this bit to be set, because it's never
1156 // been set before. (This works on ash on Windows because none of the mouse
1157 // events on the ash desktop are clicking in what Windows considers to be a
1158 // non client area.) Likewise, we won't want to do the following in any
1159 // WindowTreeHost that hosts ash.
1160 if (content_window_ && content_window_->delegate()) {
1161 int flags = event->flags();
1163 content_window_->delegate()->GetNonClientComponent(event->location());
1164 if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1165 flags |= ui::EF_IS_NON_CLIENT;
1166 event->set_flags(flags);
1169 // While we unset the urgency hint when we gain focus, we also must remove it
1170 // on mouse clicks because we can call FlashFrame() on an active window.
1171 if (event->IsAnyButton() || event->IsMouseWheelEvent())
1174 if (!g_current_capture || g_current_capture == this) {
1175 SendEventToProcessor(event);
1177 // Another DesktopWindowTreeHostX11 has installed itself as
1178 // capture. Translate the event's location and dispatch to the other.
1179 event->ConvertLocationToTarget(window(), g_current_capture->window());
1180 g_current_capture->SendEventToProcessor(event);
1184 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1185 if (g_current_capture && g_current_capture != this &&
1186 event->type() == ui::ET_TOUCH_PRESSED) {
1187 event->ConvertLocationToTarget(window(), g_current_capture->window());
1188 g_current_capture->SendEventToProcessor(event);
1190 SendEventToProcessor(event);
1194 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1195 // If a custom window shape was supplied then apply it.
1196 if (custom_window_shape_) {
1197 XShapeCombineRegion(
1198 xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false);
1202 if (!IsMaximized()) {
1203 gfx::Path window_mask;
1204 views::Widget* widget = native_widget_delegate_->AsWidget();
1205 if (widget->non_client_view()) {
1206 // Some frame views define a custom (non-rectangular) window mask. If
1207 // so, use it to define the window shape. If not, fall through.
1208 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1209 if (window_mask.countPoints() > 0) {
1210 Region region = gfx::CreateRegionFromSkPath(window_mask);
1211 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1212 0, 0, region, false);
1213 XDestroyRegion(region);
1219 // If we didn't set the shape for any reason, reset the shaping information.
1220 // How this is done depends on the border style, due to quirks and bugs in
1221 // various window managers.
1222 if (ShouldUseNativeFrame()) {
1223 // If the window has system borders, the mask must be set to null (not a
1224 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1225 // not put borders on a window with a custom shape.
1226 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1228 // Conversely, if the window does not have system borders, the mask must be
1229 // manually set to a rectangle that covers the whole window (not null). This
1230 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1231 // shape causes the hint to disable system borders to be ignored (resulting
1232 // in a double border).
1233 XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
1234 static_cast<unsigned short>(bounds_.height())};
1235 XShapeCombineRectangles(
1236 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1240 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1241 const gfx::ImageSkiaRep& rep,
1242 std::vector<unsigned long>* data) {
1243 int width = rep.GetWidth();
1244 data->push_back(width);
1246 int height = rep.GetHeight();
1247 data->push_back(height);
1249 const SkBitmap& bitmap = rep.sk_bitmap();
1250 SkAutoLockPixels locker(bitmap);
1252 for (int y = 0; y < height; ++y)
1253 for (int x = 0; x < width; ++x)
1254 data->push_back(bitmap.getColor(x, y));
1257 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1259 open_windows_ = new std::list<XID>();
1260 return *open_windows_;
1263 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1264 if (show_state != ui::SHOW_STATE_DEFAULT &&
1265 show_state != ui::SHOW_STATE_NORMAL &&
1266 show_state != ui::SHOW_STATE_INACTIVE) {
1267 // It will behave like SHOW_STATE_NORMAL.
1271 // Before we map the window, set size hints. Otherwise, some window managers
1272 // will ignore toplevel XMoveWindow commands.
1273 XSizeHints size_hints;
1274 size_hints.flags = PPosition;
1275 size_hints.x = bounds_.x();
1276 size_hints.y = bounds_.y();
1277 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1279 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1280 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1281 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1282 if (show_state == ui::SHOW_STATE_INACTIVE) {
1283 unsigned long value = 0;
1284 XChangeProperty(xdisplay_,
1286 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1290 reinterpret_cast<const unsigned char *>(&value),
1293 // TODO(piman): if this window was created in response to an X event, we
1294 // should set the time to the server time of the event that caused this.
1295 // https://crbug.com/355667
1297 xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_USER_TIME"));
1300 XMapWindow(xdisplay_, xwindow_);
1302 // We now block until our window is mapped. Some X11 APIs will crash and
1303 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1305 base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
1306 window_mapped_ = true;
1309 ////////////////////////////////////////////////////////////////////////////////
1310 // DesktopWindowTreeHostX11, MessagePumpDispatcher implementation:
1312 uint32_t DesktopWindowTreeHostX11::Dispatch(const base::NativeEvent& event) {
1313 XEvent* xev = event;
1315 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1316 "event->type", event->type);
1318 // May want to factor CheckXEventForConsistency(xev); into a common location
1319 // since it is called here.
1320 switch (xev->type) {
1323 if (!g_current_capture)
1324 X11DesktopHandler::get()->ProcessXEvent(xev);
1325 ui::MouseEvent mouse_event(xev);
1326 DispatchMouseEvent(&mouse_event);
1330 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1331 xev->xexpose.width, xev->xexpose.height);
1332 compositor()->ScheduleRedrawRect(damage_rect);
1336 ui::KeyEvent keydown_event(xev, false);
1337 SendEventToProcessor(&keydown_event);
1341 ui::KeyEvent keyup_event(xev, false);
1342 SendEventToProcessor(&keyup_event);
1346 case ButtonRelease: {
1347 ui::EventType event_type = ui::EventTypeFromNative(xev);
1348 switch (event_type) {
1349 case ui::ET_MOUSEWHEEL: {
1350 ui::MouseWheelEvent mouseev(xev);
1351 DispatchMouseEvent(&mouseev);
1354 case ui::ET_MOUSE_PRESSED:
1355 case ui::ET_MOUSE_RELEASED: {
1356 ui::MouseEvent mouseev(xev);
1357 DispatchMouseEvent(&mouseev);
1360 case ui::ET_UNKNOWN:
1361 // No event is created for X11-release events for mouse-wheel buttons.
1364 NOTREACHED() << event_type;
1369 if (xev->xfocus.mode != NotifyGrab) {
1371 OnHostLostWindowCapture();
1373 dispatcher()->OnHostLostMouseGrab();
1377 X11DesktopHandler::get()->ProcessXEvent(xev);
1379 case ConfigureNotify: {
1380 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1381 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1382 // It's possible that the X window may be resized by some other means than
1383 // from within aura (e.g. the X window manager can change the size). Make
1384 // sure the root window size is maintained properly.
1385 int translated_x = xev->xconfigure.x;
1386 int translated_y = xev->xconfigure.y;
1387 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1389 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1390 0, 0, &translated_x, &translated_y, &unused);
1392 gfx::Rect bounds(translated_x, translated_y,
1393 xev->xconfigure.width, xev->xconfigure.height);
1394 bool size_changed = bounds_.size() != bounds.size();
1395 bool origin_changed = bounds_.origin() != bounds.origin();
1396 previous_bounds_ = bounds_;
1399 OnHostResized(bounds.size());
1401 OnHostMoved(bounds_.origin());
1402 ResetWindowRegion();
1405 case GenericEvent: {
1406 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1407 if (!factory->ShouldProcessXI2Event(xev))
1410 ui::EventType type = ui::EventTypeFromNative(xev);
1412 int num_coalesced = 0;
1415 case ui::ET_TOUCH_MOVED:
1416 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1417 if (num_coalesced > 0)
1420 case ui::ET_TOUCH_PRESSED:
1421 case ui::ET_TOUCH_RELEASED: {
1422 ui::TouchEvent touchev(xev);
1423 DispatchTouchEvent(&touchev);
1426 case ui::ET_MOUSE_MOVED:
1427 case ui::ET_MOUSE_DRAGGED:
1428 case ui::ET_MOUSE_PRESSED:
1429 case ui::ET_MOUSE_RELEASED:
1430 case ui::ET_MOUSE_ENTERED:
1431 case ui::ET_MOUSE_EXITED: {
1432 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1433 // If this is a motion event, we want to coalesce all pending motion
1434 // events that are at the top of the queue.
1435 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1436 if (num_coalesced > 0)
1439 ui::MouseEvent mouseev(xev);
1440 DispatchMouseEvent(&mouseev);
1443 case ui::ET_MOUSEWHEEL: {
1444 ui::MouseWheelEvent mouseev(xev);
1445 DispatchMouseEvent(&mouseev);
1448 case ui::ET_SCROLL_FLING_START:
1449 case ui::ET_SCROLL_FLING_CANCEL:
1450 case ui::ET_SCROLL: {
1451 ui::ScrollEvent scrollev(xev);
1452 SendEventToProcessor(&scrollev);
1455 case ui::ET_UNKNOWN:
1461 // If we coalesced an event we need to free its cookie.
1462 if (num_coalesced > 0)
1463 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1467 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1469 OnWindowMapped(xwindow_));
1473 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1475 OnWindowUnmapped(xwindow_));
1478 case ClientMessage: {
1479 Atom message_type = xev->xclient.message_type;
1480 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1481 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1482 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1483 // We have received a close message from the window manager.
1484 OnHostCloseRequested();
1485 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1486 XEvent reply_event = *xev;
1487 reply_event.xclient.window = x_root_window_;
1489 XSendEvent(xdisplay_,
1490 reply_event.xclient.window,
1492 SubstructureRedirectMask | SubstructureNotifyMask,
1495 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1496 drag_drop_client_->OnXdndEnter(xev->xclient);
1497 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1498 drag_drop_client_->OnXdndLeave(xev->xclient);
1499 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1500 drag_drop_client_->OnXdndPosition(xev->xclient);
1501 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1502 drag_drop_client_->OnXdndStatus(xev->xclient);
1503 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1504 drag_drop_client_->OnXdndFinished(xev->xclient);
1505 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1506 drag_drop_client_->OnXdndDrop(xev->xclient);
1510 case MappingNotify: {
1511 switch (xev->xmapping.request) {
1512 case MappingModifier:
1513 case MappingKeyboard:
1514 XRefreshKeyboardMapping(&xev->xmapping);
1516 case MappingPointer:
1517 ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1520 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1525 case MotionNotify: {
1526 // Discard all but the most recent motion event that targets the same
1527 // window with unchanged state.
1529 while (XPending(xev->xany.display)) {
1531 XPeekEvent(xev->xany.display, &next_event);
1532 if (next_event.type == MotionNotify &&
1533 next_event.xmotion.window == xev->xmotion.window &&
1534 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1535 next_event.xmotion.state == xev->xmotion.state) {
1536 XNextEvent(xev->xany.display, &last_event);
1543 ui::MouseEvent mouseev(xev);
1544 DispatchMouseEvent(&mouseev);
1547 case PropertyNotify: {
1548 // Get our new window property state if the WM has told us its changed.
1549 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1551 std::vector< ::Atom> atom_list;
1552 if (xev->xproperty.atom == state &&
1553 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1554 window_properties_.clear();
1555 std::copy(atom_list.begin(), atom_list.end(),
1556 inserter(window_properties_, window_properties_.begin()));
1558 if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
1559 // If we have restored bounds, but WM_STATE no longer claims to be
1560 // maximized, we should clear our restored bounds.
1561 restored_bounds_ = gfx::Rect();
1562 } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
1563 // The request that we become maximized originated from a different
1564 // process. |bounds_| already contains our maximized bounds. Do a
1565 // best effort attempt to get restored bounds by setting it to our
1566 // previously set bounds (and if we get this wrong, we aren't any
1567 // worse off since we'd otherwise be returning our maximized bounds).
1568 restored_bounds_ = previous_bounds_;
1571 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
1572 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1574 // Now that we have different window properties, we may need to
1575 // relayout the window. (The windows code doesn't need this because
1576 // their window change is synchronous.)
1578 // TODO(erg): While this does work, there's a quick flash showing the
1579 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
1580 // those parts of the UI because we receive the sizing event from the
1581 // window manager before we receive the event that changes the
1582 // fullscreen state. Unsure what to do about that.
1583 Widget* widget = native_widget_delegate_->AsWidget();
1584 NonClientView* non_client_view = widget->non_client_view();
1585 // non_client_view may be NULL, especially during creation.
1586 if (non_client_view) {
1587 non_client_view->client_view()->InvalidateLayout();
1588 non_client_view->InvalidateLayout();
1590 widget->GetRootView()->Layout();
1591 // Refresh the window's border, which may need to be updated if we have
1592 // changed the window's maximization state.
1593 ResetWindowRegion();
1597 case SelectionNotify: {
1598 drag_drop_client_->OnSelectionNotify(xev->xselection);
1602 return POST_DISPATCH_NONE;
1605 ////////////////////////////////////////////////////////////////////////////////
1606 // DesktopWindowTreeHost, public:
1609 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1610 internal::NativeWidgetDelegate* native_widget_delegate,
1611 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1612 return new DesktopWindowTreeHostX11(native_widget_delegate,
1613 desktop_native_widget_aura);
1617 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1618 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1620 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
1622 return native_theme;
1625 return ui::NativeTheme::instance();
1628 } // namespace views