- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / widget / desktop_aura / desktop_root_window_host_x11.cc
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.
4
5 #include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
6
7 #include <X11/extensions/shape.h>
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xregion.h>
11 #include <X11/Xutil.h>
12
13 #include "base/basictypes.h"
14 #include "base/message_loop/message_pump_x11.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "third_party/skia/include/core/SkPath.h"
18 #include "ui/aura/client/cursor_client.h"
19 #include "ui/aura/client/focus_client.h"
20 #include "ui/aura/client/user_action_client.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/window_property.h"
23 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
24 #include "ui/base/x/x11_util.h"
25 #include "ui/events/event_utils.h"
26 #include "ui/events/x/device_data_manager.h"
27 #include "ui/events/x/touch_factory_x11.h"
28 #include "ui/gfx/insets.h"
29 #include "ui/gfx/path.h"
30 #include "ui/gfx/path_x11.h"
31 #include "ui/native_theme/native_theme.h"
32 #include "ui/views/corewm/compound_event_filter.h"
33 #include "ui/views/corewm/corewm_switches.h"
34 #include "ui/views/corewm/tooltip_aura.h"
35 #include "ui/views/ime/input_method.h"
36 #include "ui/views/linux_ui/linux_ui.h"
37 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
38 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
39 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
40 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
41 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
42 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
43 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
44 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
45
46 namespace views {
47
48 DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
49     NULL;
50 std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
51
52 DEFINE_WINDOW_PROPERTY_KEY(
53     aura::Window*, kViewsWindowForRootWindow, NULL);
54
55 DEFINE_WINDOW_PROPERTY_KEY(
56     DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
57
58 namespace {
59
60 // Standard Linux mouse buttons for going back and forward.
61 const int kBackMouseButton = 8;
62 const int kForwardMouseButton = 9;
63
64 // Constants that are part of EWMH.
65 const int k_NET_WM_STATE_ADD = 1;
66 const int k_NET_WM_STATE_REMOVE = 0;
67
68 const char* kAtomsToCache[] = {
69   "WM_DELETE_WINDOW",
70   "WM_PROTOCOLS",
71   "WM_S0",
72   "_NET_WM_PID",
73   "_NET_WM_PING",
74   "_NET_WM_STATE",
75   "_NET_WM_STATE_ABOVE",
76   "_NET_WM_STATE_FULLSCREEN",
77   "_NET_WM_STATE_HIDDEN",
78   "_NET_WM_STATE_MAXIMIZED_HORZ",
79   "_NET_WM_STATE_MAXIMIZED_VERT",
80   "_NET_WM_STATE_SKIP_TASKBAR",
81   "_NET_WM_WINDOW_OPACITY",
82   "_NET_WM_WINDOW_TYPE",
83   "_NET_WM_WINDOW_TYPE_MENU",
84   "_NET_WM_WINDOW_TYPE_NORMAL",
85   "_NET_WM_WINDOW_TYPE_TOOLTIP",
86   "XdndActionAsk",
87   "XdndActionCopy"
88   "XdndActionLink",
89   "XdndActionList",
90   "XdndActionMove",
91   "XdndActionPrivate",
92   "XdndAware",
93   "XdndDrop",
94   "XdndEnter",
95   "XdndFinished",
96   "XdndLeave",
97   "XdndPosition",
98   "XdndProxy",  // Proxy windows?
99   "XdndSelection",
100   "XdndStatus",
101   "XdndTypeList",
102   NULL
103 };
104
105 }  // namespace
106
107 ////////////////////////////////////////////////////////////////////////////////
108 // DesktopRootWindowHostX11, public:
109
110 DesktopRootWindowHostX11::DesktopRootWindowHostX11(
111     internal::NativeWidgetDelegate* native_widget_delegate,
112     DesktopNativeWidgetAura* desktop_native_widget_aura)
113     : close_widget_factory_(this),
114       xdisplay_(gfx::GetXDisplay()),
115       xwindow_(0),
116       x_root_window_(DefaultRootWindow(xdisplay_)),
117       atom_cache_(xdisplay_, kAtomsToCache),
118       window_mapped_(false),
119       focus_when_shown_(false),
120       is_fullscreen_(false),
121       is_always_on_top_(false),
122       root_window_(NULL),
123       drag_drop_client_(NULL),
124       current_cursor_(ui::kCursorNull),
125       native_widget_delegate_(native_widget_delegate),
126       desktop_native_widget_aura_(desktop_native_widget_aura),
127       root_window_host_delegate_(NULL),
128       content_window_(NULL),
129       window_parent_(NULL) {
130 }
131
132 DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
133   root_window_->ClearProperty(kHostForRootWindow);
134   aura::client::SetWindowMoveClient(root_window_, NULL);
135   desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_);
136 }
137
138 // static
139 aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
140   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
141   return root ? root->GetProperty(kViewsWindowForRootWindow) : NULL;
142 }
143
144 // static
145 DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
146   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
147   return root ? root->GetProperty(kHostForRootWindow) : NULL;
148 }
149
150 // static
151 std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
152   std::vector<aura::Window*> windows(open_windows().size());
153   std::transform(open_windows().begin(),
154                  open_windows().end(),
155                  windows.begin(),
156                  GetContentWindowForXID);
157   return windows;
158 }
159
160 gfx::Rect DesktopRootWindowHostX11::GetX11RootWindowBounds() const {
161   return bounds_;
162 }
163
164 void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
165     bool active) {
166   if (active)
167     root_window_host_delegate_->OnHostActivated();
168
169   desktop_native_widget_aura_->HandleActivationChanged(active);
170
171   native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
172 }
173
174 void DesktopRootWindowHostX11::AddObserver(
175     views::DesktopRootWindowHostObserverX11* observer) {
176   observer_list_.AddObserver(observer);
177 }
178
179 void DesktopRootWindowHostX11::RemoveObserver(
180     views::DesktopRootWindowHostObserverX11* observer) {
181   observer_list_.RemoveObserver(observer);
182 }
183
184 void DesktopRootWindowHostX11::CleanUpWindowList() {
185   delete open_windows_;
186   open_windows_ = NULL;
187 }
188
189 ////////////////////////////////////////////////////////////////////////////////
190 // DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
191
192 void DesktopRootWindowHostX11::Init(
193     aura::Window* content_window,
194     const Widget::InitParams& params,
195     aura::RootWindow::CreateParams* rw_create_params) {
196   content_window_ = content_window;
197
198   // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
199   // whether we should be proxying requests to another DRWHL.
200
201   // In some situations, views tries to make a zero sized window, and that
202   // makes us crash. Make sure we have valid sizes.
203   Widget::InitParams sanitized_params = params;
204   if (sanitized_params.bounds.width() == 0)
205     sanitized_params.bounds.set_width(100);
206   if (sanitized_params.bounds.height() == 0)
207     sanitized_params.bounds.set_height(100);
208
209   InitX11Window(sanitized_params);
210
211   rw_create_params->initial_bounds = bounds_;
212   rw_create_params->host = this;
213 }
214
215 void DesktopRootWindowHostX11::OnRootWindowCreated(
216     aura::RootWindow* root,
217     const Widget::InitParams& params) {
218   root_window_ = root;
219
220   root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
221   root_window_->SetProperty(kHostForRootWindow, this);
222   root_window_host_delegate_ = root_window_;
223
224   // If we're given a parent, we need to mark ourselves as transient to another
225   // window. Otherwise activation gets screwy.
226   gfx::NativeView parent = params.parent;
227   if (!params.child && params.parent)
228     parent->AddTransientChild(content_window_);
229
230   // Ensure that the X11DesktopHandler exists so that it dispatches activation
231   // messages to us.
232   X11DesktopHandler::get();
233
234   // TODO(erg): Unify this code once the other consumer goes away.
235   x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_));
236   x11_window_event_filter_->SetUseHostWindowBorders(false);
237   desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
238       x11_window_event_filter_.get());
239
240   x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
241   aura::client::SetWindowMoveClient(root_window_,
242                                     x11_window_move_client_.get());
243
244   native_widget_delegate_->OnNativeWidgetCreated(true);
245 }
246
247 scoped_ptr<corewm::Tooltip> DesktopRootWindowHostX11::CreateTooltip() {
248   return scoped_ptr<corewm::Tooltip>(
249       new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
250 }
251
252 scoped_ptr<aura::client::DragDropClient>
253 DesktopRootWindowHostX11::CreateDragDropClient(
254     DesktopNativeCursorManager* cursor_manager) {
255   drag_drop_client_ = new DesktopDragDropClientAuraX11(
256       root_window_, cursor_manager, xdisplay_, xwindow_);
257   return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
258 }
259
260 void DesktopRootWindowHostX11::Close() {
261   // TODO(erg): Might need to do additional hiding tasks here.
262
263   if (!close_widget_factory_.HasWeakPtrs()) {
264     // And we delay the close so that if we are called from an ATL callback,
265     // we don't destroy the window before the callback returned (as the caller
266     // may delete ourselves on destroy and the ATL callback would still
267     // dereference us when the callback returns).
268     base::MessageLoop::current()->PostTask(
269         FROM_HERE,
270         base::Bind(&DesktopRootWindowHostX11::CloseNow,
271                    close_widget_factory_.GetWeakPtr()));
272   }
273 }
274
275 void DesktopRootWindowHostX11::CloseNow() {
276   if (xwindow_ == None)
277     return;
278
279   native_widget_delegate_->OnNativeWidgetDestroying();
280
281   // If we have children, close them. Use a copy for iteration because they'll
282   // remove themselves.
283   std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_;
284   for (std::set<DesktopRootWindowHostX11*>::iterator it =
285            window_children_copy.begin(); it != window_children_copy.end();
286        ++it) {
287     (*it)->CloseNow();
288   }
289   DCHECK(window_children_.empty());
290
291   // If we have a parent, remove ourselves from its children list.
292   if (window_parent_) {
293     window_parent_->window_children_.erase(this);
294     window_parent_ = NULL;
295   }
296
297   // Remove the event listeners we've installed. We need to remove these
298   // because otherwise we get assert during ~RootWindow().
299   desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
300       x11_window_event_filter_.get());
301
302   open_windows().remove(xwindow_);
303   // Actually free our native resources.
304   base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
305   XDestroyWindow(xdisplay_, xwindow_);
306   xwindow_ = None;
307
308   desktop_native_widget_aura_->OnHostClosed();
309 }
310
311 aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
312   return this;
313 }
314
315 void DesktopRootWindowHostX11::ShowWindowWithState(
316     ui::WindowShowState show_state) {
317   if (show_state != ui::SHOW_STATE_DEFAULT &&
318       show_state != ui::SHOW_STATE_NORMAL) {
319     // Only forwarding to Show().
320     NOTIMPLEMENTED();
321   }
322
323   Show();
324 }
325
326 void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
327     const gfx::Rect& restored_bounds) {
328   restored_bounds_ = restored_bounds;
329   Maximize();
330   Show();
331 }
332
333 bool DesktopRootWindowHostX11::IsVisible() const {
334   return window_mapped_;
335 }
336
337 void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
338   // TODO(erg):
339   NOTIMPLEMENTED();
340 }
341
342 void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
343   gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
344
345   // If |window_|'s transient parent bounds are big enough to contain |size|,
346   // use them instead.
347   if (content_window_->transient_parent()) {
348     gfx::Rect transient_parent_rect =
349         content_window_->transient_parent()->GetBoundsInScreen();
350     if (transient_parent_rect.height() >= size.height() &&
351         transient_parent_rect.width() >= size.width()) {
352       parent_bounds = transient_parent_rect;
353     }
354   }
355
356   gfx::Rect window_bounds(
357       parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
358       parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
359       size.width(),
360       size.height());
361   // Don't size the window bigger than the parent, otherwise the user may not be
362   // able to close or move it.
363   window_bounds.AdjustToFit(parent_bounds);
364
365   SetBounds(window_bounds);
366 }
367
368 void DesktopRootWindowHostX11::GetWindowPlacement(
369     gfx::Rect* bounds,
370     ui::WindowShowState* show_state) const {
371   *bounds = bounds_;
372
373   if (IsFullscreen()) {
374     *show_state = ui::SHOW_STATE_FULLSCREEN;
375   } else if (IsMinimized()) {
376     *show_state = ui::SHOW_STATE_MINIMIZED;
377   } else if (IsMaximized()) {
378     *show_state = ui::SHOW_STATE_MAXIMIZED;
379   } else if (!IsActive()) {
380     *show_state = ui::SHOW_STATE_INACTIVE;
381   } else {
382     *show_state = ui::SHOW_STATE_NORMAL;
383   }
384 }
385
386 gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
387   return bounds_;
388 }
389
390 gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
391   // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
392   // needed for View::ConvertPointToScreen() to work
393   // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
394   // asks windows what it thinks the client rect is.
395   //
396   // Attempts to calculate the rect by asking the NonClientFrameView what it
397   // thought its GetBoundsForClientView() were broke combobox drop down
398   // placement.
399   return bounds_;
400 }
401
402 gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
403   // We can't reliably track the restored bounds of a window, but we can get
404   // the 90% case down. When *chrome* is the process that requests maximizing
405   // or restoring bounds, we can record the current bounds before we request
406   // maximization, and clear it when we detect a state change.
407   if (!restored_bounds_.IsEmpty())
408     return restored_bounds_;
409
410   return GetWindowBoundsInScreen();
411 }
412
413 gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
414   std::vector<int> value;
415   if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
416       value.size() >= 4) {
417     return gfx::Rect(value[0], value[1], value[2], value[3]);
418   }
419
420   // Fetch the geometry of the root window.
421   Window root;
422   int x, y;
423   unsigned int width, height;
424   unsigned int border_width, depth;
425   if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
426                     &width, &height, &border_width, &depth)) {
427     NOTIMPLEMENTED();
428     return gfx::Rect(0, 0, 10, 10);
429   }
430
431   return gfx::Rect(x, y, width, height);
432 }
433
434 void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
435   if (native_region) {
436     SkPath path;
437     native_region->getBoundaryPath(&path);
438     Region region = gfx::CreateRegionFromSkPath(path);
439     XShapeCombineRegion(
440         xdisplay_, xwindow_, ShapeBounding, 0, 0, region, false);
441     XDestroyRegion(region);
442   } else {
443     ResetWindowRegion();
444   }
445
446   delete native_region;
447 }
448
449 void DesktopRootWindowHostX11::Activate() {
450   X11DesktopHandler::get()->ActivateWindow(xwindow_);
451 }
452
453 void DesktopRootWindowHostX11::Deactivate() {
454   // Deactivating a window means activating nothing.
455   X11DesktopHandler::get()->ActivateWindow(None);
456 }
457
458 bool DesktopRootWindowHostX11::IsActive() const {
459   return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
460 }
461
462 void DesktopRootWindowHostX11::Maximize() {
463   // When we're the process requesting the maximizing, we can accurately keep
464   // track of our restored bounds instead of relying on the heuristics that are
465   // in the PropertyNotify and ConfigureNotify handlers.
466   restored_bounds_ = bounds_;
467
468   SetWMSpecState(true,
469                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
470                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
471 }
472
473 void DesktopRootWindowHostX11::Minimize() {
474   XIconifyWindow(xdisplay_, xwindow_, 0);
475 }
476
477 void DesktopRootWindowHostX11::Restore() {
478   SetWMSpecState(false,
479                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
480                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
481 }
482
483 bool DesktopRootWindowHostX11::IsMaximized() const {
484   return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") ||
485           HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
486 }
487
488 bool DesktopRootWindowHostX11::IsMinimized() const {
489   return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
490 }
491
492
493 bool DesktopRootWindowHostX11::HasCapture() const {
494   return g_current_capture == this;
495 }
496
497 void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
498   is_always_on_top_ = always_on_top;
499   SetWMSpecState(always_on_top,
500                  atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
501                  None);
502 }
503
504 bool DesktopRootWindowHostX11::IsAlwaysOnTop() const {
505   return is_always_on_top_;
506 }
507
508 void DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
509   XmbSetWMProperties(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str(), NULL,
510       NULL, 0, NULL, NULL, NULL);
511 }
512
513 void DesktopRootWindowHostX11::ClearNativeFocus() {
514   // This method is weird and misnamed. Instead of clearing the native focus,
515   // it sets the focus to our |content_window_|, which will trigger a cascade
516   // of focus changes into views.
517   if (content_window_ && aura::client::GetFocusClient(content_window_) &&
518       content_window_->Contains(
519           aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
520     aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
521   }
522 }
523
524 Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
525     const gfx::Vector2d& drag_offset,
526     Widget::MoveLoopSource source,
527     Widget::MoveLoopEscapeBehavior escape_behavior) {
528   SetCapture();
529
530   aura::client::WindowMoveSource window_move_source =
531       source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
532       aura::client::WINDOW_MOVE_SOURCE_MOUSE :
533       aura::client::WINDOW_MOVE_SOURCE_TOUCH;
534   if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
535       window_move_source) == aura::client::MOVE_SUCCESSFUL)
536     return Widget::MOVE_LOOP_SUCCESSFUL;
537
538   return Widget::MOVE_LOOP_CANCELED;
539 }
540
541 void DesktopRootWindowHostX11::EndMoveLoop() {
542   x11_window_move_client_->EndMoveLoop();
543 }
544
545 void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
546     bool value) {
547   // Much like the previous NativeWidgetGtk, we don't have anything to do here.
548 }
549
550 bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
551   return false;
552 }
553
554 void DesktopRootWindowHostX11::FrameTypeChanged() {
555   // Replace the frame and layout the contents. Even though we don't have a
556   // swapable glass frame like on Windows, we still replace the frame because
557   // the button assets don't update otherwise.
558   native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(true);
559 }
560
561 NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
562   return NULL;
563 }
564
565 void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
566   is_fullscreen_ = fullscreen;
567   SetWMSpecState(fullscreen,
568                  atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
569                  None);
570 }
571
572 bool DesktopRootWindowHostX11::IsFullscreen() const {
573   return is_fullscreen_;
574 }
575
576 void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
577   // X server opacity is in terms of 32 bit unsigned int space, and counts from
578   // the opposite direction.
579   // XChangeProperty() expects "cardinality" to be long.
580   unsigned long cardinality = opacity * 0x1010101;
581
582   if (cardinality == 0xffffffff) {
583     XDeleteProperty(xdisplay_, xwindow_,
584                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
585   } else {
586     XChangeProperty(xdisplay_, xwindow_,
587                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
588                     XA_CARDINAL, 32,
589                     PropModeReplace,
590                     reinterpret_cast<unsigned char*>(&cardinality), 1);
591   }
592 }
593
594 void DesktopRootWindowHostX11::SetWindowIcons(
595     const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
596   // TODO(erg):
597   NOTIMPLEMENTED();
598 }
599
600 void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
601   switch (modal_type) {
602     case ui::MODAL_TYPE_NONE:
603       break;
604     default:
605       // TODO(erg): Figure out under what situations |modal_type| isn't
606       // none. The comment in desktop_native_widget_aura.cc suggests that this
607       // is rare.
608       NOTIMPLEMENTED();
609   }
610 }
611
612 void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
613   // TODO(erg):
614   NOTIMPLEMENTED();
615 }
616
617 void DesktopRootWindowHostX11::OnRootViewLayout() const {
618   if (!window_mapped_)
619     return;
620
621   XSizeHints hints;
622   long supplied_return;
623   XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
624
625   gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
626   if (minimum.IsEmpty()) {
627     hints.flags &= ~PMinSize;
628   } else {
629     hints.flags |= PMinSize;
630     hints.min_width = minimum.width();
631     hints.min_height = minimum.height();
632   }
633
634   gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
635   if (maximum.IsEmpty()) {
636     hints.flags &= ~PMaxSize;
637   } else {
638     hints.flags |= PMaxSize;
639     hints.max_width = maximum.width();
640     hints.max_height = maximum.height();
641   }
642
643   XSetWMNormalHints(xdisplay_, xwindow_, &hints);
644 }
645
646 void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
647   native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
648 }
649
650 void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
651   if (xwindow_)
652     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
653 }
654
655 bool DesktopRootWindowHostX11::IsAnimatingClosed() const {
656   return false;
657 }
658
659 ////////////////////////////////////////////////////////////////////////////////
660 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
661
662 void DesktopRootWindowHostX11::SetDelegate(
663     aura::RootWindowHostDelegate* delegate) {
664   root_window_host_delegate_ = delegate;
665 }
666
667 aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
668   return root_window_;
669 }
670
671 gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
672   return xwindow_;
673 }
674
675 void DesktopRootWindowHostX11::Show() {
676   if (!window_mapped_) {
677     // Before we map the window, set size hints. Otherwise, some window managers
678     // will ignore toplevel XMoveWindow commands.
679     XSizeHints size_hints;
680     size_hints.flags = PPosition;
681     size_hints.x = bounds_.x();
682     size_hints.y = bounds_.y();
683     XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
684
685     XMapWindow(xdisplay_, xwindow_);
686
687     // We now block until our window is mapped. Some X11 APIs will crash and
688     // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
689     // asynchronous.
690     base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
691     window_mapped_ = true;
692   }
693 }
694
695 void DesktopRootWindowHostX11::Hide() {
696   if (window_mapped_) {
697     XWithdrawWindow(xdisplay_, xwindow_, 0);
698     window_mapped_ = false;
699   }
700 }
701
702 void DesktopRootWindowHostX11::ToggleFullScreen() {
703   NOTIMPLEMENTED();
704 }
705
706 gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
707   return bounds_;
708 }
709
710 void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
711   bool origin_changed = bounds_.origin() != bounds.origin();
712   bool size_changed = bounds_.size() != bounds.size();
713   XWindowChanges changes = {0};
714   unsigned value_mask = 0;
715
716   if (size_changed) {
717     // X11 will send an XError at our process if have a 0 sized window.
718     DCHECK_GT(bounds.width(), 0);
719     DCHECK_GT(bounds.height(), 0);
720
721     changes.width = bounds.width();
722     changes.height = bounds.height();
723     value_mask |= CWHeight | CWWidth;
724   }
725
726   if (origin_changed) {
727     changes.x = bounds.x();
728     changes.y = bounds.y();
729     value_mask |= CWX | CWY;
730   }
731   if (value_mask)
732     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
733
734   // Assume that the resize will go through as requested, which should be the
735   // case if we're running without a window manager.  If there's a window
736   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
737   // (possibly synthetic) ConfigureNotify about the actual size and correct
738   // |bounds_| later.
739   bounds_ = bounds;
740
741   if (origin_changed)
742     native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
743   if (size_changed)
744     root_window_host_delegate_->OnHostResized(bounds.size());
745   else
746     root_window_host_delegate_->OnHostPaint(gfx::Rect(bounds.size()));
747 }
748
749 gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
750   return gfx::Insets();
751 }
752
753 void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
754 }
755
756 gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
757   return bounds_.origin();
758 }
759
760 void DesktopRootWindowHostX11::SetCapture() {
761   // This is vaguely based on the old NativeWidgetGtk implementation.
762   //
763   // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
764   // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
765   // a grab that wasn't the X11 pointer grab, but was instead a manual
766   // redirection of the event. (You need to drop into GDK if you want to
767   // perform a raw X11 grab).
768
769   if (g_current_capture)
770     g_current_capture->OnCaptureReleased();
771
772   g_current_capture = this;
773
774   // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
775   // pointer grab when our NativeWidget is of type Menu. However, things work
776   // without it. Clicking inside a chrome window causes a release capture, and
777   // clicking outside causes an activation change. Since previous attempts at
778   // using XPointerGrab() to implement this have locked my X server, I'm going
779   // to skip this for now.
780 }
781
782 void DesktopRootWindowHostX11::ReleaseCapture() {
783   if (g_current_capture)
784     g_current_capture->OnCaptureReleased();
785 }
786
787 void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
788   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
789 }
790
791 bool DesktopRootWindowHostX11::QueryMouseLocation(
792     gfx::Point* location_return) {
793   aura::client::CursorClient* cursor_client =
794       aura::client::GetCursorClient(GetRootWindow());
795   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
796     *location_return = gfx::Point(0, 0);
797     return false;
798   }
799
800   ::Window root_return, child_return;
801   int root_x_return, root_y_return, win_x_return, win_y_return;
802   unsigned int mask_return;
803   XQueryPointer(xdisplay_,
804                 xwindow_,
805                 &root_return,
806                 &child_return,
807                 &root_x_return, &root_y_return,
808                 &win_x_return, &win_y_return,
809                 &mask_return);
810   *location_return = gfx::Point(
811       std::max(0, std::min(bounds_.width(), win_x_return)),
812       std::max(0, std::min(bounds_.height(), win_y_return)));
813   return (win_x_return >= 0 && win_x_return < bounds_.width() &&
814           win_y_return >= 0 && win_y_return < bounds_.height());
815 }
816
817 bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
818   NOTIMPLEMENTED();
819   return false;
820 }
821
822 void DesktopRootWindowHostX11::UnConfineCursor() {
823   NOTIMPLEMENTED();
824 }
825
826 void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
827   // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
828   // the same tap-to-click disabling here that chromeos does.
829 }
830
831 void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
832   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
833                bounds_.x() + location.x(), bounds_.y() + location.y());
834 }
835
836 void DesktopRootWindowHostX11::SetFocusWhenShown(bool focus_when_shown) {
837   static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME";
838   focus_when_shown_ = focus_when_shown;
839   if (IsWindowManagerPresent() && !focus_when_shown_) {
840     ui::SetIntProperty(xwindow_,
841                        k_NET_WM_USER_TIME,
842                        k_NET_WM_USER_TIME,
843                        0);
844   }
845 }
846
847 void DesktopRootWindowHostX11::PostNativeEvent(
848     const base::NativeEvent& native_event) {
849   DCHECK(xwindow_);
850   DCHECK(xdisplay_);
851   XEvent xevent = *native_event;
852   xevent.xany.display = xdisplay_;
853   xevent.xany.window = xwindow_;
854
855   switch (xevent.type) {
856     case EnterNotify:
857     case LeaveNotify:
858     case MotionNotify:
859     case KeyPress:
860     case KeyRelease:
861     case ButtonPress:
862     case ButtonRelease: {
863       // The fields used below are in the same place for all of events
864       // above. Using xmotion from XEvent's unions to avoid repeating
865       // the code.
866       xevent.xmotion.root = x_root_window_;
867       xevent.xmotion.time = CurrentTime;
868
869       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
870       root_window_->ConvertPointToNativeScreen(&point);
871       xevent.xmotion.x_root = point.x();
872       xevent.xmotion.y_root = point.y();
873     }
874     default:
875       break;
876   }
877   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
878 }
879
880 void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
881     float device_scale_factor) {
882 }
883
884 void DesktopRootWindowHostX11::PrepareForShutdown() {
885 }
886
887 ////////////////////////////////////////////////////////////////////////////////
888 // DesktopRootWindowHostX11, private:
889
890 void DesktopRootWindowHostX11::InitX11Window(
891     const Widget::InitParams& params) {
892   unsigned long attribute_mask = CWBackPixmap;
893   XSetWindowAttributes swa;
894   memset(&swa, 0, sizeof(swa));
895   swa.background_pixmap = None;
896
897   ::Atom window_type;
898   switch (params.type) {
899     case Widget::InitParams::TYPE_MENU:
900       swa.override_redirect = True;
901       attribute_mask |= CWOverrideRedirect;
902       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
903       break;
904     case Widget::InitParams::TYPE_TOOLTIP:
905       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
906       break;
907     default:
908       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
909       break;
910   }
911
912   bounds_ = params.bounds;
913   xwindow_ = XCreateWindow(
914       xdisplay_, x_root_window_,
915       bounds_.x(), bounds_.y(),
916       bounds_.width(), bounds_.height(),
917       0,               // border width
918       CopyFromParent,  // depth
919       InputOutput,
920       CopyFromParent,  // visual
921       attribute_mask,
922       &swa);
923   base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
924   open_windows().push_back(xwindow_);
925
926   // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
927
928   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
929                     KeyPressMask | KeyReleaseMask |
930                     EnterWindowMask | LeaveWindowMask |
931                     ExposureMask | VisibilityChangeMask |
932                     StructureNotifyMask | PropertyChangeMask |
933                     PointerMotionMask;
934   XSelectInput(xdisplay_, xwindow_, event_mask);
935   XFlush(xdisplay_);
936
937   if (base::MessagePumpForUI::HasXInput2())
938     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
939
940   // TODO(erg): We currently only request window deletion events. We also
941   // should listen for activation events and anything else that GTK+ listens
942   // for, and do something useful.
943   ::Atom protocols[2];
944   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
945   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
946   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
947
948   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
949   // the desktop environment.
950   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
951
952   // Likewise, the X server needs to know this window's pid so it knows which
953   // program to kill if the window hangs.
954   // XChangeProperty() expects "pid" to be long.
955   COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
956   long pid = params.net_wm_pid;
957   if (!pid)
958     pid = getpid();
959   XChangeProperty(xdisplay_,
960                   xwindow_,
961                   atom_cache_.GetAtom("_NET_WM_PID"),
962                   XA_CARDINAL,
963                   32,
964                   PropModeReplace,
965                   reinterpret_cast<unsigned char*>(&pid), 1);
966
967   XChangeProperty(xdisplay_,
968                   xwindow_,
969                   atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
970                   XA_ATOM,
971                   32,
972                   PropModeReplace,
973                   reinterpret_cast<unsigned char*>(&window_type), 1);
974
975   // List of window state properties (_NET_WM_STATE) to set, if any.
976   std::vector< ::Atom> state_atom_list;
977
978   // Remove popup windows from taskbar.
979   if (params.type == Widget::InitParams::TYPE_POPUP ||
980       params.type == Widget::InitParams::TYPE_BUBBLE) {
981     state_atom_list.push_back(
982         atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
983   }
984
985   // If the window should stay on top of other windows, add the
986   // _NET_WM_STATE_ABOVE property.
987   is_always_on_top_ = params.keep_on_top;
988   if (is_always_on_top_)
989     state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
990
991   // Setting _NET_WM_STATE by sending a message to the root_window (with
992   // SetWMSpecState) has no effect here since the window has not yet been
993   // mapped. So we manually change the state.
994   if (!state_atom_list.empty()) {
995     ui::SetAtomArrayProperty(xwindow_,
996                              "_NET_WM_STATE",
997                              "ATOM",
998                              state_atom_list);
999   }
1000
1001   if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1002     ui::SetWindowClassHint(
1003         xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1004   }
1005
1006   // If we have a parent, record the parent/child relationship. We use this
1007   // data during destruction to make sure that when we try to close a parent
1008   // window, we also destroy all child windows.
1009   if (params.parent && params.parent->GetDispatcher()) {
1010     XID parent_xid = params.parent->GetDispatcher()->GetAcceleratedWidget();
1011     window_parent_ = GetHostForXID(parent_xid);
1012     DCHECK(window_parent_);
1013     window_parent_->window_children_.insert(this);
1014   }
1015 }
1016
1017 bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
1018   // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
1019   // of WM_Sn selections (where n is a screen number).
1020   return XGetSelectionOwner(
1021       xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1022 }
1023
1024 void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
1025                                                 ::Atom state1,
1026                                                 ::Atom state2) {
1027   XEvent xclient;
1028   memset(&xclient, 0, sizeof(xclient));
1029   xclient.type = ClientMessage;
1030   xclient.xclient.window = xwindow_;
1031   xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1032   xclient.xclient.format = 32;
1033   xclient.xclient.data.l[0] =
1034       enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1035   xclient.xclient.data.l[1] = state1;
1036   xclient.xclient.data.l[2] = state2;
1037   xclient.xclient.data.l[3] = 1;
1038   xclient.xclient.data.l[4] = 0;
1039
1040   XSendEvent(xdisplay_, x_root_window_, False,
1041              SubstructureRedirectMask | SubstructureNotifyMask,
1042              &xclient);
1043 }
1044
1045 bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
1046   return window_properties_.find(atom_cache_.GetAtom(property)) !=
1047       window_properties_.end();
1048 }
1049
1050 void DesktopRootWindowHostX11::OnCaptureReleased() {
1051   g_current_capture = NULL;
1052   root_window_host_delegate_->OnHostLostWindowCapture();
1053   native_widget_delegate_->OnMouseCaptureLost();
1054 }
1055
1056 void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1057   if (!g_current_capture || g_current_capture == this) {
1058     root_window_host_delegate_->OnHostMouseEvent(event);
1059   } else {
1060     // Another DesktopRootWindowHostX11 has installed itself as
1061     // capture. Translate the event's location and dispatch to the other.
1062     event->ConvertLocationToTarget(root_window_,
1063                                    g_current_capture->root_window_);
1064     g_current_capture->root_window_host_delegate_->OnHostMouseEvent(event);
1065   }
1066 }
1067
1068 void DesktopRootWindowHostX11::ResetWindowRegion() {
1069   if (!IsMaximized()) {
1070     gfx::Path window_mask;
1071     views::Widget* widget = native_widget_delegate_->AsWidget();
1072     if (widget->non_client_view()) {
1073       // Some frame views define a custom (non-rectangular) window mask. If
1074       // so, use it to define the window shape. If not, fall through.
1075       widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1076       if (window_mask.countPoints() > 0) {
1077         Region region = gfx::CreateRegionFromSkPath(window_mask);
1078         XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1079                             0, 0, region, false);
1080         XDestroyRegion(region);
1081         return;
1082       }
1083     }
1084   }
1085
1086   // If we didn't set the shape for any reason, reset the shaping information
1087   // by ShapeSet-ing with our bounds rect.
1088   XRectangle r = { 0, 0, static_cast<unsigned short>(bounds_.width()),
1089                    static_cast<unsigned short>(bounds_.height()) };
1090   XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding,
1091                           0, 0, &r, 1, ShapeSet, YXBanded);
1092 }
1093
1094 std::list<XID>& DesktopRootWindowHostX11::open_windows() {
1095   if (!open_windows_)
1096     open_windows_ = new std::list<XID>();
1097   return *open_windows_;
1098 }
1099
1100 ////////////////////////////////////////////////////////////////////////////////
1101 // DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
1102
1103 bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
1104   XEvent* xev = event;
1105
1106   // May want to factor CheckXEventForConsistency(xev); into a common location
1107   // since it is called here.
1108   switch (xev->type) {
1109     case EnterNotify:
1110     case LeaveNotify: {
1111       ui::MouseEvent mouse_event(xev);
1112       DispatchMouseEvent(&mouse_event);
1113       break;
1114     }
1115     case Expose: {
1116       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1117                             xev->xexpose.width, xev->xexpose.height);
1118       root_window_host_delegate_->OnHostPaint(damage_rect);
1119       break;
1120     }
1121     case KeyPress: {
1122       ui::KeyEvent keydown_event(xev, false);
1123       root_window_host_delegate_->OnHostKeyEvent(&keydown_event);
1124       break;
1125     }
1126     case KeyRelease: {
1127       ui::KeyEvent keyup_event(xev, false);
1128       root_window_host_delegate_->OnHostKeyEvent(&keyup_event);
1129       break;
1130     }
1131     case ButtonPress: {
1132       if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
1133           static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
1134         aura::client::UserActionClient* gesture_client =
1135             aura::client::GetUserActionClient(root_window_);
1136         if (gesture_client) {
1137           gesture_client->OnUserAction(
1138               static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
1139               aura::client::UserActionClient::BACK :
1140               aura::client::UserActionClient::FORWARD);
1141         }
1142         break;
1143       }
1144     }  // fallthrough
1145     case ButtonRelease: {
1146       ui::MouseEvent mouseev(xev);
1147       DispatchMouseEvent(&mouseev);
1148       break;
1149     }
1150     case FocusOut:
1151       if (xev->xfocus.mode != NotifyGrab) {
1152         ReleaseCapture();
1153         root_window_host_delegate_->OnHostLostWindowCapture();
1154       } else {
1155         root_window_host_delegate_->OnHostLostMouseGrab();
1156       }
1157       break;
1158     case ConfigureNotify: {
1159       DCHECK_EQ(xwindow_, xev->xconfigure.window);
1160       DCHECK_EQ(xwindow_, xev->xconfigure.event);
1161       // It's possible that the X window may be resized by some other means than
1162       // from within aura (e.g. the X window manager can change the size). Make
1163       // sure the root window size is maintained properly.
1164       int translated_x = xev->xconfigure.x;
1165       int translated_y = xev->xconfigure.y;
1166       if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1167         Window unused;
1168         XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1169             0, 0, &translated_x, &translated_y, &unused);
1170       }
1171       gfx::Rect bounds(translated_x, translated_y,
1172                        xev->xconfigure.width, xev->xconfigure.height);
1173       bool size_changed = bounds_.size() != bounds.size();
1174       bool origin_changed = bounds_.origin() != bounds.origin();
1175       previous_bounds_ = bounds_;
1176       bounds_ = bounds;
1177       if (size_changed)
1178         root_window_host_delegate_->OnHostResized(bounds.size());
1179       if (origin_changed)
1180         root_window_host_delegate_->OnHostMoved(bounds_.origin());
1181       ResetWindowRegion();
1182       break;
1183     }
1184     case GenericEvent: {
1185       ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1186       if (!factory->ShouldProcessXI2Event(xev))
1187         break;
1188
1189       ui::EventType type = ui::EventTypeFromNative(xev);
1190       XEvent last_event;
1191       int num_coalesced = 0;
1192
1193       switch (type) {
1194         case ui::ET_TOUCH_MOVED:
1195         case ui::ET_TOUCH_PRESSED:
1196         case ui::ET_TOUCH_RELEASED: {
1197           ui::TouchEvent touchev(xev);
1198           root_window_host_delegate_->OnHostTouchEvent(&touchev);
1199           break;
1200         }
1201         case ui::ET_MOUSE_MOVED:
1202         case ui::ET_MOUSE_DRAGGED:
1203         case ui::ET_MOUSE_PRESSED:
1204         case ui::ET_MOUSE_RELEASED:
1205         case ui::ET_MOUSE_ENTERED:
1206         case ui::ET_MOUSE_EXITED: {
1207           if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1208             // If this is a motion event, we want to coalesce all pending motion
1209             // events that are at the top of the queue.
1210             num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1211             if (num_coalesced > 0)
1212               xev = &last_event;
1213           } else if (type == ui::ET_MOUSE_PRESSED) {
1214             XIDeviceEvent* xievent =
1215                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1216             int button = xievent->detail;
1217             if (button == kBackMouseButton || button == kForwardMouseButton) {
1218               aura::client::UserActionClient* gesture_client =
1219                   aura::client::GetUserActionClient(
1220                       root_window_host_delegate_->AsRootWindow());
1221               if (gesture_client) {
1222                 bool reverse_direction =
1223                     ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
1224                 gesture_client->OnUserAction(
1225                     (button == kBackMouseButton && !reverse_direction) ||
1226                     (button == kForwardMouseButton && reverse_direction) ?
1227                     aura::client::UserActionClient::BACK :
1228                     aura::client::UserActionClient::FORWARD);
1229               }
1230               break;
1231             }
1232           } else if (type == ui::ET_MOUSE_RELEASED) {
1233             XIDeviceEvent* xievent =
1234                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
1235             int button = xievent->detail;
1236             if (button == kBackMouseButton || button == kForwardMouseButton) {
1237               // We've already passed the back/forward mouse down to the user
1238               // action client; we want to swallow the corresponding release.
1239               break;
1240             }
1241           }
1242           ui::MouseEvent mouseev(xev);
1243           DispatchMouseEvent(&mouseev);
1244           break;
1245         }
1246         case ui::ET_MOUSEWHEEL: {
1247           ui::MouseWheelEvent mouseev(xev);
1248           DispatchMouseEvent(&mouseev);
1249           break;
1250         }
1251         case ui::ET_SCROLL_FLING_START:
1252         case ui::ET_SCROLL_FLING_CANCEL:
1253         case ui::ET_SCROLL: {
1254           ui::ScrollEvent scrollev(xev);
1255           root_window_host_delegate_->OnHostScrollEvent(&scrollev);
1256           break;
1257         }
1258         case ui::ET_UNKNOWN:
1259           break;
1260         default:
1261           NOTREACHED();
1262       }
1263
1264       // If we coalesced an event we need to free its cookie.
1265       if (num_coalesced > 0)
1266         XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1267       break;
1268     }
1269     case MapNotify: {
1270       // If there's no window manager running, we need to assign the X input
1271       // focus to our host window.
1272       if (!IsWindowManagerPresent() && focus_when_shown_)
1273         XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
1274
1275       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
1276                         observer_list_,
1277                         OnWindowMapped(xwindow_));
1278       break;
1279     }
1280     case UnmapNotify: {
1281       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
1282                         observer_list_,
1283                         OnWindowUnmapped(xwindow_));
1284       break;
1285     }
1286     case ClientMessage: {
1287       Atom message_type = xev->xclient.message_type;
1288       if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1289         Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1290         if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1291           // We have received a close message from the window manager.
1292           root_window_->OnRootWindowHostCloseRequested();
1293         } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1294           XEvent reply_event = *xev;
1295           reply_event.xclient.window = x_root_window_;
1296
1297           XSendEvent(xdisplay_,
1298                      reply_event.xclient.window,
1299                      False,
1300                      SubstructureRedirectMask | SubstructureNotifyMask,
1301                      &reply_event);
1302         }
1303       } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1304         drag_drop_client_->OnXdndEnter(xev->xclient);
1305       } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1306         drag_drop_client_->OnXdndLeave(xev->xclient);
1307       } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1308         drag_drop_client_->OnXdndPosition(xev->xclient);
1309       } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1310         drag_drop_client_->OnXdndStatus(xev->xclient);
1311       } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1312         drag_drop_client_->OnXdndFinished(xev->xclient);
1313       } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1314         drag_drop_client_->OnXdndDrop(xev->xclient);
1315       }
1316       break;
1317     }
1318     case MappingNotify: {
1319       switch (xev->xmapping.request) {
1320         case MappingModifier:
1321         case MappingKeyboard:
1322           XRefreshKeyboardMapping(&xev->xmapping);
1323           root_window_->OnKeyboardMappingChanged();
1324           break;
1325         case MappingPointer:
1326           ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1327           break;
1328         default:
1329           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1330           break;
1331       }
1332       break;
1333     }
1334     case MotionNotify: {
1335       // Discard all but the most recent motion event that targets the same
1336       // window with unchanged state.
1337       XEvent last_event;
1338       while (XPending(xev->xany.display)) {
1339         XEvent next_event;
1340         XPeekEvent(xev->xany.display, &next_event);
1341         if (next_event.type == MotionNotify &&
1342             next_event.xmotion.window == xev->xmotion.window &&
1343             next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1344             next_event.xmotion.state == xev->xmotion.state) {
1345           XNextEvent(xev->xany.display, &last_event);
1346           xev = &last_event;
1347         } else {
1348           break;
1349         }
1350       }
1351
1352       ui::MouseEvent mouseev(xev);
1353       DispatchMouseEvent(&mouseev);
1354       break;
1355     }
1356     case PropertyNotify: {
1357       // Get our new window property state if the WM has told us its changed.
1358       ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
1359
1360       std::vector< ::Atom> atom_list;
1361       if (xev->xproperty.atom == state &&
1362           ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
1363         window_properties_.clear();
1364         std::copy(atom_list.begin(), atom_list.end(),
1365                   inserter(window_properties_, window_properties_.begin()));
1366
1367         if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
1368           // If we have restored bounds, but WM_STATE no longer claims to be
1369           // maximized, we should clear our restored bounds.
1370           restored_bounds_ = gfx::Rect();
1371         } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
1372           // The request that we become maximized originated from a different
1373           // process. |bounds_| already contains our maximized bounds. Do a
1374           // best effort attempt to get restored bounds by setting it to our
1375           // previously set bounds (and if we get this wrong, we aren't any
1376           // worse off since we'd otherwise be returning our maximized bounds).
1377           restored_bounds_ = previous_bounds_;
1378         }
1379
1380         is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
1381         is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1382
1383         // Now that we have different window properties, we may need to
1384         // relayout the window. (The windows code doesn't need this because
1385         // their window change is synchronous.)
1386         //
1387         // TODO(erg): While this does work, there's a quick flash showing the
1388         // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
1389         // those parts of the UI because we receive the sizing event from the
1390         // window manager before we receive the event that changes the
1391         // fullscreen state. Unsure what to do about that.
1392         Widget* widget = native_widget_delegate_->AsWidget();
1393         NonClientView* non_client_view = widget->non_client_view();
1394         // non_client_view may be NULL, especially during creation.
1395         if (non_client_view) {
1396           non_client_view->client_view()->InvalidateLayout();
1397           non_client_view->InvalidateLayout();
1398         }
1399         widget->GetRootView()->Layout();
1400       }
1401       break;
1402     }
1403     case SelectionNotify: {
1404       drag_drop_client_->OnSelectionNotify(xev->xselection);
1405       break;
1406     }
1407   }
1408   return true;
1409 }
1410
1411 ////////////////////////////////////////////////////////////////////////////////
1412 // DesktopRootWindowHost, public:
1413
1414 // static
1415 DesktopRootWindowHost* DesktopRootWindowHost::Create(
1416     internal::NativeWidgetDelegate* native_widget_delegate,
1417     DesktopNativeWidgetAura* desktop_native_widget_aura) {
1418   return new DesktopRootWindowHostX11(native_widget_delegate,
1419                                       desktop_native_widget_aura);
1420 }
1421
1422 // static
1423 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
1424   const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1425   if (linux_ui) {
1426     ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
1427     if (native_theme)
1428       return native_theme;
1429   }
1430
1431   return ui::NativeTheme::instance();
1432 }
1433
1434 }  // namespace views