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