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