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