1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
7 #include <X11/extensions/shape.h>
8 #include <X11/extensions/XInput2.h>
10 #include <X11/Xregion.h>
11 #include <X11/Xutil.h>
13 #include "base/basictypes.h"
14 #include "base/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/client/user_action_client.h"
22 #include "ui/aura/root_window.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_property.h"
25 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.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/compound_event_filter.h"
38 #include "ui/views/corewm/corewm_switches.h"
39 #include "ui/views/corewm/tooltip_aura.h"
40 #include "ui/views/corewm/window_util.h"
41 #include "ui/views/ime/input_method.h"
42 #include "ui/views/linux_ui/linux_ui.h"
43 #include "ui/views/views_delegate.h"
44 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
45 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
46 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
47 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
48 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
49 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
50 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
51 #include "ui/views/widget/desktop_aura/x11_scoped_capture.h"
52 #include "ui/views/widget/desktop_aura/x11_window_event_filter.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 // Standard Linux mouse buttons for going back and forward.
69 const int kBackMouseButton = 8;
70 const int kForwardMouseButton = 9;
72 // Constants that are part of EWMH.
73 const int k_NET_WM_STATE_ADD = 1;
74 const int k_NET_WM_STATE_REMOVE = 0;
76 const char* kAtomsToCache[] = {
86 "_NET_WM_STATE_ABOVE",
87 "_NET_WM_STATE_FULLSCREEN",
88 "_NET_WM_STATE_HIDDEN",
89 "_NET_WM_STATE_MAXIMIZED_HORZ",
90 "_NET_WM_STATE_MAXIMIZED_VERT",
91 "_NET_WM_STATE_SKIP_TASKBAR",
92 "_NET_WM_WINDOW_OPACITY",
93 "_NET_WM_WINDOW_TYPE",
94 "_NET_WM_WINDOW_TYPE_DND",
95 "_NET_WM_WINDOW_TYPE_MENU",
96 "_NET_WM_WINDOW_TYPE_NORMAL",
97 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
98 "_NET_WM_WINDOW_TYPE_TOOLTIP",
111 "XdndProxy", // Proxy windows?
120 ////////////////////////////////////////////////////////////////////////////////
121 // DesktopWindowTreeHostX11, public:
123 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
124 internal::NativeWidgetDelegate* native_widget_delegate,
125 DesktopNativeWidgetAura* desktop_native_widget_aura)
126 : close_widget_factory_(this),
127 xdisplay_(gfx::GetXDisplay()),
129 x_root_window_(DefaultRootWindow(xdisplay_)),
130 atom_cache_(xdisplay_, kAtomsToCache),
131 window_mapped_(false),
132 is_fullscreen_(false),
133 is_always_on_top_(false),
135 drag_drop_client_(NULL),
136 current_cursor_(ui::kCursorNull),
137 native_widget_delegate_(native_widget_delegate),
138 desktop_native_widget_aura_(desktop_native_widget_aura),
139 content_window_(NULL),
140 window_parent_(NULL),
141 custom_window_shape_(NULL) {
144 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
145 root_window_->window()->ClearProperty(kHostForRootWindow);
146 aura::client::SetWindowMoveClient(root_window_->window(), NULL);
147 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(root_window_);
148 if (custom_window_shape_)
149 XDestroyRegion(custom_window_shape_);
153 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
154 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
155 return root ? root->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
159 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
160 aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
161 return root ? root->window()->GetProperty(kHostForRootWindow) : NULL;
165 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
166 std::vector<aura::Window*> windows(open_windows().size());
167 std::transform(open_windows().begin(),
168 open_windows().end(),
170 GetContentWindowForXID);
174 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
178 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
181 delegate_->OnHostActivated();
182 open_windows().remove(xwindow_);
183 open_windows().insert(open_windows().begin(), xwindow_);
186 desktop_native_widget_aura_->HandleActivationChanged(active);
188 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
191 void DesktopWindowTreeHostX11::AddObserver(
192 views::DesktopWindowTreeHostObserverX11* observer) {
193 observer_list_.AddObserver(observer);
196 void DesktopWindowTreeHostX11::RemoveObserver(
197 views::DesktopWindowTreeHostObserverX11* observer) {
198 observer_list_.RemoveObserver(observer);
201 void DesktopWindowTreeHostX11::CleanUpWindowList() {
202 delete open_windows_;
203 open_windows_ = NULL;
206 ////////////////////////////////////////////////////////////////////////////////
207 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
209 void DesktopWindowTreeHostX11::Init(
210 aura::Window* content_window,
211 const Widget::InitParams& params,
212 aura::RootWindow::CreateParams* rw_create_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);
228 rw_create_params->initial_bounds = bounds_;
229 rw_create_params->host = this;
232 void DesktopWindowTreeHostX11::OnRootWindowCreated(
233 aura::RootWindow* root,
234 const Widget::InitParams& params) {
237 root_window_->window()->SetProperty(kViewsWindowForRootWindow,
239 root_window_->window()->SetProperty(kHostForRootWindow, this);
240 delegate_ = root_window_;
242 // If we're given a parent, we need to mark ourselves as transient to another
243 // window. Otherwise activation gets screwy.
244 gfx::NativeView parent = params.parent;
245 if (!params.child && params.parent) {
246 corewm::AddTransientChild(parent, content_window_);
249 // Ensure that the X11DesktopHandler exists so that it dispatches activation
251 X11DesktopHandler::get();
253 // TODO(erg): Unify this code once the other consumer goes away.
254 x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_, this));
255 x11_window_event_filter_->SetUseHostWindowBorders(
256 params.type == Widget::InitParams::TYPE_WINDOW &&
257 !params.remove_standard_frame);
258 desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
259 x11_window_event_filter_.get());
261 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
262 aura::client::SetWindowMoveClient(root_window_->window(),
263 x11_window_move_client_.get());
265 native_widget_delegate_->OnNativeWidgetCreated(true);
268 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
269 return scoped_ptr<corewm::Tooltip>(
270 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
273 scoped_ptr<aura::client::DragDropClient>
274 DesktopWindowTreeHostX11::CreateDragDropClient(
275 DesktopNativeCursorManager* cursor_manager) {
276 drag_drop_client_ = new DesktopDragDropClientAuraX11(
277 root_window_->window(), cursor_manager, xdisplay_, xwindow_);
278 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
281 void DesktopWindowTreeHostX11::Close() {
282 // TODO(erg): Might need to do additional hiding tasks here.
284 if (!close_widget_factory_.HasWeakPtrs()) {
285 // And we delay the close so that if we are called from an ATL callback,
286 // we don't destroy the window before the callback returned (as the caller
287 // may delete ourselves on destroy and the ATL callback would still
288 // dereference us when the callback returns).
289 base::MessageLoop::current()->PostTask(
291 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
292 close_widget_factory_.GetWeakPtr()));
296 void DesktopWindowTreeHostX11::CloseNow() {
297 if (xwindow_ == None)
300 x11_capture_.reset();
301 native_widget_delegate_->OnNativeWidgetDestroying();
303 // If we have children, close them. Use a copy for iteration because they'll
304 // remove themselves.
305 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
306 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
307 window_children_copy.begin(); it != window_children_copy.end();
311 DCHECK(window_children_.empty());
313 // If we have a parent, remove ourselves from its children list.
314 if (window_parent_) {
315 window_parent_->window_children_.erase(this);
316 window_parent_ = NULL;
319 // Remove the event listeners we've installed. We need to remove these
320 // because otherwise we get assert during ~RootWindow().
321 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
322 x11_window_event_filter_.get());
324 // Destroy the compositor before destroying the |xwindow_| since shutdown
325 // may try to swap, and the swap without a window causes an X error, which
326 // causes a crash with in-process renderer.
329 open_windows().remove(xwindow_);
330 // Actually free our native resources.
331 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
332 XDestroyWindow(xdisplay_, xwindow_);
335 desktop_native_widget_aura_->OnHostClosed();
338 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
342 void DesktopWindowTreeHostX11::ShowWindowWithState(
343 ui::WindowShowState show_state) {
345 MapWindow(show_state);
347 if (show_state == ui::SHOW_STATE_NORMAL ||
348 show_state == ui::SHOW_STATE_MAXIMIZED) {
352 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
355 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
356 const gfx::Rect& restored_bounds) {
357 restored_bounds_ = restored_bounds;
362 bool DesktopWindowTreeHostX11::IsVisible() const {
363 return window_mapped_;
366 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) {
367 bool size_changed = bounds_.size() != size;
368 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
369 bounds_.set_size(size);
371 NotifyHostResized(size);
374 void DesktopWindowTreeHostX11::StackAtTop() {
375 XRaiseWindow(xdisplay_, xwindow_);
378 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
379 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
381 // If |window_|'s transient parent bounds are big enough to contain |size|,
383 if (corewm::GetTransientParent(content_window_)) {
384 gfx::Rect transient_parent_rect =
385 corewm::GetTransientParent(content_window_)->GetBoundsInScreen();
386 if (transient_parent_rect.height() >= size.height() &&
387 transient_parent_rect.width() >= size.width()) {
388 parent_bounds = transient_parent_rect;
392 gfx::Rect window_bounds(
393 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
394 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
397 // Don't size the window bigger than the parent, otherwise the user may not be
398 // able to close or move it.
399 window_bounds.AdjustToFit(parent_bounds);
401 SetBounds(window_bounds);
404 void DesktopWindowTreeHostX11::GetWindowPlacement(
406 ui::WindowShowState* show_state) const {
409 if (IsFullscreen()) {
410 *show_state = ui::SHOW_STATE_FULLSCREEN;
411 } else if (IsMinimized()) {
412 *show_state = ui::SHOW_STATE_MINIMIZED;
413 } else if (IsMaximized()) {
414 *show_state = ui::SHOW_STATE_MAXIMIZED;
415 } else if (!IsActive()) {
416 *show_state = ui::SHOW_STATE_INACTIVE;
418 *show_state = ui::SHOW_STATE_NORMAL;
422 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
426 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
427 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
428 // needed for View::ConvertPointToScreen() to work
429 // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
430 // asks windows what it thinks the client rect is.
432 // Attempts to calculate the rect by asking the NonClientFrameView what it
433 // thought its GetBoundsForClientView() were broke combobox drop down
438 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
439 // We can't reliably track the restored bounds of a window, but we can get
440 // the 90% case down. When *chrome* is the process that requests maximizing
441 // or restoring bounds, we can record the current bounds before we request
442 // maximization, and clear it when we detect a state change.
443 if (!restored_bounds_.IsEmpty())
444 return restored_bounds_;
446 return GetWindowBoundsInScreen();
449 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
450 std::vector<int> value;
451 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
453 return gfx::Rect(value[0], value[1], value[2], value[3]);
456 // Fetch the geometry of the root window.
459 unsigned int width, height;
460 unsigned int border_width, depth;
461 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
462 &width, &height, &border_width, &depth)) {
464 return gfx::Rect(0, 0, 10, 10);
467 return gfx::Rect(x, y, width, height);
470 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
471 if (custom_window_shape_)
472 XDestroyRegion(custom_window_shape_);
473 custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
475 delete native_region;
478 void DesktopWindowTreeHostX11::Activate() {
482 X11DesktopHandler::get()->ActivateWindow(xwindow_);
485 void DesktopWindowTreeHostX11::Deactivate() {
489 x11_capture_.reset();
490 X11DesktopHandler::get()->DeactivateWindow(xwindow_);
493 bool DesktopWindowTreeHostX11::IsActive() const {
494 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
497 void DesktopWindowTreeHostX11::Maximize() {
498 // When we're the process requesting the maximizing, we can accurately keep
499 // track of our restored bounds instead of relying on the heuristics that are
500 // in the PropertyNotify and ConfigureNotify handlers.
501 restored_bounds_ = bounds_;
504 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
505 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
508 void DesktopWindowTreeHostX11::Minimize() {
509 x11_capture_.reset();
510 XIconifyWindow(xdisplay_, xwindow_, 0);
513 void DesktopWindowTreeHostX11::Restore() {
514 SetWMSpecState(false,
515 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
516 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
519 bool DesktopWindowTreeHostX11::IsMaximized() const {
520 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
521 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
524 bool DesktopWindowTreeHostX11::IsMinimized() const {
525 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
529 bool DesktopWindowTreeHostX11::HasCapture() const {
530 return g_current_capture == this;
533 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
534 is_always_on_top_ = always_on_top;
535 SetWMSpecState(always_on_top,
536 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
540 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
541 return is_always_on_top_;
544 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
545 if (window_title_ == title)
547 window_title_ = title;
548 std::string utf8str = base::UTF16ToUTF8(title);
549 XChangeProperty(xdisplay_,
551 atom_cache_.GetAtom("_NET_WM_NAME"),
552 atom_cache_.GetAtom("UTF8_STRING"),
555 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
557 // TODO(erg): This is technically wrong. So XStoreName and friends expect
558 // this in Host Portable Character Encoding instead of UTF-8, which I believe
559 // is Compound Text. This shouldn't matter 90% of the time since this is the
560 // fallback to the UTF8 property above.
561 XStoreName(xdisplay_, xwindow_, utf8str.c_str());
565 void DesktopWindowTreeHostX11::ClearNativeFocus() {
566 // This method is weird and misnamed. Instead of clearing the native focus,
567 // it sets the focus to our |content_window_|, which will trigger a cascade
568 // of focus changes into views.
569 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
570 content_window_->Contains(
571 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
572 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
576 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
577 const gfx::Vector2d& drag_offset,
578 Widget::MoveLoopSource source,
579 Widget::MoveLoopEscapeBehavior escape_behavior) {
580 aura::client::WindowMoveSource window_move_source =
581 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
582 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
583 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
584 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
585 window_move_source) == aura::client::MOVE_SUCCESSFUL)
586 return Widget::MOVE_LOOP_SUCCESSFUL;
588 return Widget::MOVE_LOOP_CANCELED;
591 void DesktopWindowTreeHostX11::EndMoveLoop() {
592 x11_window_move_client_->EndMoveLoop();
595 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
597 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
600 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() {
604 void DesktopWindowTreeHostX11::FrameTypeChanged() {
605 // Replace the frame and layout the contents. Even though we don't have a
606 // swapable glass frame like on Windows, we still replace the frame because
607 // the button assets don't update otherwise.
608 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
611 NonClientFrameView* DesktopWindowTreeHostX11::CreateNonClientFrameView() {
615 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
616 is_fullscreen_ = fullscreen;
617 SetWMSpecState(fullscreen,
618 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
622 bool DesktopWindowTreeHostX11::IsFullscreen() const {
623 return is_fullscreen_;
626 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
627 // X server opacity is in terms of 32 bit unsigned int space, and counts from
628 // the opposite direction.
629 // XChangeProperty() expects "cardinality" to be long.
630 unsigned long cardinality = opacity * 0x1010101;
632 if (cardinality == 0xffffffff) {
633 XDeleteProperty(xdisplay_, xwindow_,
634 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
636 XChangeProperty(xdisplay_, xwindow_,
637 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
640 reinterpret_cast<unsigned char*>(&cardinality), 1);
644 void DesktopWindowTreeHostX11::SetWindowIcons(
645 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
646 // TODO(erg): The way we handle icons across different versions of chrome
647 // could be substantially improved. The Windows version does its own thing
648 // and only sometimes comes down this code path. The icon stuff in
649 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
650 // coded to be given two images instead of an arbitrary collection of images
651 // so that we can pass to the WM.
653 // All of this could be made much, much better.
654 std::vector<unsigned long> data;
656 if (window_icon.HasRepresentation(1.0f))
657 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
659 if (app_icon.HasRepresentation(1.0f))
660 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
663 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
665 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
668 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
669 switch (modal_type) {
670 case ui::MODAL_TYPE_NONE:
673 // TODO(erg): Figure out under what situations |modal_type| isn't
674 // none. The comment in desktop_native_widget_aura.cc suggests that this
680 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
685 void DesktopWindowTreeHostX11::OnRootViewLayout() const {
690 long supplied_return;
691 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
693 gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
694 if (minimum.IsEmpty()) {
695 hints.flags &= ~PMinSize;
697 hints.flags |= PMinSize;
698 hints.min_width = minimum.width();
699 hints.min_height = minimum.height();
702 gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
703 if (maximum.IsEmpty()) {
704 hints.flags &= ~PMaxSize;
706 hints.flags |= PMaxSize;
707 hints.max_width = maximum.width();
708 hints.max_height = maximum.height();
711 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
714 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
715 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
718 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
720 x11_capture_.reset();
721 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
725 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
729 ////////////////////////////////////////////////////////////////////////////////
730 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
732 aura::RootWindow* DesktopWindowTreeHostX11::GetRootWindow() {
736 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
740 void DesktopWindowTreeHostX11::Show() {
741 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
744 void DesktopWindowTreeHostX11::Hide() {
745 if (window_mapped_) {
746 XWithdrawWindow(xdisplay_, xwindow_, 0);
747 window_mapped_ = false;
751 void DesktopWindowTreeHostX11::ToggleFullScreen() {
755 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
759 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
760 bool origin_changed = bounds_.origin() != bounds.origin();
761 bool size_changed = bounds_.size() != bounds.size();
762 XWindowChanges changes = {0};
763 unsigned value_mask = 0;
766 // X11 will send an XError at our process if have a 0 sized window.
767 DCHECK_GT(bounds.width(), 0);
768 DCHECK_GT(bounds.height(), 0);
770 changes.width = bounds.width();
771 changes.height = bounds.height();
772 value_mask |= CWHeight | CWWidth;
775 if (origin_changed) {
776 changes.x = bounds.x();
777 changes.y = bounds.y();
778 value_mask |= CWX | CWY;
781 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
783 // Assume that the resize will go through as requested, which should be the
784 // case if we're running without a window manager. If there's a window
785 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
786 // (possibly synthetic) ConfigureNotify about the actual size and correct
791 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
793 NotifyHostResized(bounds.size());
795 compositor()->ScheduleRedrawRect(gfx::Rect(bounds.size()));
798 gfx::Insets DesktopWindowTreeHostX11::GetInsets() const {
799 return gfx::Insets();
802 void DesktopWindowTreeHostX11::SetInsets(const gfx::Insets& insets) {
805 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
806 return bounds_.origin();
809 void DesktopWindowTreeHostX11::SetCapture() {
810 // This is vaguely based on the old NativeWidgetGtk implementation.
812 // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
813 // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
814 // a grab that wasn't the X11 pointer grab, but was instead a manual
815 // redirection of the event. (You need to drop into GDK if you want to
816 // perform a raw X11 grab).
818 if (g_current_capture)
819 g_current_capture->OnCaptureReleased();
821 g_current_capture = this;
822 x11_capture_.reset(new X11ScopedCapture(xwindow_));
825 void DesktopWindowTreeHostX11::ReleaseCapture() {
826 if (g_current_capture == this)
827 g_current_capture->OnCaptureReleased();
830 void DesktopWindowTreeHostX11::SetCursor(gfx::NativeCursor cursor) {
831 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
834 bool DesktopWindowTreeHostX11::QueryMouseLocation(
835 gfx::Point* location_return) {
836 aura::client::CursorClient* cursor_client =
837 aura::client::GetCursorClient(GetRootWindow()->window());
838 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
839 *location_return = gfx::Point(0, 0);
843 ::Window root_return, child_return;
844 int root_x_return, root_y_return, win_x_return, win_y_return;
845 unsigned int mask_return;
846 XQueryPointer(xdisplay_,
850 &root_x_return, &root_y_return,
851 &win_x_return, &win_y_return,
853 *location_return = gfx::Point(
854 std::max(0, std::min(bounds_.width(), win_x_return)),
855 std::max(0, std::min(bounds_.height(), win_y_return)));
856 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
857 win_y_return >= 0 && win_y_return < bounds_.height());
860 bool DesktopWindowTreeHostX11::ConfineCursorToRootWindow() {
865 void DesktopWindowTreeHostX11::UnConfineCursor() {
869 void DesktopWindowTreeHostX11::OnCursorVisibilityChanged(bool show) {
870 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
871 // the same tap-to-click disabling here that chromeos does.
874 void DesktopWindowTreeHostX11::MoveCursorTo(const gfx::Point& location) {
875 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
876 bounds_.x() + location.x(), bounds_.y() + location.y());
879 void DesktopWindowTreeHostX11::PostNativeEvent(
880 const base::NativeEvent& native_event) {
883 XEvent xevent = *native_event;
884 xevent.xany.display = xdisplay_;
885 xevent.xany.window = xwindow_;
887 switch (xevent.type) {
894 case ButtonRelease: {
895 // The fields used below are in the same place for all of events
896 // above. Using xmotion from XEvent's unions to avoid repeating
898 xevent.xmotion.root = x_root_window_;
899 xevent.xmotion.time = CurrentTime;
901 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
902 ConvertPointToNativeScreen(&point);
903 xevent.xmotion.x_root = point.x();
904 xevent.xmotion.y_root = point.y();
909 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
912 void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged(
913 float device_scale_factor) {
916 void DesktopWindowTreeHostX11::PrepareForShutdown() {
919 ////////////////////////////////////////////////////////////////////////////////
920 // DesktopWindowTreeHostX11, private:
922 void DesktopWindowTreeHostX11::InitX11Window(
923 const Widget::InitParams& params) {
924 unsigned long attribute_mask = CWBackPixmap;
925 XSetWindowAttributes swa;
926 memset(&swa, 0, sizeof(swa));
927 swa.background_pixmap = None;
930 switch (params.type) {
931 case Widget::InitParams::TYPE_MENU:
932 swa.override_redirect = True;
933 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
935 case Widget::InitParams::TYPE_TOOLTIP:
936 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
938 case Widget::InitParams::TYPE_POPUP:
939 swa.override_redirect = True;
940 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
942 case Widget::InitParams::TYPE_DRAG:
943 swa.override_redirect = True;
944 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
947 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
950 if (swa.override_redirect)
951 attribute_mask |= CWOverrideRedirect;
953 bounds_ = params.bounds;
954 xwindow_ = XCreateWindow(
955 xdisplay_, x_root_window_,
956 bounds_.x(), bounds_.y(),
957 bounds_.width(), bounds_.height(),
959 CopyFromParent, // depth
961 CopyFromParent, // visual
964 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
965 open_windows().push_back(xwindow_);
967 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
969 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
970 KeyPressMask | KeyReleaseMask |
971 EnterWindowMask | LeaveWindowMask |
972 ExposureMask | VisibilityChangeMask |
973 StructureNotifyMask | PropertyChangeMask |
975 XSelectInput(xdisplay_, xwindow_, event_mask);
978 if (ui::IsXInput2Available())
979 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
981 // TODO(erg): We currently only request window deletion events. We also
982 // should listen for activation events and anything else that GTK+ listens
983 // for, and do something useful.
985 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
986 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
987 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
989 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
990 // the desktop environment.
991 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
993 // Likewise, the X server needs to know this window's pid so it knows which
994 // program to kill if the window hangs.
995 // XChangeProperty() expects "pid" to be long.
996 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
997 long pid = params.net_wm_pid;
1000 XChangeProperty(xdisplay_,
1002 atom_cache_.GetAtom("_NET_WM_PID"),
1006 reinterpret_cast<unsigned char*>(&pid), 1);
1008 XChangeProperty(xdisplay_,
1010 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1014 reinterpret_cast<unsigned char*>(&window_type), 1);
1016 // List of window state properties (_NET_WM_STATE) to set, if any.
1017 std::vector< ::Atom> state_atom_list;
1019 // Remove popup windows from taskbar unless overridden.
1020 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1021 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1022 !params.force_show_in_taskbar) {
1023 state_atom_list.push_back(
1024 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1027 // If the window should stay on top of other windows, add the
1028 // _NET_WM_STATE_ABOVE property.
1029 is_always_on_top_ = params.keep_on_top;
1030 if (is_always_on_top_)
1031 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1033 // Setting _NET_WM_STATE by sending a message to the root_window (with
1034 // SetWMSpecState) has no effect here since the window has not yet been
1035 // mapped. So we manually change the state.
1036 if (!state_atom_list.empty()) {
1037 ui::SetAtomArrayProperty(xwindow_,
1043 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1044 ui::SetWindowClassHint(
1045 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1047 if (!params.wm_role_name.empty() ||
1048 params.type == Widget::InitParams::TYPE_POPUP) {
1049 const char kX11WindowRolePopup[] = "popup";
1050 ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1051 std::string(kX11WindowRolePopup) : params.wm_role_name);
1054 // If we have a parent, record the parent/child relationship. We use this
1055 // data during destruction to make sure that when we try to close a parent
1056 // window, we also destroy all child windows.
1057 if (params.parent && params.parent->GetDispatcher()) {
1059 params.parent->GetDispatcher()->host()->GetAcceleratedWidget();
1060 window_parent_ = GetHostForXID(parent_xid);
1061 DCHECK(window_parent_);
1062 window_parent_->window_children_.insert(this);
1065 // If we have a delegate which is providing a default window icon, use that
1067 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1068 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1070 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1072 CreateCompositor(GetAcceleratedWidget());
1075 bool DesktopWindowTreeHostX11::IsWindowManagerPresent() {
1076 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
1077 // of WM_Sn selections (where n is a screen number).
1078 return XGetSelectionOwner(
1079 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1082 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1086 memset(&xclient, 0, sizeof(xclient));
1087 xclient.type = ClientMessage;
1088 xclient.xclient.window = xwindow_;
1089 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1090 xclient.xclient.format = 32;
1091 xclient.xclient.data.l[0] =
1092 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1093 xclient.xclient.data.l[1] = state1;
1094 xclient.xclient.data.l[2] = state2;
1095 xclient.xclient.data.l[3] = 1;
1096 xclient.xclient.data.l[4] = 0;
1098 XSendEvent(xdisplay_, x_root_window_, False,
1099 SubstructureRedirectMask | SubstructureNotifyMask,
1103 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1104 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1105 window_properties_.end();
1108 void DesktopWindowTreeHostX11::OnCaptureReleased() {
1109 x11_capture_.reset();
1110 g_current_capture = NULL;
1111 delegate_->OnHostLostWindowCapture();
1112 native_widget_delegate_->OnMouseCaptureLost();
1115 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1116 if (!g_current_capture || g_current_capture == this) {
1117 delegate_->OnHostMouseEvent(event);
1119 // Another DesktopWindowTreeHostX11 has installed itself as
1120 // capture. Translate the event's location and dispatch to the other.
1121 event->ConvertLocationToTarget(root_window_->window(),
1122 g_current_capture->root_window_->window());
1123 g_current_capture->delegate_->OnHostMouseEvent(event);
1127 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1128 if (g_current_capture && g_current_capture != this &&
1129 event->type() == ui::ET_TOUCH_PRESSED) {
1130 event->ConvertLocationToTarget(root_window_->window(),
1131 g_current_capture->root_window_->window());
1132 g_current_capture->delegate_->OnHostTouchEvent(event);
1134 delegate_->OnHostTouchEvent(event);
1138 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1139 // If a custom window shape was supplied then apply it.
1140 if (custom_window_shape_) {
1141 XShapeCombineRegion(
1142 xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false);
1146 if (!IsMaximized()) {
1147 gfx::Path window_mask;
1148 views::Widget* widget = native_widget_delegate_->AsWidget();
1149 if (widget->non_client_view()) {
1150 // Some frame views define a custom (non-rectangular) window mask. If
1151 // so, use it to define the window shape. If not, fall through.
1152 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1153 if (window_mask.countPoints() > 0) {
1154 Region region = gfx::CreateRegionFromSkPath(window_mask);
1155 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1156 0, 0, region, false);
1157 XDestroyRegion(region);
1163 // If we didn't set the shape for any reason, reset the shaping information
1164 // by ShapeSet-ing with our bounds rect.
1165 XRectangle r = { 0, 0, static_cast<unsigned short>(bounds_.width()),
1166 static_cast<unsigned short>(bounds_.height()) };
1167 XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding,
1168 0, 0, &r, 1, ShapeSet, YXBanded);
1171 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1172 const gfx::ImageSkiaRep& rep,
1173 std::vector<unsigned long>* data) {
1174 int width = rep.GetWidth();
1175 data->push_back(width);
1177 int height = rep.GetHeight();
1178 data->push_back(height);
1180 const SkBitmap& bitmap = rep.sk_bitmap();
1181 SkAutoLockPixels locker(bitmap);
1183 for (int y = 0; y < height; ++y)
1184 for (int x = 0; x < width; ++x)
1185 data->push_back(bitmap.getColor(x, y));
1188 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1190 open_windows_ = new std::list<XID>();
1191 return *open_windows_;
1194 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1195 if (show_state != ui::SHOW_STATE_DEFAULT &&
1196 show_state != ui::SHOW_STATE_NORMAL &&
1197 show_state != ui::SHOW_STATE_INACTIVE) {
1198 // It will behave like SHOW_STATE_NORMAL.
1202 // Before we map the window, set size hints. Otherwise, some window managers
1203 // will ignore toplevel XMoveWindow commands.
1204 XSizeHints size_hints;
1205 size_hints.flags = PPosition;
1206 size_hints.x = bounds_.x();
1207 size_hints.y = bounds_.y();
1208 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1211 wm_hints.flags = InputHint | StateHint;
1212 // If SHOW_STATE_INACTIVE, tell the window manager that the window is not
1213 // focusable. This will make the window inactive upon creation.
1214 wm_hints.input = show_state != ui::SHOW_STATE_INACTIVE;
1215 wm_hints.initial_state = NormalState;
1216 XSetWMHints(xdisplay_, xwindow_, &wm_hints);
1218 XMapWindow(xdisplay_, xwindow_);
1220 // We now block until our window is mapped. Some X11 APIs will crash and
1221 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1223 base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
1224 window_mapped_ = true;
1226 // The window has been created and mapped. It should now accept input.
1227 if (show_state == ui::SHOW_STATE_INACTIVE) {
1229 wm_hints.flags = InputHint;
1230 wm_hints.input = true;
1231 // Tell the window manager that the window is now focusable.
1232 XSetWMHints(xdisplay_, xwindow_, &wm_hints);
1236 ////////////////////////////////////////////////////////////////////////////////
1237 // DesktopWindowTreeHostX11, MessagePumpDispatcher implementation:
1239 bool DesktopWindowTreeHostX11::Dispatch(const base::NativeEvent& event) {
1240 XEvent* xev = event;
1242 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1243 "event->type", event->type);
1245 // May want to factor CheckXEventForConsistency(xev); into a common location
1246 // since it is called here.
1247 switch (xev->type) {
1250 if (!g_current_capture)
1251 X11DesktopHandler::get()->ProcessXEvent(xev);
1252 ui::MouseEvent mouse_event(xev);
1253 DispatchMouseEvent(&mouse_event);
1257 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1258 xev->xexpose.width, xev->xexpose.height);
1259 compositor()->ScheduleRedrawRect(damage_rect);
1263 ui::KeyEvent keydown_event(xev, false);
1264 delegate_->OnHostKeyEvent(&keydown_event);
1268 ui::KeyEvent keyup_event(xev, false);
1269 delegate_->OnHostKeyEvent(&keyup_event);
1273 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
1274 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
1275 aura::client::UserActionClient* gesture_client =
1276 aura::client::GetUserActionClient(root_window_->window());
1277 if (gesture_client) {
1278 gesture_client->OnUserAction(
1279 static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
1280 aura::client::UserActionClient::BACK :
1281 aura::client::UserActionClient::FORWARD);
1286 case ButtonRelease: {
1287 ui::EventType event_type = ui::EventTypeFromNative(xev);
1288 switch (event_type) {
1289 case ui::ET_MOUSEWHEEL: {
1290 ui::MouseWheelEvent mouseev(xev);
1291 DispatchMouseEvent(&mouseev);
1294 case ui::ET_MOUSE_PRESSED:
1295 case ui::ET_MOUSE_RELEASED: {
1296 ui::MouseEvent mouseev(xev);
1297 DispatchMouseEvent(&mouseev);
1300 case ui::ET_UNKNOWN:
1301 // No event is created for X11-release events for mouse-wheel buttons.
1304 NOTREACHED() << event_type;
1309 if (xev->xfocus.mode != NotifyGrab) {
1311 delegate_->OnHostLostWindowCapture();
1313 delegate_->OnHostLostMouseGrab();
1316 case ConfigureNotify: {
1317 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1318 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1319 // It's possible that the X window may be resized by some other means than
1320 // from within aura (e.g. the X window manager can change the size). Make
1321 // sure the root window size is maintained properly.
1322 int translated_x = xev->xconfigure.x;
1323 int translated_y = xev->xconfigure.y;
1324 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1326 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1327 0, 0, &translated_x, &translated_y, &unused);
1329 gfx::Rect bounds(translated_x, translated_y,
1330 xev->xconfigure.width, xev->xconfigure.height);
1331 bool size_changed = bounds_.size() != bounds.size();
1332 bool origin_changed = bounds_.origin() != bounds.origin();
1333 previous_bounds_ = bounds_;
1336 NotifyHostResized(bounds.size());
1338 delegate_->OnHostMoved(bounds_.origin());
1339 ResetWindowRegion();
1342 case GenericEvent: {
1343 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1344 if (!factory->ShouldProcessXI2Event(xev))
1347 ui::EventType type = ui::EventTypeFromNative(xev);
1349 int num_coalesced = 0;
1352 case ui::ET_TOUCH_MOVED:
1353 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1354 if (num_coalesced > 0)
1357 case ui::ET_TOUCH_PRESSED:
1358 case ui::ET_TOUCH_RELEASED: {
1359 ui::TouchEvent touchev(xev);
1360 DispatchTouchEvent(&touchev);
1363 case ui::ET_MOUSE_MOVED:
1364 case ui::ET_MOUSE_DRAGGED:
1365 case ui::ET_MOUSE_PRESSED:
1366 case ui::ET_MOUSE_RELEASED:
1367 case ui::ET_MOUSE_ENTERED:
1368 case ui::ET_MOUSE_EXITED: {
1369 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1370 // If this is a motion event, we want to coalesce all pending motion
1371 // events that are at the top of the queue.
1372 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1373 if (num_coalesced > 0)
1375 } else if (type == ui::ET_MOUSE_PRESSED) {
1376 XIDeviceEvent* xievent =
1377 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1378 int button = xievent->detail;
1379 if (button == kBackMouseButton || button == kForwardMouseButton) {
1380 aura::client::UserActionClient* gesture_client =
1381 aura::client::GetUserActionClient(
1382 delegate_->AsRootWindow()->window());
1383 if (gesture_client) {
1384 bool reverse_direction =
1385 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
1386 gesture_client->OnUserAction(
1387 (button == kBackMouseButton && !reverse_direction) ||
1388 (button == kForwardMouseButton && reverse_direction) ?
1389 aura::client::UserActionClient::BACK :
1390 aura::client::UserActionClient::FORWARD);
1394 } else if (type == ui::ET_MOUSE_RELEASED) {
1395 XIDeviceEvent* xievent =
1396 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1397 int button = xievent->detail;
1398 if (button == kBackMouseButton || button == kForwardMouseButton) {
1399 // We've already passed the back/forward mouse down to the user
1400 // action client; we want to swallow the corresponding release.
1404 ui::MouseEvent mouseev(xev);
1405 DispatchMouseEvent(&mouseev);
1408 case ui::ET_MOUSEWHEEL: {
1409 ui::MouseWheelEvent mouseev(xev);
1410 DispatchMouseEvent(&mouseev);
1413 case ui::ET_SCROLL_FLING_START:
1414 case ui::ET_SCROLL_FLING_CANCEL:
1415 case ui::ET_SCROLL: {
1416 ui::ScrollEvent scrollev(xev);
1417 delegate_->OnHostScrollEvent(&scrollev);
1420 case ui::ET_UNKNOWN:
1426 // If we coalesced an event we need to free its cookie.
1427 if (num_coalesced > 0)
1428 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1432 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1434 OnWindowMapped(xwindow_));
1438 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1440 OnWindowUnmapped(xwindow_));
1443 case ClientMessage: {
1444 Atom message_type = xev->xclient.message_type;
1445 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1446 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1447 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1448 // We have received a close message from the window manager.
1449 root_window_->OnWindowTreeHostCloseRequested();
1450 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1451 XEvent reply_event = *xev;
1452 reply_event.xclient.window = x_root_window_;
1454 XSendEvent(xdisplay_,
1455 reply_event.xclient.window,
1457 SubstructureRedirectMask | SubstructureNotifyMask,
1460 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1461 drag_drop_client_->OnXdndEnter(xev->xclient);
1462 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1463 drag_drop_client_->OnXdndLeave(xev->xclient);
1464 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1465 drag_drop_client_->OnXdndPosition(xev->xclient);
1466 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1467 drag_drop_client_->OnXdndStatus(xev->xclient);
1468 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1469 drag_drop_client_->OnXdndFinished(xev->xclient);
1470 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1471 drag_drop_client_->OnXdndDrop(xev->xclient);
1475 case MappingNotify: {
1476 switch (xev->xmapping.request) {
1477 case MappingModifier:
1478 case MappingKeyboard:
1479 XRefreshKeyboardMapping(&xev->xmapping);
1480 root_window_->OnKeyboardMappingChanged();
1482 case MappingPointer:
1483 ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1486 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1491 case MotionNotify: {
1492 // Discard all but the most recent motion event that targets the same
1493 // window with unchanged state.
1495 while (XPending(xev->xany.display)) {
1497 XPeekEvent(xev->xany.display, &next_event);
1498 if (next_event.type == MotionNotify &&
1499 next_event.xmotion.window == xev->xmotion.window &&
1500 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1501 next_event.xmotion.state == xev->xmotion.state) {
1502 XNextEvent(xev->xany.display, &last_event);
1509 ui::MouseEvent mouseev(xev);
1510 DispatchMouseEvent(&mouseev);
1513 case PropertyNotify: {
1514 // Get our new window property state if the WM has told us its changed.
1515 ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1517 std::vector< ::Atom> atom_list;
1518 if (xev->xproperty.atom == state &&
1519 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1520 window_properties_.clear();
1521 std::copy(atom_list.begin(), atom_list.end(),
1522 inserter(window_properties_, window_properties_.begin()));
1524 if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
1525 // If we have restored bounds, but WM_STATE no longer claims to be
1526 // maximized, we should clear our restored bounds.
1527 restored_bounds_ = gfx::Rect();
1528 } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
1529 // The request that we become maximized originated from a different
1530 // process. |bounds_| already contains our maximized bounds. Do a
1531 // best effort attempt to get restored bounds by setting it to our
1532 // previously set bounds (and if we get this wrong, we aren't any
1533 // worse off since we'd otherwise be returning our maximized bounds).
1534 restored_bounds_ = previous_bounds_;
1537 is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
1538 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1540 // Now that we have different window properties, we may need to
1541 // relayout the window. (The windows code doesn't need this because
1542 // their window change is synchronous.)
1544 // TODO(erg): While this does work, there's a quick flash showing the
1545 // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
1546 // those parts of the UI because we receive the sizing event from the
1547 // window manager before we receive the event that changes the
1548 // fullscreen state. Unsure what to do about that.
1549 Widget* widget = native_widget_delegate_->AsWidget();
1550 NonClientView* non_client_view = widget->non_client_view();
1551 // non_client_view may be NULL, especially during creation.
1552 if (non_client_view) {
1553 non_client_view->client_view()->InvalidateLayout();
1554 non_client_view->InvalidateLayout();
1556 widget->GetRootView()->Layout();
1557 // Refresh the window's border, which may need to be updated if we have
1558 // changed the window's maximization state.
1559 ResetWindowRegion();
1563 case SelectionNotify: {
1564 drag_drop_client_->OnSelectionNotify(xev->xselection);
1571 ////////////////////////////////////////////////////////////////////////////////
1572 // DesktopWindowTreeHost, public:
1575 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1576 internal::NativeWidgetDelegate* native_widget_delegate,
1577 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1578 return new DesktopWindowTreeHostX11(native_widget_delegate,
1579 desktop_native_widget_aura);
1583 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1584 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1586 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
1588 return native_theme;
1591 return ui::NativeTheme::instance();
1594 } // namespace views