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/command_line.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/trace_event/trace_event.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/devices/x11/device_data_manager_x11.h"
28 #include "ui/events/devices/x11/device_list_cache_x11.h"
29 #include "ui/events/devices/x11/touch_factory_x11.h"
30 #include "ui/events/event_utils.h"
31 #include "ui/events/platform/platform_event_source.h"
32 #include "ui/events/platform/x11/x11_event_source.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/geometry/insets.h"
35 #include "ui/gfx/geometry/size_conversions.h"
36 #include "ui/gfx/image/image_skia.h"
37 #include "ui/gfx/image/image_skia_rep.h"
38 #include "ui/gfx/path.h"
39 #include "ui/gfx/path_x11.h"
40 #include "ui/gfx/screen.h"
41 #include "ui/native_theme/native_theme.h"
42 #include "ui/views/corewm/tooltip_aura.h"
43 #include "ui/views/ime/input_method.h"
44 #include "ui/views/linux_ui/linux_ui.h"
45 #include "ui/views/views_delegate.h"
46 #include "ui/views/views_switches.h"
47 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
48 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
49 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
50 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
51 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
52 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
53 #include "ui/views/widget/desktop_aura/x11_pointer_grab.h"
54 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
55 #include "ui/wm/core/compound_event_filter.h"
56 #include "ui/wm/core/window_util.h"
58 DECLARE_WINDOW_PROPERTY_TYPE(views::DesktopWindowTreeHostX11
*);
62 DesktopWindowTreeHostX11
* DesktopWindowTreeHostX11::g_current_capture
=
64 std::list
<XID
>* DesktopWindowTreeHostX11::open_windows_
= NULL
;
66 DEFINE_WINDOW_PROPERTY_KEY(
67 aura::Window
*, kViewsWindowForRootWindow
, NULL
);
69 DEFINE_WINDOW_PROPERTY_KEY(
70 DesktopWindowTreeHostX11
*, kHostForRootWindow
, NULL
);
74 // Constants that are part of EWMH.
75 const int k_NET_WM_STATE_ADD
= 1;
76 const int k_NET_WM_STATE_REMOVE
= 0;
78 // Special value of the _NET_WM_DESKTOP property which indicates that the window
79 // should appear on all desktops.
80 const int kAllDesktops
= 0xFFFFFFFF;
82 const char* kAtomsToCache
[] = {
94 "_NET_WM_STATE_ABOVE",
95 "_NET_WM_STATE_FULLSCREEN",
96 "_NET_WM_STATE_HIDDEN",
97 "_NET_WM_STATE_MAXIMIZED_HORZ",
98 "_NET_WM_STATE_MAXIMIZED_VERT",
99 "_NET_WM_STATE_SKIP_TASKBAR",
100 "_NET_WM_STATE_STICKY",
102 "_NET_WM_WINDOW_OPACITY",
103 "_NET_WM_WINDOW_TYPE",
104 "_NET_WM_WINDOW_TYPE_DND",
105 "_NET_WM_WINDOW_TYPE_MENU",
106 "_NET_WM_WINDOW_TYPE_NORMAL",
107 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
108 "_NET_WM_WINDOW_TYPE_TOOLTIP",
121 "XdndProxy", // Proxy windows?
128 const char kX11WindowRolePopup
[] = "popup";
129 const char kX11WindowRoleBubble
[] = "bubble";
133 ////////////////////////////////////////////////////////////////////////////////
134 // DesktopWindowTreeHostX11, public:
136 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
137 internal::NativeWidgetDelegate
* native_widget_delegate
,
138 DesktopNativeWidgetAura
* desktop_native_widget_aura
)
139 : xdisplay_(gfx::GetXDisplay()),
141 x_root_window_(DefaultRootWindow(xdisplay_
)),
142 atom_cache_(xdisplay_
, kAtomsToCache
),
143 window_mapped_(false),
144 is_fullscreen_(false),
145 is_always_on_top_(false),
146 use_native_frame_(false),
147 should_maximize_after_map_(false),
148 use_argb_visual_(false),
149 drag_drop_client_(NULL
),
150 native_widget_delegate_(native_widget_delegate
),
151 desktop_native_widget_aura_(desktop_native_widget_aura
),
152 content_window_(NULL
),
153 window_parent_(NULL
),
154 custom_window_shape_(false),
155 urgency_hint_set_(false),
156 close_widget_factory_(this) {
159 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
160 window()->ClearProperty(kHostForRootWindow
);
161 aura::client::SetWindowMoveClient(window(), NULL
);
162 desktop_native_widget_aura_
->OnDesktopWindowTreeHostDestroyed(this);
167 aura::Window
* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid
) {
168 aura::WindowTreeHost
* host
=
169 aura::WindowTreeHost::GetForAcceleratedWidget(xid
);
170 return host
? host
->window()->GetProperty(kViewsWindowForRootWindow
) : NULL
;
174 DesktopWindowTreeHostX11
* DesktopWindowTreeHostX11::GetHostForXID(XID xid
) {
175 aura::WindowTreeHost
* host
=
176 aura::WindowTreeHost::GetForAcceleratedWidget(xid
);
177 return host
? host
->window()->GetProperty(kHostForRootWindow
) : NULL
;
181 std::vector
<aura::Window
*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
182 std::vector
<aura::Window
*> windows(open_windows().size());
183 std::transform(open_windows().begin(),
184 open_windows().end(),
186 GetContentWindowForXID
);
190 gfx::Rect
DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
191 return bounds_in_pixels_
;
194 gfx::Rect
DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
195 gfx::Rect
outer_bounds(bounds_in_pixels_
);
196 outer_bounds
.Inset(-native_window_frame_borders_in_pixels_
);
200 ::Region
DesktopWindowTreeHostX11::GetWindowShape() const {
201 return window_shape_
.get();
204 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
209 open_windows().remove(xwindow_
);
210 open_windows().insert(open_windows().begin(), xwindow_
);
215 desktop_native_widget_aura_
->HandleActivationChanged(active
);
217 native_widget_delegate_
->AsWidget()->GetRootView()->SchedulePaint();
220 void DesktopWindowTreeHostX11::AddObserver(
221 views::DesktopWindowTreeHostObserverX11
* observer
) {
222 observer_list_
.AddObserver(observer
);
225 void DesktopWindowTreeHostX11::RemoveObserver(
226 views::DesktopWindowTreeHostObserverX11
* observer
) {
227 observer_list_
.RemoveObserver(observer
);
230 void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
231 scoped_ptr
<ui::EventHandler
> handler
) {
232 wm::CompoundEventFilter
* compound_event_filter
=
233 desktop_native_widget_aura_
->root_window_event_filter();
234 if (x11_non_client_event_filter_
)
235 compound_event_filter
->RemoveHandler(x11_non_client_event_filter_
.get());
236 compound_event_filter
->AddHandler(handler
.get());
237 x11_non_client_event_filter_
= handler
.Pass();
240 void DesktopWindowTreeHostX11::CleanUpWindowList() {
241 delete open_windows_
;
242 open_windows_
= NULL
;
245 ////////////////////////////////////////////////////////////////////////////////
246 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
248 void DesktopWindowTreeHostX11::Init(aura::Window
* content_window
,
249 const Widget::InitParams
& params
) {
250 content_window_
= content_window
;
252 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
253 // whether we should be proxying requests to another DRWHL.
255 // In some situations, views tries to make a zero sized window, and that
256 // makes us crash. Make sure we have valid sizes.
257 Widget::InitParams sanitized_params
= params
;
258 if (sanitized_params
.bounds
.width() == 0)
259 sanitized_params
.bounds
.set_width(100);
260 if (sanitized_params
.bounds
.height() == 0)
261 sanitized_params
.bounds
.set_height(100);
263 InitX11Window(sanitized_params
);
266 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
267 const Widget::InitParams
& params
) {
268 window()->SetProperty(kViewsWindowForRootWindow
, content_window_
);
269 window()->SetProperty(kHostForRootWindow
, this);
271 // Ensure that the X11DesktopHandler exists so that it dispatches activation
273 X11DesktopHandler::get();
275 // TODO(erg): Unify this code once the other consumer goes away.
276 SwapNonClientEventHandler(
277 scoped_ptr
<ui::EventHandler
>(new X11WindowEventFilter(this)).Pass());
278 SetUseNativeFrame(params
.type
== Widget::InitParams::TYPE_WINDOW
&&
279 !params
.remove_standard_frame
);
281 x11_window_move_client_
.reset(new X11DesktopWindowMoveClient
);
282 aura::client::SetWindowMoveClient(window(), x11_window_move_client_
.get());
284 SetWindowTransparency();
286 native_widget_delegate_
->OnNativeWidgetCreated(true);
289 scoped_ptr
<corewm::Tooltip
> DesktopWindowTreeHostX11::CreateTooltip() {
290 return make_scoped_ptr(new corewm::TooltipAura
);
293 scoped_ptr
<aura::client::DragDropClient
>
294 DesktopWindowTreeHostX11::CreateDragDropClient(
295 DesktopNativeCursorManager
* cursor_manager
) {
296 drag_drop_client_
= new DesktopDragDropClientAuraX11(
297 window(), cursor_manager
, xdisplay_
, xwindow_
);
298 drag_drop_client_
->Init();
299 return make_scoped_ptr(drag_drop_client_
);
302 void DesktopWindowTreeHostX11::Close() {
303 // TODO(erg): Might need to do additional hiding tasks here.
304 delayed_resize_task_
.Cancel();
306 if (!close_widget_factory_
.HasWeakPtrs()) {
307 // And we delay the close so that if we are called from an ATL callback,
308 // we don't destroy the window before the callback returned (as the caller
309 // may delete ourselves on destroy and the ATL callback would still
310 // dereference us when the callback returns).
311 base::MessageLoop::current()->PostTask(
313 base::Bind(&DesktopWindowTreeHostX11::CloseNow
,
314 close_widget_factory_
.GetWeakPtr()));
318 void DesktopWindowTreeHostX11::CloseNow() {
319 if (xwindow_
== None
)
323 native_widget_delegate_
->OnNativeWidgetDestroying();
325 // If we have children, close them. Use a copy for iteration because they'll
326 // remove themselves.
327 std::set
<DesktopWindowTreeHostX11
*> window_children_copy
= window_children_
;
328 for (std::set
<DesktopWindowTreeHostX11
*>::iterator it
=
329 window_children_copy
.begin(); it
!= window_children_copy
.end();
333 DCHECK(window_children_
.empty());
335 // If we have a parent, remove ourselves from its children list.
336 if (window_parent_
) {
337 window_parent_
->window_children_
.erase(this);
338 window_parent_
= NULL
;
341 // Remove the event listeners we've installed. We need to remove these
342 // because otherwise we get assert during ~WindowEventDispatcher().
343 desktop_native_widget_aura_
->root_window_event_filter()->RemoveHandler(
344 x11_non_client_event_filter_
.get());
345 x11_non_client_event_filter_
.reset();
347 // Destroy the compositor before destroying the |xwindow_| since shutdown
348 // may try to swap, and the swap without a window causes an X error, which
349 // causes a crash with in-process renderer.
352 open_windows().remove(xwindow_
);
353 // Actually free our native resources.
354 if (ui::PlatformEventSource::GetInstance())
355 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
356 XDestroyWindow(xdisplay_
, xwindow_
);
359 desktop_native_widget_aura_
->OnHostClosed();
362 aura::WindowTreeHost
* DesktopWindowTreeHostX11::AsWindowTreeHost() {
366 void DesktopWindowTreeHostX11::ShowWindowWithState(
367 ui::WindowShowState show_state
) {
369 MapWindow(show_state
);
371 switch (show_state
) {
372 case ui::SHOW_STATE_NORMAL
:
375 case ui::SHOW_STATE_MAXIMIZED
:
378 case ui::SHOW_STATE_MINIMIZED
:
381 case ui::SHOW_STATE_FULLSCREEN
:
388 native_widget_delegate_
->AsWidget()->SetInitialFocus(show_state
);
391 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
392 const gfx::Rect
& restored_bounds
) {
393 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED
);
394 // Enforce |restored_bounds_in_pixels_| since calling Maximize() could have
396 restored_bounds_in_pixels_
= ToPixelRect(restored_bounds
);
399 bool DesktopWindowTreeHostX11::IsVisible() const {
400 return window_mapped_
;
403 void DesktopWindowTreeHostX11::SetSize(const gfx::Size
& requested_size
) {
404 gfx::Size size_in_pixels
= ToPixelRect(gfx::Rect(requested_size
)).size();
405 size_in_pixels
= AdjustSize(size_in_pixels
);
406 bool size_changed
= bounds_in_pixels_
.size() != size_in_pixels
;
407 XResizeWindow(xdisplay_
, xwindow_
, size_in_pixels
.width(),
408 size_in_pixels
.height());
409 bounds_in_pixels_
.set_size(size_in_pixels
);
411 OnHostResized(size_in_pixels
);
416 void DesktopWindowTreeHostX11::StackAtTop() {
417 XRaiseWindow(xdisplay_
, xwindow_
);
420 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size
& size
) {
421 gfx::Size size_in_pixels
= ToPixelRect(gfx::Rect(size
)).size();
422 gfx::Rect parent_bounds_in_pixels
= GetWorkAreaBoundsInPixels();
424 // If |window_|'s transient parent bounds are big enough to contain |size|,
426 if (wm::GetTransientParent(content_window_
)) {
427 gfx::Rect transient_parent_rect
=
428 wm::GetTransientParent(content_window_
)->GetBoundsInScreen();
429 if (transient_parent_rect
.height() >= size
.height() &&
430 transient_parent_rect
.width() >= size
.width()) {
431 parent_bounds_in_pixels
= ToPixelRect(transient_parent_rect
);
435 gfx::Rect
window_bounds_in_pixels(
436 parent_bounds_in_pixels
.x() +
437 (parent_bounds_in_pixels
.width() - size_in_pixels
.width()) / 2,
438 parent_bounds_in_pixels
.y() +
439 (parent_bounds_in_pixels
.height() - size_in_pixels
.height()) / 2,
440 size_in_pixels
.width(), size_in_pixels
.height());
441 // Don't size the window bigger than the parent, otherwise the user may not be
442 // able to close or move it.
443 window_bounds_in_pixels
.AdjustToFit(parent_bounds_in_pixels
);
445 SetBounds(window_bounds_in_pixels
);
448 void DesktopWindowTreeHostX11::GetWindowPlacement(
450 ui::WindowShowState
* show_state
) const {
451 *bounds
= GetRestoredBounds();
453 if (IsFullscreen()) {
454 *show_state
= ui::SHOW_STATE_FULLSCREEN
;
455 } else if (IsMinimized()) {
456 *show_state
= ui::SHOW_STATE_MINIMIZED
;
457 } else if (IsMaximized()) {
458 *show_state
= ui::SHOW_STATE_MAXIMIZED
;
459 } else if (!IsActive()) {
460 *show_state
= ui::SHOW_STATE_INACTIVE
;
462 *show_state
= ui::SHOW_STATE_NORMAL
;
466 gfx::Rect
DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
467 return ToDIPRect(bounds_in_pixels_
);
470 gfx::Rect
DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
471 // TODO(erg): The NativeWidgetAura version returns |bounds_in_pixels_|,
472 // claiming it's needed for View::ConvertPointToScreen() to work correctly.
473 // DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just asks windows
474 // what it thinks the client rect is.
476 // Attempts to calculate the rect by asking the NonClientFrameView what it
477 // thought its GetBoundsForClientView() were broke combobox drop down
479 return GetWindowBoundsInScreen();
482 gfx::Rect
DesktopWindowTreeHostX11::GetRestoredBounds() const {
483 // We can't reliably track the restored bounds of a window, but we can get
484 // the 90% case down. When *chrome* is the process that requests maximizing
485 // or restoring bounds, we can record the current bounds before we request
486 // maximization, and clear it when we detect a state change.
487 if (!restored_bounds_in_pixels_
.IsEmpty())
488 return ToDIPRect(restored_bounds_in_pixels_
);
490 return GetWindowBoundsInScreen();
493 gfx::Rect
DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
494 return ToDIPRect(GetWorkAreaBoundsInPixels());
497 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region
) {
498 custom_window_shape_
= false;
499 window_shape_
.reset();
502 gfx::Transform transform
= GetRootTransform();
503 if (!transform
.IsIdentity() && !native_region
->isEmpty()) {
505 if (native_region
->getBoundaryPath(&path_in_dip
)) {
506 SkPath path_in_pixels
;
507 path_in_dip
.transform(transform
.matrix(), &path_in_pixels
);
508 window_shape_
.reset(gfx::CreateRegionFromSkPath(path_in_pixels
));
510 window_shape_
.reset(XCreateRegion());
513 window_shape_
.reset(gfx::CreateRegionFromSkRegion(*native_region
));
516 custom_window_shape_
= true;
517 delete native_region
;
522 void DesktopWindowTreeHostX11::Activate() {
526 X11DesktopHandler::get()->ActivateWindow(xwindow_
);
529 void DesktopWindowTreeHostX11::Deactivate() {
534 X11DesktopHandler::get()->DeactivateWindow(xwindow_
);
537 bool DesktopWindowTreeHostX11::IsActive() const {
538 return X11DesktopHandler::get()->IsActiveWindow(xwindow_
);
541 void DesktopWindowTreeHostX11::Maximize() {
542 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN")) {
543 // Unfullscreen the window if it is fullscreen.
544 SetWMSpecState(false,
545 atom_cache_
.GetAtom("_NET_WM_STATE_FULLSCREEN"),
548 // Resize the window so that it does not have the same size as a monitor.
549 // (Otherwise, some window managers immediately put the window back in
551 gfx::Rect
adjusted_bounds_in_pixels(bounds_in_pixels_
.origin(),
552 AdjustSize(bounds_in_pixels_
.size()));
553 if (adjusted_bounds_in_pixels
!= bounds_in_pixels_
)
554 SetBounds(adjusted_bounds_in_pixels
);
557 // Some WMs do not respect maximization hints on unmapped windows, so we
558 // save this one for later too.
559 should_maximize_after_map_
= !window_mapped_
;
561 // When we are in the process of requesting to maximize a window, we can
562 // accurately keep track of our restored bounds instead of relying on the
563 // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
564 restored_bounds_in_pixels_
= bounds_in_pixels_
;
567 atom_cache_
.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
568 atom_cache_
.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
570 ShowWindowWithState(ui::SHOW_STATE_NORMAL
);
573 void DesktopWindowTreeHostX11::Minimize() {
575 XIconifyWindow(xdisplay_
, xwindow_
, 0);
578 void DesktopWindowTreeHostX11::Restore() {
579 should_maximize_after_map_
= false;
580 SetWMSpecState(false,
581 atom_cache_
.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
582 atom_cache_
.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
584 ShowWindowWithState(ui::SHOW_STATE_NORMAL
);
587 bool DesktopWindowTreeHostX11::IsMaximized() const {
588 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
589 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
592 bool DesktopWindowTreeHostX11::IsMinimized() const {
593 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
596 bool DesktopWindowTreeHostX11::HasCapture() const {
597 return g_current_capture
== this;
600 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top
) {
601 is_always_on_top_
= always_on_top
;
602 SetWMSpecState(always_on_top
,
603 atom_cache_
.GetAtom("_NET_WM_STATE_ABOVE"),
607 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
608 return is_always_on_top_
;
611 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible
) {
612 SetWMSpecState(always_visible
,
613 atom_cache_
.GetAtom("_NET_WM_STATE_STICKY"),
617 if (always_visible
) {
618 new_desktop
= kAllDesktops
;
620 if (!ui::GetCurrentDesktop(&new_desktop
))
625 memset (&xevent
, 0, sizeof (xevent
));
626 xevent
.type
= ClientMessage
;
627 xevent
.xclient
.window
= xwindow_
;
628 xevent
.xclient
.message_type
= atom_cache_
.GetAtom("_NET_WM_DESKTOP");
629 xevent
.xclient
.format
= 32;
630 xevent
.xclient
.data
.l
[0] = new_desktop
;
631 xevent
.xclient
.data
.l
[1] = 0;
632 xevent
.xclient
.data
.l
[2] = 0;
633 xevent
.xclient
.data
.l
[3] = 0;
634 xevent
.xclient
.data
.l
[4] = 0;
635 XSendEvent(xdisplay_
, x_root_window_
, False
,
636 SubstructureRedirectMask
| SubstructureNotifyMask
,
640 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16
& title
) {
641 if (window_title_
== title
)
643 window_title_
= title
;
644 std::string utf8str
= base::UTF16ToUTF8(title
);
645 XChangeProperty(xdisplay_
,
647 atom_cache_
.GetAtom("_NET_WM_NAME"),
648 atom_cache_
.GetAtom("UTF8_STRING"),
651 reinterpret_cast<const unsigned char*>(utf8str
.c_str()),
654 char *c_utf8_str
= const_cast<char *>(utf8str
.c_str());
655 if (Xutf8TextListToTextProperty(xdisplay_
, &c_utf8_str
, 1,
656 XUTF8StringStyle
, &xtp
) == Success
) {
657 XSetWMName(xdisplay_
, xwindow_
, &xtp
);
663 void DesktopWindowTreeHostX11::ClearNativeFocus() {
664 // This method is weird and misnamed. Instead of clearing the native focus,
665 // it sets the focus to our |content_window_|, which will trigger a cascade
666 // of focus changes into views.
667 if (content_window_
&& aura::client::GetFocusClient(content_window_
) &&
668 content_window_
->Contains(
669 aura::client::GetFocusClient(content_window_
)->GetFocusedWindow())) {
670 aura::client::GetFocusClient(content_window_
)->FocusWindow(content_window_
);
674 Widget::MoveLoopResult
DesktopWindowTreeHostX11::RunMoveLoop(
675 const gfx::Vector2d
& drag_offset
,
676 Widget::MoveLoopSource source
,
677 Widget::MoveLoopEscapeBehavior escape_behavior
) {
678 aura::client::WindowMoveSource window_move_source
=
679 source
== Widget::MOVE_LOOP_SOURCE_MOUSE
?
680 aura::client::WINDOW_MOVE_SOURCE_MOUSE
:
681 aura::client::WINDOW_MOVE_SOURCE_TOUCH
;
682 if (x11_window_move_client_
->RunMoveLoop(content_window_
, drag_offset
,
683 window_move_source
) == aura::client::MOVE_SUCCESSFUL
)
684 return Widget::MOVE_LOOP_SUCCESSFUL
;
686 return Widget::MOVE_LOOP_CANCELED
;
689 void DesktopWindowTreeHostX11::EndMoveLoop() {
690 x11_window_move_client_
->EndMoveLoop();
693 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
695 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
698 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
699 return use_native_frame_
;
702 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
706 void DesktopWindowTreeHostX11::FrameTypeChanged() {
707 Widget::FrameType new_type
=
708 native_widget_delegate_
->AsWidget()->frame_type();
709 if (new_type
== Widget::FRAME_TYPE_DEFAULT
) {
710 // The default is determined by Widget::InitParams::remove_standard_frame
711 // and does not change.
715 SetUseNativeFrame(new_type
== Widget::FRAME_TYPE_FORCE_NATIVE
);
716 // Replace the frame and layout the contents. Even though we don't have a
717 // swapable glass frame like on Windows, we still replace the frame because
718 // the button assets don't update otherwise.
719 native_widget_delegate_
->AsWidget()->non_client_view()->UpdateFrame();
722 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen
) {
723 if (is_fullscreen_
== fullscreen
)
725 is_fullscreen_
= fullscreen
;
727 delayed_resize_task_
.Cancel();
729 // Work around a bug where if we try to unfullscreen, metacity immediately
730 // fullscreens us again. This is a little flickery and not necessary if
731 // there's a gnome-panel, but it's not easy to detect whether there's a
733 bool unmaximize_and_remaximize
= !fullscreen
&& IsMaximized() &&
734 ui::GuessWindowManager() == ui::WM_METACITY
;
736 if (unmaximize_and_remaximize
)
738 SetWMSpecState(fullscreen
,
739 atom_cache_
.GetAtom("_NET_WM_STATE_FULLSCREEN"),
741 if (unmaximize_and_remaximize
)
744 // Try to guess the size we will have after the switch to/from fullscreen:
745 // - (may) avoid transient states
746 // - works around Flash content which expects to have the size updated
748 // See https://crbug.com/361408
750 restored_bounds_in_pixels_
= bounds_in_pixels_
;
751 const gfx::Display display
=
752 gfx::Screen::GetScreenFor(NULL
)->GetDisplayNearestWindow(window());
753 bounds_in_pixels_
= ToPixelRect(display
.bounds());
755 bounds_in_pixels_
= restored_bounds_in_pixels_
;
757 OnHostMoved(bounds_in_pixels_
.origin());
758 OnHostResized(bounds_in_pixels_
.size());
760 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen
) {
764 // Else: the widget will be relaid out either when the window bounds change or
765 // when |xwindow_|'s fullscreen state changes.
768 bool DesktopWindowTreeHostX11::IsFullscreen() const {
769 return is_fullscreen_
;
772 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity
) {
773 // X server opacity is in terms of 32 bit unsigned int space, and counts from
774 // the opposite direction.
775 // XChangeProperty() expects "cardinality" to be long.
776 unsigned long cardinality
= opacity
* 0x1010101;
778 if (cardinality
== 0xffffffff) {
779 XDeleteProperty(xdisplay_
, xwindow_
,
780 atom_cache_
.GetAtom("_NET_WM_WINDOW_OPACITY"));
782 XChangeProperty(xdisplay_
, xwindow_
,
783 atom_cache_
.GetAtom("_NET_WM_WINDOW_OPACITY"),
786 reinterpret_cast<unsigned char*>(&cardinality
), 1);
790 void DesktopWindowTreeHostX11::SetWindowIcons(
791 const gfx::ImageSkia
& window_icon
, const gfx::ImageSkia
& app_icon
) {
792 // TODO(erg): The way we handle icons across different versions of chrome
793 // could be substantially improved. The Windows version does its own thing
794 // and only sometimes comes down this code path. The icon stuff in
795 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
796 // coded to be given two images instead of an arbitrary collection of images
797 // so that we can pass to the WM.
799 // All of this could be made much, much better.
800 std::vector
<unsigned long> data
;
802 if (window_icon
.HasRepresentation(1.0f
))
803 SerializeImageRepresentation(window_icon
.GetRepresentation(1.0f
), &data
);
805 if (app_icon
.HasRepresentation(1.0f
))
806 SerializeImageRepresentation(app_icon
.GetRepresentation(1.0f
), &data
);
809 ui::SetAtomArrayProperty(xwindow_
, "_NET_WM_ICON", "CARDINAL", data
);
812 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type
) {
813 switch (modal_type
) {
814 case ui::MODAL_TYPE_NONE
:
817 // TODO(erg): Figure out under what situations |modal_type| isn't
818 // none. The comment in desktop_native_widget_aura.cc suggests that this
824 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame
) {
825 if (urgency_hint_set_
== flash_frame
)
828 gfx::XScopedPtr
<XWMHints
> hints(XGetWMHints(xdisplay_
, xwindow_
));
830 // The window hasn't had its hints set yet.
831 hints
.reset(XAllocWMHints());
835 hints
->flags
|= XUrgencyHint
;
837 hints
->flags
&= ~XUrgencyHint
;
839 XSetWMHints(xdisplay_
, xwindow_
, hints
.get());
841 urgency_hint_set_
= flash_frame
;
844 void DesktopWindowTreeHostX11::OnRootViewLayout() {
845 UpdateMinAndMaxSize();
848 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
849 native_widget_delegate_
->AsWidget()->GetInputMethod()->OnFocus();
852 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
854 native_widget_delegate_
->AsWidget()->GetInputMethod()->OnBlur();
857 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
861 bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
865 void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
866 UpdateMinAndMaxSize();
869 ////////////////////////////////////////////////////////////////////////////////
870 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
872 gfx::Transform
DesktopWindowTreeHostX11::GetRootTransform() const {
873 gfx::Display display
= gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
874 if (window_mapped_
) {
875 aura::Window
* win
= const_cast<aura::Window
*>(window());
876 display
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(win
);
879 float scale
= display
.device_scale_factor();
880 gfx::Transform transform
;
881 transform
.Scale(scale
, scale
);
885 ui::EventSource
* DesktopWindowTreeHostX11::GetEventSource() {
889 gfx::AcceleratedWidget
DesktopWindowTreeHostX11::GetAcceleratedWidget() {
893 void DesktopWindowTreeHostX11::Show() {
894 ShowWindowWithState(ui::SHOW_STATE_NORMAL
);
895 native_widget_delegate_
->OnNativeWidgetVisibilityChanged(true);
898 void DesktopWindowTreeHostX11::Hide() {
899 if (window_mapped_
) {
900 XWithdrawWindow(xdisplay_
, xwindow_
, 0);
901 window_mapped_
= false;
903 native_widget_delegate_
->OnNativeWidgetVisibilityChanged(false);
906 gfx::Rect
DesktopWindowTreeHostX11::GetBounds() const {
907 return bounds_in_pixels_
;
910 void DesktopWindowTreeHostX11::SetBounds(
911 const gfx::Rect
& requested_bounds_in_pixel
) {
912 gfx::Rect
bounds_in_pixels(requested_bounds_in_pixel
.origin(),
913 AdjustSize(requested_bounds_in_pixel
.size()));
914 bool origin_changed
= bounds_in_pixels_
.origin() != bounds_in_pixels
.origin();
915 bool size_changed
= bounds_in_pixels_
.size() != bounds_in_pixels
.size();
916 XWindowChanges changes
= {0};
917 unsigned value_mask
= 0;
920 if (bounds_in_pixels
.width() < min_size_in_pixels_
.width() ||
921 bounds_in_pixels
.height() < min_size_in_pixels_
.height() ||
922 (!max_size_in_pixels_
.IsEmpty() &&
923 (bounds_in_pixels
.width() > max_size_in_pixels_
.width() ||
924 bounds_in_pixels
.height() > max_size_in_pixels_
.height()))) {
925 // Update the minimum and maximum sizes in case they have changed.
926 UpdateMinAndMaxSize();
928 gfx::Size size_in_pixels
= bounds_in_pixels
.size();
929 size_in_pixels
.SetToMin(max_size_in_pixels_
);
930 size_in_pixels
.SetToMax(min_size_in_pixels_
);
931 bounds_in_pixels
.set_size(size_in_pixels
);
934 changes
.width
= bounds_in_pixels
.width();
935 changes
.height
= bounds_in_pixels
.height();
936 value_mask
|= CWHeight
| CWWidth
;
939 if (origin_changed
) {
940 changes
.x
= bounds_in_pixels
.x();
941 changes
.y
= bounds_in_pixels
.y();
942 value_mask
|= CWX
| CWY
;
945 XConfigureWindow(xdisplay_
, xwindow_
, value_mask
, &changes
);
947 // Assume that the resize will go through as requested, which should be the
948 // case if we're running without a window manager. If there's a window
949 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
950 // (possibly synthetic) ConfigureNotify about the actual size and correct
951 // |bounds_in_pixels_| later.
952 bounds_in_pixels_
= bounds_in_pixels
;
955 native_widget_delegate_
->AsWidget()->OnNativeWidgetMove();
957 OnHostResized(bounds_in_pixels
.size());
962 gfx::Point
DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
963 return bounds_in_pixels_
.origin();
966 void DesktopWindowTreeHostX11::SetCapture() {
970 // Grabbing the mouse is asynchronous. However, we synchronously start
971 // forwarding all mouse events received by Chrome to the
972 // aura::WindowEventDispatcher which has capture. This makes capture
973 // synchronous for all intents and purposes if either:
974 // - |g_current_capture|'s X window has capture.
976 // - The topmost window underneath the mouse is managed by Chrome.
977 DesktopWindowTreeHostX11
* old_capturer
= g_current_capture
;
979 // Update |g_current_capture| prior to calling OnHostLostWindowCapture() to
980 // avoid releasing pointer grab.
981 g_current_capture
= this;
983 old_capturer
->OnHostLostWindowCapture();
985 GrabPointer(xwindow_
, true, None
);
988 void DesktopWindowTreeHostX11::ReleaseCapture() {
989 if (g_current_capture
== this) {
990 // Release mouse grab asynchronously. A window managed by Chrome is likely
991 // the topmost window underneath the mouse so the capture release being
992 // asynchronous is likely inconsequential.
993 g_current_capture
= NULL
;
996 OnHostLostWindowCapture();
1000 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor
) {
1001 XDefineCursor(xdisplay_
, xwindow_
, cursor
.platform());
1004 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point
& location
) {
1005 XWarpPointer(xdisplay_
, None
, x_root_window_
, 0, 0, 0, 0,
1006 bounds_in_pixels_
.x() + location
.x(),
1007 bounds_in_pixels_
.y() + location
.y());
1010 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show
) {
1011 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
1012 // the same tap-to-click disabling here that chromeos does.
1015 ////////////////////////////////////////////////////////////////////////////////
1016 // DesktopWindowTreeHostX11, ui::EventSource implementation:
1018 ui::EventProcessor
* DesktopWindowTreeHostX11::GetEventProcessor() {
1019 return dispatcher();
1022 ////////////////////////////////////////////////////////////////////////////////
1023 // DesktopWindowTreeHostX11, private:
1025 void DesktopWindowTreeHostX11::InitX11Window(
1026 const Widget::InitParams
& params
) {
1027 unsigned long attribute_mask
= CWBackPixmap
;
1028 XSetWindowAttributes swa
;
1029 memset(&swa
, 0, sizeof(swa
));
1030 swa
.background_pixmap
= None
;
1033 switch (params
.type
) {
1034 case Widget::InitParams::TYPE_MENU
:
1035 swa
.override_redirect
= True
;
1036 window_type
= atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
1038 case Widget::InitParams::TYPE_TOOLTIP
:
1039 swa
.override_redirect
= True
;
1040 window_type
= atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
1042 case Widget::InitParams::TYPE_POPUP
:
1043 swa
.override_redirect
= True
;
1044 window_type
= atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
1046 case Widget::InitParams::TYPE_DRAG
:
1047 swa
.override_redirect
= True
;
1048 window_type
= atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE_DND");
1051 window_type
= atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
1054 if (swa
.override_redirect
)
1055 attribute_mask
|= CWOverrideRedirect
;
1057 // Detect whether we're running inside a compositing manager. If so, try to
1058 // use the ARGB visual. Otherwise, just use our parent's visual.
1059 Visual
* visual
= CopyFromParent
;
1060 int depth
= CopyFromParent
;
1061 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1062 switches::kEnableTransparentVisuals
) &&
1063 XGetSelectionOwner(xdisplay_
, atom_cache_
.GetAtom("_NET_WM_CM_S0")) !=
1065 Visual
* rgba_visual
= GetARGBVisual();
1067 visual
= rgba_visual
;
1070 attribute_mask
|= CWColormap
;
1071 swa
.colormap
= XCreateColormap(xdisplay_
, x_root_window_
, visual
,
1074 // x.org will BadMatch if we don't set a border when the depth isn't the
1075 // same as the parent depth.
1076 attribute_mask
|= CWBorderPixel
;
1077 swa
.border_pixel
= 0;
1079 use_argb_visual_
= true;
1083 bounds_in_pixels_
= ToPixelRect(params
.bounds
);
1084 bounds_in_pixels_
.set_size(AdjustSize(bounds_in_pixels_
.size()));
1085 xwindow_
= XCreateWindow(xdisplay_
, x_root_window_
, bounds_in_pixels_
.x(),
1086 bounds_in_pixels_
.y(), bounds_in_pixels_
.width(),
1087 bounds_in_pixels_
.height(),
1089 depth
, InputOutput
, visual
, attribute_mask
, &swa
);
1090 if (ui::PlatformEventSource::GetInstance())
1091 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
1092 open_windows().push_back(xwindow_
);
1094 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1096 long event_mask
= ButtonPressMask
| ButtonReleaseMask
| FocusChangeMask
|
1097 KeyPressMask
| KeyReleaseMask
|
1098 EnterWindowMask
| LeaveWindowMask
|
1099 ExposureMask
| VisibilityChangeMask
|
1100 StructureNotifyMask
| PropertyChangeMask
|
1102 XSelectInput(xdisplay_
, xwindow_
, event_mask
);
1105 if (ui::IsXInput2Available())
1106 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_
);
1108 // TODO(erg): We currently only request window deletion events. We also
1109 // should listen for activation events and anything else that GTK+ listens
1110 // for, and do something useful.
1111 ::Atom protocols
[2];
1112 protocols
[0] = atom_cache_
.GetAtom("WM_DELETE_WINDOW");
1113 protocols
[1] = atom_cache_
.GetAtom("_NET_WM_PING");
1114 XSetWMProtocols(xdisplay_
, xwindow_
, protocols
, 2);
1116 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1117 // the desktop environment.
1118 XSetWMProperties(xdisplay_
, xwindow_
, NULL
, NULL
, NULL
, 0, NULL
, NULL
, NULL
);
1120 // Likewise, the X server needs to know this window's pid so it knows which
1121 // program to kill if the window hangs.
1122 // XChangeProperty() expects "pid" to be long.
1123 static_assert(sizeof(long) >= sizeof(pid_t
),
1124 "pid_t should not be larger than long");
1125 long pid
= getpid();
1126 XChangeProperty(xdisplay_
,
1128 atom_cache_
.GetAtom("_NET_WM_PID"),
1132 reinterpret_cast<unsigned char*>(&pid
), 1);
1134 XChangeProperty(xdisplay_
,
1136 atom_cache_
.GetAtom("_NET_WM_WINDOW_TYPE"),
1140 reinterpret_cast<unsigned char*>(&window_type
), 1);
1142 // List of window state properties (_NET_WM_STATE) to set, if any.
1143 std::vector
< ::Atom
> state_atom_list
;
1145 // Remove popup windows from taskbar unless overridden.
1146 if ((params
.type
== Widget::InitParams::TYPE_POPUP
||
1147 params
.type
== Widget::InitParams::TYPE_BUBBLE
) &&
1148 !params
.force_show_in_taskbar
) {
1149 state_atom_list
.push_back(
1150 atom_cache_
.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1153 // If the window should stay on top of other windows, add the
1154 // _NET_WM_STATE_ABOVE property.
1155 is_always_on_top_
= params
.keep_on_top
;
1156 if (is_always_on_top_
)
1157 state_atom_list
.push_back(atom_cache_
.GetAtom("_NET_WM_STATE_ABOVE"));
1159 if (params
.visible_on_all_workspaces
) {
1160 state_atom_list
.push_back(atom_cache_
.GetAtom("_NET_WM_STATE_STICKY"));
1161 ui::SetIntProperty(xwindow_
, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops
);
1164 // Setting _NET_WM_STATE by sending a message to the root_window (with
1165 // SetWMSpecState) has no effect here since the window has not yet been
1166 // mapped. So we manually change the state.
1167 if (!state_atom_list
.empty()) {
1168 ui::SetAtomArrayProperty(xwindow_
,
1174 if (!params
.wm_class_name
.empty() || !params
.wm_class_class
.empty()) {
1175 ui::SetWindowClassHint(
1176 xdisplay_
, xwindow_
, params
.wm_class_name
, params
.wm_class_class
);
1179 const char* wm_role_name
= NULL
;
1180 // If the widget isn't overriding the role, provide a default value for popup
1181 // and bubble types.
1182 if (!params
.wm_role_name
.empty()) {
1183 wm_role_name
= params
.wm_role_name
.c_str();
1185 switch (params
.type
) {
1186 case Widget::InitParams::TYPE_POPUP
:
1187 wm_role_name
= kX11WindowRolePopup
;
1189 case Widget::InitParams::TYPE_BUBBLE
:
1190 wm_role_name
= kX11WindowRoleBubble
;
1197 ui::SetWindowRole(xdisplay_
, xwindow_
, std::string(wm_role_name
));
1199 if (params
.remove_standard_frame
) {
1200 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1201 // fullscreen on the window when it matches the desktop size.
1202 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_
,
1203 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED
);
1206 // If we have a parent, record the parent/child relationship. We use this
1207 // data during destruction to make sure that when we try to close a parent
1208 // window, we also destroy all child windows.
1209 if (params
.parent
&& params
.parent
->GetHost()) {
1211 params
.parent
->GetHost()->GetAcceleratedWidget();
1212 window_parent_
= GetHostForXID(parent_xid
);
1213 DCHECK(window_parent_
);
1214 window_parent_
->window_children_
.insert(this);
1217 // If we have a delegate which is providing a default window icon, use that
1219 gfx::ImageSkia
* window_icon
= ViewsDelegate::views_delegate
?
1220 ViewsDelegate::views_delegate
->GetDefaultWindowIcon() : NULL
;
1222 SetWindowIcons(gfx::ImageSkia(), *window_icon
);
1224 CreateCompositor(GetAcceleratedWidget());
1227 gfx::Size
DesktopWindowTreeHostX11::AdjustSize(
1228 const gfx::Size
& requested_size_in_pixels
) {
1229 std::vector
<gfx::Display
> displays
=
1230 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE
)->GetAllDisplays();
1231 // Compare against all monitor sizes. The window manager can move the window
1232 // to whichever monitor it wants.
1233 for (size_t i
= 0; i
< displays
.size(); ++i
) {
1234 if (requested_size_in_pixels
== displays
[i
].GetSizeInPixel()) {
1235 return gfx::Size(requested_size_in_pixels
.width() - 1,
1236 requested_size_in_pixels
.height() - 1);
1240 // Do not request a 0x0 window size. It causes an XError.
1241 gfx::Size size_in_pixels
= requested_size_in_pixels
;
1242 size_in_pixels
.SetToMax(gfx::Size(1, 1));
1243 return size_in_pixels
;
1246 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1247 std::vector
< ::Atom
> atom_list
;
1248 // Ignore the return value of ui::GetAtomArrayProperty(). Fluxbox removes the
1249 // _NET_WM_STATE property when no _NET_WM_STATE atoms are set.
1250 ui::GetAtomArrayProperty(xwindow_
, "_NET_WM_STATE", &atom_list
);
1252 bool was_minimized
= IsMinimized();
1254 window_properties_
.clear();
1255 std::copy(atom_list
.begin(), atom_list
.end(),
1256 inserter(window_properties_
, window_properties_
.begin()));
1258 // Propagate the window minimization information to the content window, so
1259 // the render side can update its visibility properly. OnWMStateUpdated() is
1260 // called by PropertyNofify event from DispatchEvent() when the browser is
1261 // minimized or shown from minimized state. On Windows, this is realized by
1262 // calling OnHostResized() with an empty size. In particular,
1263 // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
1264 // window is minimized. On Linux, returning empty size in GetBounds() or
1265 // SetBounds() does not work.
1266 // We also propagate the minimization to the compositor, to makes sure that we
1267 // don't draw any 'blank' frames that could be noticed in applications such as
1268 // window manager previews, which show content even when a window is
1270 bool is_minimized
= IsMinimized();
1271 if (is_minimized
!= was_minimized
) {
1273 compositor()->SetVisible(false);
1274 content_window_
->Hide();
1276 content_window_
->Show();
1277 compositor()->SetVisible(true);
1281 if (restored_bounds_in_pixels_
.IsEmpty()) {
1282 DCHECK(!IsFullscreen());
1283 if (IsMaximized()) {
1284 // The request that we become maximized originated from a different
1285 // process. |bounds_in_pixels_| already contains our maximized bounds. Do
1286 // a best effort attempt to get restored bounds by setting it to our
1287 // previously set bounds (and if we get this wrong, we aren't any worse
1288 // off since we'd otherwise be returning our maximized bounds).
1289 restored_bounds_in_pixels_
= previous_bounds_in_pixels_
;
1291 } else if (!IsMaximized() && !IsFullscreen()) {
1292 // If we have restored bounds, but WM_STATE no longer claims to be
1293 // maximized or fullscreen, we should clear our restored bounds.
1294 restored_bounds_in_pixels_
= gfx::Rect();
1297 // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
1298 // a result of pressing a window manager accelerator key). Chrome does not
1299 // handle window manager initiated fullscreen. In particular, Chrome needs to
1300 // do preprocessing before the x window's fullscreen state is toggled.
1302 is_always_on_top_
= HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1304 // Now that we have different window properties, we may need to relayout the
1305 // window. (The windows code doesn't need this because their window change is
1308 ResetWindowRegion();
1311 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
1312 std::vector
<int> insets
;
1313 if (ui::GetIntArrayProperty(xwindow_
, "_NET_FRAME_EXTENTS", &insets
) &&
1314 insets
.size() == 4) {
1315 // |insets| are returned in the order: [left, right, top, bottom].
1316 native_window_frame_borders_in_pixels_
=
1317 gfx::Insets(insets
[2], insets
[0], insets
[3], insets
[1]);
1319 native_window_frame_borders_in_pixels_
= gfx::Insets();
1323 void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
1324 if (!window_mapped_
)
1327 gfx::Size minimum_in_pixels
=
1328 ToPixelRect(gfx::Rect(native_widget_delegate_
->GetMinimumSize())).size();
1329 gfx::Size maximum_in_pixels
=
1330 ToPixelRect(gfx::Rect(native_widget_delegate_
->GetMaximumSize())).size();
1331 if (min_size_in_pixels_
== minimum_in_pixels
&&
1332 max_size_in_pixels_
== maximum_in_pixels
)
1335 min_size_in_pixels_
= minimum_in_pixels
;
1336 max_size_in_pixels_
= maximum_in_pixels
;
1339 long supplied_return
;
1340 XGetWMNormalHints(xdisplay_
, xwindow_
, &hints
, &supplied_return
);
1342 if (minimum_in_pixels
.IsEmpty()) {
1343 hints
.flags
&= ~PMinSize
;
1345 hints
.flags
|= PMinSize
;
1346 hints
.min_width
= min_size_in_pixels_
.width();
1347 hints
.min_height
= min_size_in_pixels_
.height();
1350 if (maximum_in_pixels
.IsEmpty()) {
1351 hints
.flags
&= ~PMaxSize
;
1353 hints
.flags
|= PMaxSize
;
1354 hints
.max_width
= max_size_in_pixels_
.width();
1355 hints
.max_height
= max_size_in_pixels_
.height();
1358 XSetWMNormalHints(xdisplay_
, xwindow_
, &hints
);
1361 void DesktopWindowTreeHostX11::UpdateWMUserTime(
1362 const ui::PlatformEvent
& event
) {
1366 ui::EventType type
= ui::EventTypeFromNative(event
);
1367 if (type
== ui::ET_MOUSE_PRESSED
||
1368 type
== ui::ET_KEY_PRESSED
||
1369 type
== ui::ET_TOUCH_PRESSED
) {
1370 unsigned long wm_user_time_ms
= static_cast<unsigned long>(
1371 ui::EventTimeFromNative(event
).InMilliseconds());
1372 XChangeProperty(xdisplay_
,
1374 atom_cache_
.GetAtom("_NET_WM_USER_TIME"),
1378 reinterpret_cast<const unsigned char *>(&wm_user_time_ms
),
1380 X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms
);
1384 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled
,
1388 memset(&xclient
, 0, sizeof(xclient
));
1389 xclient
.type
= ClientMessage
;
1390 xclient
.xclient
.window
= xwindow_
;
1391 xclient
.xclient
.message_type
= atom_cache_
.GetAtom("_NET_WM_STATE");
1392 xclient
.xclient
.format
= 32;
1393 xclient
.xclient
.data
.l
[0] =
1394 enabled
? k_NET_WM_STATE_ADD
: k_NET_WM_STATE_REMOVE
;
1395 xclient
.xclient
.data
.l
[1] = state1
;
1396 xclient
.xclient
.data
.l
[2] = state2
;
1397 xclient
.xclient
.data
.l
[3] = 1;
1398 xclient
.xclient
.data
.l
[4] = 0;
1400 XSendEvent(xdisplay_
, x_root_window_
, False
,
1401 SubstructureRedirectMask
| SubstructureNotifyMask
,
1405 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property
) const {
1406 return window_properties_
.find(atom_cache_
.GetAtom(property
)) !=
1407 window_properties_
.end();
1410 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame
) {
1411 use_native_frame_
= use_native_frame
;
1412 ui::SetUseOSWindowFrame(xwindow_
, use_native_frame
);
1413 ResetWindowRegion();
1416 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent
* event
) {
1417 // In Windows, the native events sent to chrome are separated into client
1418 // and non-client versions of events, which we record on our LocatedEvent
1419 // structures. On X11, we emulate the concept of non-client. Before we pass
1420 // this event to the cross platform event handling framework, we need to
1421 // make sure it is appropriately marked as non-client if it's in the non
1422 // client area, or otherwise, we can get into a state where the a window is
1423 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1424 // despite the mouse button being released.
1426 // We can't do this later in the dispatch process because we share that
1427 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1428 // events, since ash doesn't expect this bit to be set, because it's never
1429 // been set before. (This works on ash on Windows because none of the mouse
1430 // events on the ash desktop are clicking in what Windows considers to be a
1431 // non client area.) Likewise, we won't want to do the following in any
1432 // WindowTreeHost that hosts ash.
1433 if (content_window_
&& content_window_
->delegate()) {
1434 int flags
= event
->flags();
1436 content_window_
->delegate()->GetNonClientComponent(event
->location());
1437 if (hit_test_code
!= HTCLIENT
&& hit_test_code
!= HTNOWHERE
)
1438 flags
|= ui::EF_IS_NON_CLIENT
;
1439 event
->set_flags(flags
);
1442 // While we unset the urgency hint when we gain focus, we also must remove it
1443 // on mouse clicks because we can call FlashFrame() on an active window.
1444 if (event
->IsAnyButton() || event
->IsMouseWheelEvent())
1447 if (!g_current_capture
|| g_current_capture
== this) {
1448 SendEventToProcessor(event
);
1450 // Another DesktopWindowTreeHostX11 has installed itself as
1451 // capture. Translate the event's location and dispatch to the other.
1452 ConvertEventToDifferentHost(event
, g_current_capture
);
1453 g_current_capture
->SendEventToProcessor(event
);
1457 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent
* event
) {
1458 if (g_current_capture
&& g_current_capture
!= this &&
1459 event
->type() == ui::ET_TOUCH_PRESSED
) {
1460 ConvertEventToDifferentHost(event
, g_current_capture
);
1461 g_current_capture
->SendEventToProcessor(event
);
1463 SendEventToProcessor(event
);
1467 void DesktopWindowTreeHostX11::ConvertEventToDifferentHost(
1468 ui::LocatedEvent
* located_event
,
1469 DesktopWindowTreeHostX11
* host
) {
1470 DCHECK_NE(this, host
);
1471 const gfx::Display display_src
=
1472 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(window());
1473 const gfx::Display display_dest
=
1474 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(host
->window());
1475 DCHECK_EQ(display_src
.device_scale_factor(),
1476 display_dest
.device_scale_factor());
1477 gfx::Vector2d offset
= GetLocationOnNativeScreen() -
1478 host
->GetLocationOnNativeScreen();
1479 gfx::Point location_in_pixel_in_host
= located_event
->location() + offset
;
1480 located_event
->set_location(location_in_pixel_in_host
);
1483 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1484 // If a custom window shape was supplied then apply it.
1485 if (custom_window_shape_
) {
1486 XShapeCombineRegion(xdisplay_
, xwindow_
, ShapeBounding
, 0, 0,
1487 window_shape_
.get(), false);
1491 window_shape_
.reset();
1493 if (!IsMaximized() && !IsFullscreen()) {
1494 gfx::Path window_mask
;
1495 views::Widget
* widget
= native_widget_delegate_
->AsWidget();
1496 if (widget
->non_client_view()) {
1497 // Some frame views define a custom (non-rectangular) window mask. If
1498 // so, use it to define the window shape. If not, fall through.
1499 widget
->non_client_view()->GetWindowMask(bounds_in_pixels_
.size(),
1501 if (window_mask
.countPoints() > 0) {
1502 window_shape_
.reset(gfx::CreateRegionFromSkPath(window_mask
));
1503 XShapeCombineRegion(xdisplay_
, xwindow_
, ShapeBounding
, 0, 0,
1504 window_shape_
.get(), false);
1510 // If we didn't set the shape for any reason, reset the shaping information.
1511 // How this is done depends on the border style, due to quirks and bugs in
1512 // various window managers.
1513 if (ShouldUseNativeFrame()) {
1514 // If the window has system borders, the mask must be set to null (not a
1515 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1516 // not put borders on a window with a custom shape.
1517 XShapeCombineMask(xdisplay_
, xwindow_
, ShapeBounding
, 0, 0, None
, ShapeSet
);
1519 // Conversely, if the window does not have system borders, the mask must be
1520 // manually set to a rectangle that covers the whole window (not null). This
1521 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1522 // shape causes the hint to disable system borders to be ignored (resulting
1523 // in a double border).
1526 static_cast<unsigned short>(bounds_in_pixels_
.width()),
1527 static_cast<unsigned short>(bounds_in_pixels_
.height())};
1528 XShapeCombineRectangles(
1529 xdisplay_
, xwindow_
, ShapeBounding
, 0, 0, &r
, 1, ShapeSet
, YXBanded
);
1533 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1534 const gfx::ImageSkiaRep
& rep
,
1535 std::vector
<unsigned long>* data
) {
1536 int width
= rep
.GetWidth();
1537 data
->push_back(width
);
1539 int height
= rep
.GetHeight();
1540 data
->push_back(height
);
1542 const SkBitmap
& bitmap
= rep
.sk_bitmap();
1543 SkAutoLockPixels
locker(bitmap
);
1545 for (int y
= 0; y
< height
; ++y
)
1546 for (int x
= 0; x
< width
; ++x
)
1547 data
->push_back(bitmap
.getColor(x
, y
));
1550 Visual
* DesktopWindowTreeHostX11::GetARGBVisual() {
1551 XVisualInfo visual_template
;
1552 visual_template
.screen
= 0;
1555 gfx::XScopedPtr
<XVisualInfo
[]> visual_list(XGetVisualInfo(
1556 xdisplay_
, VisualScreenMask
, &visual_template
, &visuals_len
));
1557 for (int i
= 0; i
< visuals_len
; ++i
) {
1558 // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1559 // gdkvisual-x11.cc, they look for this specific visual and use it for all
1560 // their alpha channel using needs.
1562 // TODO(erg): While the following does find a valid visual, some GL drivers
1563 // don't believe that this has an alpha channel. According to marcheu@,
1564 // this should work on open source driver though. (It doesn't work with
1565 // NVidia's binaries currently.) http://crbug.com/369209
1566 const XVisualInfo
& info
= visual_list
[i
];
1567 if (info
.depth
== 32 && info
.visual
->red_mask
== 0xff0000 &&
1568 info
.visual
->green_mask
== 0x00ff00 &&
1569 info
.visual
->blue_mask
== 0x0000ff) {
1577 std::list
<XID
>& DesktopWindowTreeHostX11::open_windows() {
1579 open_windows_
= new std::list
<XID
>();
1580 return *open_windows_
;
1583 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state
) {
1584 if (show_state
!= ui::SHOW_STATE_DEFAULT
&&
1585 show_state
!= ui::SHOW_STATE_NORMAL
&&
1586 show_state
!= ui::SHOW_STATE_INACTIVE
&&
1587 show_state
!= ui::SHOW_STATE_MAXIMIZED
) {
1588 // It will behave like SHOW_STATE_NORMAL.
1592 // Before we map the window, set size hints. Otherwise, some window managers
1593 // will ignore toplevel XMoveWindow commands.
1594 XSizeHints size_hints
;
1595 size_hints
.flags
= PPosition
;
1596 size_hints
.x
= bounds_in_pixels_
.x();
1597 size_hints
.y
= bounds_in_pixels_
.y();
1598 XSetWMNormalHints(xdisplay_
, xwindow_
, &size_hints
);
1600 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1601 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1602 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1603 unsigned long wm_user_time_ms
= (show_state
== ui::SHOW_STATE_INACTIVE
) ?
1604 0 : X11DesktopHandler::get()->wm_user_time_ms();
1605 if (show_state
== ui::SHOW_STATE_INACTIVE
|| wm_user_time_ms
!= 0) {
1606 XChangeProperty(xdisplay_
,
1608 atom_cache_
.GetAtom("_NET_WM_USER_TIME"),
1612 reinterpret_cast<const unsigned char *>(&wm_user_time_ms
),
1616 XMapWindow(xdisplay_
, xwindow_
);
1618 // We now block until our window is mapped. Some X11 APIs will crash and
1619 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1621 if (ui::X11EventSource::GetInstance())
1622 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_
);
1623 window_mapped_
= true;
1625 UpdateMinAndMaxSize();
1627 // Some WMs only respect maximize hints after the window has been mapped.
1628 // Check whether we need to re-do a maximization.
1629 if (should_maximize_after_map_
) {
1631 should_maximize_after_map_
= false;
1635 void DesktopWindowTreeHostX11::SetWindowTransparency() {
1636 compositor()->SetHostHasTransparentBackground(use_argb_visual_
);
1637 window()->SetTransparent(use_argb_visual_
);
1638 content_window_
->SetTransparent(use_argb_visual_
);
1641 void DesktopWindowTreeHostX11::Relayout() {
1642 Widget
* widget
= native_widget_delegate_
->AsWidget();
1643 NonClientView
* non_client_view
= widget
->non_client_view();
1644 // non_client_view may be NULL, especially during creation.
1645 if (non_client_view
) {
1646 non_client_view
->client_view()->InvalidateLayout();
1647 non_client_view
->InvalidateLayout();
1649 widget
->GetRootView()->Layout();
1652 ////////////////////////////////////////////////////////////////////////////////
1653 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1655 bool DesktopWindowTreeHostX11::CanDispatchEvent(
1656 const ui::PlatformEvent
& event
) {
1657 return event
->xany
.window
== xwindow_
||
1658 (event
->type
== GenericEvent
&&
1659 static_cast<XIDeviceEvent
*>(event
->xcookie
.data
)->event
== xwindow_
);
1662 uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1663 const ui::PlatformEvent
& event
) {
1664 XEvent
* xev
= event
;
1666 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1667 "event->type", event
->type
);
1669 UpdateWMUserTime(event
);
1671 // May want to factor CheckXEventForConsistency(xev); into a common location
1672 // since it is called here.
1673 switch (xev
->type
) {
1676 // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1677 // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1678 // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1679 // necessary. crbug.com/385716
1680 if (xev
->xcrossing
.detail
== NotifyInferior
)
1683 ui::MouseEvent
mouse_event(xev
);
1684 DispatchMouseEvent(&mouse_event
);
1688 gfx::Rect
damage_rect_in_pixels(xev
->xexpose
.x
, xev
->xexpose
.y
,
1689 xev
->xexpose
.width
, xev
->xexpose
.height
);
1690 compositor()->ScheduleRedrawRect(damage_rect_in_pixels
);
1694 ui::KeyEvent
keydown_event(xev
);
1695 SendEventToProcessor(&keydown_event
);
1699 // There is no way to deactivate a window in X11 so ignore input if
1700 // window is supposed to be 'inactive'. See comments in
1701 // X11DesktopHandler::DeactivateWindow() for more details.
1702 if (!IsActive() && !HasCapture())
1705 ui::KeyEvent
key_event(xev
);
1706 SendEventToProcessor(&key_event
);
1710 case ButtonRelease
: {
1711 ui::EventType event_type
= ui::EventTypeFromNative(xev
);
1712 switch (event_type
) {
1713 case ui::ET_MOUSEWHEEL
: {
1714 ui::MouseWheelEvent
mouseev(xev
);
1715 DispatchMouseEvent(&mouseev
);
1718 case ui::ET_MOUSE_PRESSED
:
1719 case ui::ET_MOUSE_RELEASED
: {
1720 ui::MouseEvent
mouseev(xev
);
1721 DispatchMouseEvent(&mouseev
);
1724 case ui::ET_UNKNOWN
:
1725 // No event is created for X11-release events for mouse-wheel buttons.
1728 NOTREACHED() << event_type
;
1733 if (xev
->xfocus
.mode
!= NotifyGrab
) {
1735 OnHostLostWindowCapture();
1736 X11DesktopHandler::get()->ProcessXEvent(xev
);
1738 dispatcher()->OnHostLostMouseGrab();
1742 X11DesktopHandler::get()->ProcessXEvent(xev
);
1744 case ConfigureNotify
: {
1745 DCHECK_EQ(xwindow_
, xev
->xconfigure
.window
);
1746 DCHECK_EQ(xwindow_
, xev
->xconfigure
.event
);
1747 // It's possible that the X window may be resized by some other means than
1748 // from within aura (e.g. the X window manager can change the size). Make
1749 // sure the root window size is maintained properly.
1750 int translated_x_in_pixels
= xev
->xconfigure
.x
;
1751 int translated_y_in_pixels
= xev
->xconfigure
.y
;
1752 if (!xev
->xconfigure
.send_event
&& !xev
->xconfigure
.override_redirect
) {
1754 XTranslateCoordinates(xdisplay_
, xwindow_
, x_root_window_
, 0, 0,
1755 &translated_x_in_pixels
, &translated_y_in_pixels
,
1758 gfx::Rect
bounds_in_pixels(translated_x_in_pixels
, translated_y_in_pixels
,
1759 xev
->xconfigure
.width
, xev
->xconfigure
.height
);
1760 bool size_changed
= bounds_in_pixels_
.size() != bounds_in_pixels
.size();
1761 bool origin_changed
=
1762 bounds_in_pixels_
.origin() != bounds_in_pixels
.origin();
1763 previous_bounds_in_pixels_
= bounds_in_pixels_
;
1764 bounds_in_pixels_
= bounds_in_pixels
;
1767 OnHostMoved(bounds_in_pixels_
.origin());
1770 delayed_resize_task_
.Reset(base::Bind(
1771 &DesktopWindowTreeHostX11::DelayedResize
,
1772 close_widget_factory_
.GetWeakPtr(), bounds_in_pixels
.size()));
1773 base::MessageLoop::current()->PostTask(
1774 FROM_HERE
, delayed_resize_task_
.callback());
1778 case GenericEvent
: {
1779 ui::TouchFactory
* factory
= ui::TouchFactory::GetInstance();
1780 if (!factory
->ShouldProcessXI2Event(xev
))
1783 ui::EventType type
= ui::EventTypeFromNative(xev
);
1785 int num_coalesced
= 0;
1788 case ui::ET_TOUCH_MOVED
:
1789 num_coalesced
= ui::CoalescePendingMotionEvents(xev
, &last_event
);
1790 if (num_coalesced
> 0)
1793 case ui::ET_TOUCH_PRESSED
:
1794 case ui::ET_TOUCH_RELEASED
: {
1795 ui::TouchEvent
touchev(xev
);
1796 DispatchTouchEvent(&touchev
);
1799 case ui::ET_MOUSE_MOVED
:
1800 case ui::ET_MOUSE_DRAGGED
:
1801 case ui::ET_MOUSE_PRESSED
:
1802 case ui::ET_MOUSE_RELEASED
:
1803 case ui::ET_MOUSE_ENTERED
:
1804 case ui::ET_MOUSE_EXITED
: {
1805 if (type
== ui::ET_MOUSE_MOVED
|| type
== ui::ET_MOUSE_DRAGGED
) {
1806 // If this is a motion event, we want to coalesce all pending motion
1807 // events that are at the top of the queue.
1808 num_coalesced
= ui::CoalescePendingMotionEvents(xev
, &last_event
);
1809 if (num_coalesced
> 0)
1812 ui::MouseEvent
mouseev(xev
);
1813 DispatchMouseEvent(&mouseev
);
1816 case ui::ET_MOUSEWHEEL
: {
1817 ui::MouseWheelEvent
mouseev(xev
);
1818 DispatchMouseEvent(&mouseev
);
1821 case ui::ET_SCROLL_FLING_START
:
1822 case ui::ET_SCROLL_FLING_CANCEL
:
1823 case ui::ET_SCROLL
: {
1824 ui::ScrollEvent
scrollev(xev
);
1825 SendEventToProcessor(&scrollev
);
1828 case ui::ET_KEY_PRESSED
:
1829 case ui::ET_KEY_RELEASED
: {
1830 ui::KeyEvent
key_event(xev
);
1831 SendEventToProcessor(&key_event
);
1834 case ui::ET_UNKNOWN
:
1840 // If we coalesced an event we need to free its cookie.
1841 if (num_coalesced
> 0)
1842 XFreeEventData(xev
->xgeneric
.display
, &last_event
.xcookie
);
1846 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11
,
1848 OnWindowMapped(xwindow_
));
1852 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11
,
1854 OnWindowUnmapped(xwindow_
));
1857 case ClientMessage
: {
1858 Atom message_type
= xev
->xclient
.message_type
;
1859 if (message_type
== atom_cache_
.GetAtom("WM_PROTOCOLS")) {
1860 Atom protocol
= static_cast<Atom
>(xev
->xclient
.data
.l
[0]);
1861 if (protocol
== atom_cache_
.GetAtom("WM_DELETE_WINDOW")) {
1862 // We have received a close message from the window manager.
1863 OnHostCloseRequested();
1864 } else if (protocol
== atom_cache_
.GetAtom("_NET_WM_PING")) {
1865 XEvent reply_event
= *xev
;
1866 reply_event
.xclient
.window
= x_root_window_
;
1868 XSendEvent(xdisplay_
,
1869 reply_event
.xclient
.window
,
1871 SubstructureRedirectMask
| SubstructureNotifyMask
,
1874 } else if (message_type
== atom_cache_
.GetAtom("XdndEnter")) {
1875 drag_drop_client_
->OnXdndEnter(xev
->xclient
);
1876 } else if (message_type
== atom_cache_
.GetAtom("XdndLeave")) {
1877 drag_drop_client_
->OnXdndLeave(xev
->xclient
);
1878 } else if (message_type
== atom_cache_
.GetAtom("XdndPosition")) {
1879 drag_drop_client_
->OnXdndPosition(xev
->xclient
);
1880 } else if (message_type
== atom_cache_
.GetAtom("XdndStatus")) {
1881 drag_drop_client_
->OnXdndStatus(xev
->xclient
);
1882 } else if (message_type
== atom_cache_
.GetAtom("XdndFinished")) {
1883 drag_drop_client_
->OnXdndFinished(xev
->xclient
);
1884 } else if (message_type
== atom_cache_
.GetAtom("XdndDrop")) {
1885 drag_drop_client_
->OnXdndDrop(xev
->xclient
);
1889 case MappingNotify
: {
1890 switch (xev
->xmapping
.request
) {
1891 case MappingModifier
:
1892 case MappingKeyboard
:
1893 XRefreshKeyboardMapping(&xev
->xmapping
);
1895 case MappingPointer
:
1896 ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
1899 NOTIMPLEMENTED() << " Unknown request: " << xev
->xmapping
.request
;
1904 case MotionNotify
: {
1905 // Discard all but the most recent motion event that targets the same
1906 // window with unchanged state.
1908 while (XPending(xev
->xany
.display
)) {
1910 XPeekEvent(xev
->xany
.display
, &next_event
);
1911 if (next_event
.type
== MotionNotify
&&
1912 next_event
.xmotion
.window
== xev
->xmotion
.window
&&
1913 next_event
.xmotion
.subwindow
== xev
->xmotion
.subwindow
&&
1914 next_event
.xmotion
.state
== xev
->xmotion
.state
) {
1915 XNextEvent(xev
->xany
.display
, &last_event
);
1922 ui::MouseEvent
mouseev(xev
);
1923 DispatchMouseEvent(&mouseev
);
1926 case PropertyNotify
: {
1927 ::Atom changed_atom
= xev
->xproperty
.atom
;
1928 if (changed_atom
== atom_cache_
.GetAtom("_NET_WM_STATE"))
1930 else if (changed_atom
== atom_cache_
.GetAtom("_NET_FRAME_EXTENTS"))
1931 OnFrameExtentsUpdated();
1934 case SelectionNotify
: {
1935 drag_drop_client_
->OnSelectionNotify(xev
->xselection
);
1939 return ui::POST_DISPATCH_STOP_PROPAGATION
;
1942 void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size
& size_in_pixels
) {
1943 OnHostResized(size_in_pixels
);
1944 ResetWindowRegion();
1945 delayed_resize_task_
.Cancel();
1948 gfx::Rect
DesktopWindowTreeHostX11::GetWorkAreaBoundsInPixels() const {
1949 std::vector
<int> value
;
1950 if (ui::GetIntArrayProperty(x_root_window_
, "_NET_WORKAREA", &value
) &&
1951 value
.size() >= 4) {
1952 return gfx::Rect(value
[0], value
[1], value
[2], value
[3]);
1955 // Fetch the geometry of the root window.
1958 unsigned int width
, height
;
1959 unsigned int border_width
, depth
;
1960 if (!XGetGeometry(xdisplay_
, x_root_window_
, &root
, &x
, &y
, &width
, &height
,
1961 &border_width
, &depth
)) {
1963 return gfx::Rect(0, 0, 10, 10);
1966 return gfx::Rect(x
, y
, width
, height
);
1969 gfx::Rect
DesktopWindowTreeHostX11::ToDIPRect(
1970 const gfx::Rect
& rect_in_pixels
) const {
1971 gfx::RectF rect_in_dip
= rect_in_pixels
;
1972 GetRootTransform().TransformRectReverse(&rect_in_dip
);
1973 return gfx::ToEnclosingRect(rect_in_dip
);
1976 gfx::Rect
DesktopWindowTreeHostX11::ToPixelRect(
1977 const gfx::Rect
& rect_in_dip
) const {
1978 gfx::RectF rect_in_pixels
= rect_in_dip
;
1979 GetRootTransform().TransformRect(&rect_in_pixels
);
1980 return gfx::ToEnclosingRect(rect_in_pixels
);
1983 ////////////////////////////////////////////////////////////////////////////////
1984 // DesktopWindowTreeHost, public:
1987 DesktopWindowTreeHost
* DesktopWindowTreeHost::Create(
1988 internal::NativeWidgetDelegate
* native_widget_delegate
,
1989 DesktopNativeWidgetAura
* desktop_native_widget_aura
) {
1990 return new DesktopWindowTreeHostX11(native_widget_delegate
,
1991 desktop_native_widget_aura
);
1995 ui::NativeTheme
* DesktopWindowTreeHost::GetNativeTheme(aura::Window
* window
) {
1996 const views::LinuxUI
* linux_ui
= views::LinuxUI::instance();
1998 ui::NativeTheme
* native_theme
= linux_ui
->GetNativeTheme(window
);
2000 return native_theme
;
2003 return ui::NativeTheme::instance();
2006 } // namespace views