Index: ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc |
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc |
deleted file mode 100644 |
index 0003030d8cca77141f6d305a0d95044d70b7fa45..0000000000000000000000000000000000000000 |
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc |
+++ /dev/null |
@@ -1,1627 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h" |
- |
-#include <X11/extensions/shape.h> |
-#include <X11/extensions/XInput2.h> |
-#include <X11/Xatom.h> |
-#include <X11/Xregion.h> |
-#include <X11/Xutil.h> |
- |
-#include "base/basictypes.h" |
-#include "base/debug/trace_event.h" |
-#include "base/message_loop/message_pump_x11.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "third_party/skia/include/core/SkPath.h" |
-#include "ui/aura/client/cursor_client.h" |
-#include "ui/aura/client/focus_client.h" |
-#include "ui/aura/client/user_action_client.h" |
-#include "ui/aura/root_window.h" |
-#include "ui/aura/window.h" |
-#include "ui/aura/window_property.h" |
-#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" |
-#include "ui/base/x/x11_util.h" |
-#include "ui/events/event_utils.h" |
-#include "ui/events/x/device_data_manager.h" |
-#include "ui/events/x/device_list_cache_x.h" |
-#include "ui/events/x/touch_factory_x11.h" |
-#include "ui/gfx/image/image_skia.h" |
-#include "ui/gfx/image/image_skia_rep.h" |
-#include "ui/gfx/insets.h" |
-#include "ui/gfx/path.h" |
-#include "ui/gfx/path_x11.h" |
-#include "ui/native_theme/native_theme.h" |
-#include "ui/views/corewm/compound_event_filter.h" |
-#include "ui/views/corewm/corewm_switches.h" |
-#include "ui/views/corewm/tooltip_aura.h" |
-#include "ui/views/corewm/window_util.h" |
-#include "ui/views/ime/input_method.h" |
-#include "ui/views/linux_ui/linux_ui.h" |
-#include "ui/views/views_delegate.h" |
-#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h" |
-#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" |
-#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" |
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" |
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h" |
-#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" |
-#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h" |
-#include "ui/views/widget/desktop_aura/x11_scoped_capture.h" |
-#include "ui/views/widget/desktop_aura/x11_window_event_filter.h" |
- |
-namespace views { |
- |
-DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture = |
- NULL; |
-std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL; |
- |
-DEFINE_WINDOW_PROPERTY_KEY( |
- aura::Window*, kViewsWindowForRootWindow, NULL); |
- |
-DEFINE_WINDOW_PROPERTY_KEY( |
- DesktopWindowTreeHostX11*, kHostForRootWindow, NULL); |
- |
-namespace { |
- |
-// Standard Linux mouse buttons for going back and forward. |
-const int kBackMouseButton = 8; |
-const int kForwardMouseButton = 9; |
- |
-// Constants that are part of EWMH. |
-const int k_NET_WM_STATE_ADD = 1; |
-const int k_NET_WM_STATE_REMOVE = 0; |
- |
-const char* kAtomsToCache[] = { |
- "UTF8_STRING", |
- "WM_DELETE_WINDOW", |
- "WM_PROTOCOLS", |
- "WM_S0", |
- "_NET_WM_ICON", |
- "_NET_WM_NAME", |
- "_NET_WM_PID", |
- "_NET_WM_PING", |
- "_NET_WM_STATE", |
- "_NET_WM_STATE_ABOVE", |
- "_NET_WM_STATE_FULLSCREEN", |
- "_NET_WM_STATE_HIDDEN", |
- "_NET_WM_STATE_MAXIMIZED_HORZ", |
- "_NET_WM_STATE_MAXIMIZED_VERT", |
- "_NET_WM_STATE_SKIP_TASKBAR", |
- "_NET_WM_WINDOW_OPACITY", |
- "_NET_WM_WINDOW_TYPE", |
- "_NET_WM_WINDOW_TYPE_DND", |
- "_NET_WM_WINDOW_TYPE_MENU", |
- "_NET_WM_WINDOW_TYPE_NORMAL", |
- "_NET_WM_WINDOW_TYPE_NOTIFICATION", |
- "_NET_WM_WINDOW_TYPE_TOOLTIP", |
- "XdndActionAsk", |
- "XdndActionCopy" |
- "XdndActionLink", |
- "XdndActionList", |
- "XdndActionMove", |
- "XdndActionPrivate", |
- "XdndAware", |
- "XdndDrop", |
- "XdndEnter", |
- "XdndFinished", |
- "XdndLeave", |
- "XdndPosition", |
- "XdndProxy", // Proxy windows? |
- "XdndSelection", |
- "XdndStatus", |
- "XdndTypeList", |
- NULL |
-}; |
- |
-} // namespace |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, public: |
- |
-DesktopWindowTreeHostX11::DesktopWindowTreeHostX11( |
- internal::NativeWidgetDelegate* native_widget_delegate, |
- DesktopNativeWidgetAura* desktop_native_widget_aura) |
- : close_widget_factory_(this), |
- xdisplay_(gfx::GetXDisplay()), |
- xwindow_(0), |
- x_root_window_(DefaultRootWindow(xdisplay_)), |
- atom_cache_(xdisplay_, kAtomsToCache), |
- window_mapped_(false), |
- is_fullscreen_(false), |
- is_always_on_top_(false), |
- use_native_frame_(false), |
- root_window_(NULL), |
- drag_drop_client_(NULL), |
- current_cursor_(ui::kCursorNull), |
- native_widget_delegate_(native_widget_delegate), |
- desktop_native_widget_aura_(desktop_native_widget_aura), |
- content_window_(NULL), |
- window_parent_(NULL), |
- custom_window_shape_(NULL) { |
-} |
- |
-DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { |
- root_window_->window()->ClearProperty(kHostForRootWindow); |
- aura::client::SetWindowMoveClient(root_window_->window(), NULL); |
- desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(root_window_); |
- if (custom_window_shape_) |
- XDestroyRegion(custom_window_shape_); |
-} |
- |
-// static |
-aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) { |
- aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid); |
- return root ? root->window()->GetProperty(kViewsWindowForRootWindow) : NULL; |
-} |
- |
-// static |
-DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) { |
- aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid); |
- return root ? root->window()->GetProperty(kHostForRootWindow) : NULL; |
-} |
- |
-// static |
-std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() { |
- std::vector<aura::Window*> windows(open_windows().size()); |
- std::transform(open_windows().begin(), |
- open_windows().end(), |
- windows.begin(), |
- GetContentWindowForXID); |
- return windows; |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const { |
- return bounds_; |
-} |
- |
-void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged( |
- bool active) { |
- if (active) { |
- delegate_->OnHostActivated(); |
- open_windows().remove(xwindow_); |
- open_windows().insert(open_windows().begin(), xwindow_); |
- } |
- |
- desktop_native_widget_aura_->HandleActivationChanged(active); |
- |
- native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint(); |
-} |
- |
-void DesktopWindowTreeHostX11::AddObserver( |
- views::DesktopWindowTreeHostObserverX11* observer) { |
- observer_list_.AddObserver(observer); |
-} |
- |
-void DesktopWindowTreeHostX11::RemoveObserver( |
- views::DesktopWindowTreeHostObserverX11* observer) { |
- observer_list_.RemoveObserver(observer); |
-} |
- |
-void DesktopWindowTreeHostX11::CleanUpWindowList() { |
- delete open_windows_; |
- open_windows_ = NULL; |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation: |
- |
-void DesktopWindowTreeHostX11::Init( |
- aura::Window* content_window, |
- const Widget::InitParams& params, |
- aura::RootWindow::CreateParams* rw_create_params) { |
- content_window_ = content_window; |
- |
- // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or |
- // whether we should be proxying requests to another DRWHL. |
- |
- // In some situations, views tries to make a zero sized window, and that |
- // makes us crash. Make sure we have valid sizes. |
- Widget::InitParams sanitized_params = params; |
- if (sanitized_params.bounds.width() == 0) |
- sanitized_params.bounds.set_width(100); |
- if (sanitized_params.bounds.height() == 0) |
- sanitized_params.bounds.set_height(100); |
- |
- InitX11Window(sanitized_params); |
- |
- rw_create_params->initial_bounds = bounds_; |
- rw_create_params->host = this; |
-} |
- |
-void DesktopWindowTreeHostX11::OnRootWindowCreated( |
- aura::RootWindow* root, |
- const Widget::InitParams& params) { |
- root_window_ = root; |
- |
- root_window_->window()->SetProperty(kViewsWindowForRootWindow, |
- content_window_); |
- root_window_->window()->SetProperty(kHostForRootWindow, this); |
- delegate_ = root_window_; |
- |
- // If we're given a parent, we need to mark ourselves as transient to another |
- // window. Otherwise activation gets screwy. |
- gfx::NativeView parent = params.parent; |
- if (!params.child && params.parent) { |
- corewm::AddTransientChild(parent, content_window_); |
- } |
- |
- // Ensure that the X11DesktopHandler exists so that it dispatches activation |
- // messages to us. |
- X11DesktopHandler::get(); |
- |
- // TODO(erg): Unify this code once the other consumer goes away. |
- x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_, this)); |
- SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW && |
- !params.remove_standard_frame); |
- desktop_native_widget_aura_->root_window_event_filter()->AddHandler( |
- x11_window_event_filter_.get()); |
- |
- x11_window_move_client_.reset(new X11DesktopWindowMoveClient); |
- aura::client::SetWindowMoveClient(root_window_->window(), |
- x11_window_move_client_.get()); |
- |
- native_widget_delegate_->OnNativeWidgetCreated(true); |
-} |
- |
-scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() { |
- return scoped_ptr<corewm::Tooltip>( |
- new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE)); |
-} |
- |
-scoped_ptr<aura::client::DragDropClient> |
-DesktopWindowTreeHostX11::CreateDragDropClient( |
- DesktopNativeCursorManager* cursor_manager) { |
- drag_drop_client_ = new DesktopDragDropClientAuraX11( |
- root_window_->window(), cursor_manager, xdisplay_, xwindow_); |
- return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass(); |
-} |
- |
-void DesktopWindowTreeHostX11::Close() { |
- // TODO(erg): Might need to do additional hiding tasks here. |
- |
- if (!close_widget_factory_.HasWeakPtrs()) { |
- // And we delay the close so that if we are called from an ATL callback, |
- // we don't destroy the window before the callback returned (as the caller |
- // may delete ourselves on destroy and the ATL callback would still |
- // dereference us when the callback returns). |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&DesktopWindowTreeHostX11::CloseNow, |
- close_widget_factory_.GetWeakPtr())); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::CloseNow() { |
- if (xwindow_ == None) |
- return; |
- |
- x11_capture_.reset(); |
- native_widget_delegate_->OnNativeWidgetDestroying(); |
- |
- // If we have children, close them. Use a copy for iteration because they'll |
- // remove themselves. |
- std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_; |
- for (std::set<DesktopWindowTreeHostX11*>::iterator it = |
- window_children_copy.begin(); it != window_children_copy.end(); |
- ++it) { |
- (*it)->CloseNow(); |
- } |
- DCHECK(window_children_.empty()); |
- |
- // If we have a parent, remove ourselves from its children list. |
- if (window_parent_) { |
- window_parent_->window_children_.erase(this); |
- window_parent_ = NULL; |
- } |
- |
- // Remove the event listeners we've installed. We need to remove these |
- // because otherwise we get assert during ~RootWindow(). |
- desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler( |
- x11_window_event_filter_.get()); |
- |
- // Destroy the compositor before destroying the |xwindow_| since shutdown |
- // may try to swap, and the swap without a window causes an X error, which |
- // causes a crash with in-process renderer. |
- DestroyCompositor(); |
- |
- open_windows().remove(xwindow_); |
- // Actually free our native resources. |
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_); |
- XDestroyWindow(xdisplay_, xwindow_); |
- xwindow_ = None; |
- |
- desktop_native_widget_aura_->OnHostClosed(); |
-} |
- |
-aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() { |
- return this; |
-} |
- |
-void DesktopWindowTreeHostX11::ShowWindowWithState( |
- ui::WindowShowState show_state) { |
- if (!window_mapped_) |
- MapWindow(show_state); |
- |
- if (show_state == ui::SHOW_STATE_NORMAL || |
- show_state == ui::SHOW_STATE_MAXIMIZED) { |
- Activate(); |
- } |
- |
- native_widget_delegate_->AsWidget()->SetInitialFocus(show_state); |
-} |
- |
-void DesktopWindowTreeHostX11::ShowMaximizedWithBounds( |
- const gfx::Rect& restored_bounds) { |
- restored_bounds_ = restored_bounds; |
- Maximize(); |
- Show(); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsVisible() const { |
- return window_mapped_; |
-} |
- |
-void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) { |
- bool size_changed = bounds_.size() != size; |
- XResizeWindow(xdisplay_, xwindow_, size.width(), size.height()); |
- bounds_.set_size(size); |
- if (size_changed) |
- NotifyHostResized(size); |
-} |
- |
-void DesktopWindowTreeHostX11::StackAtTop() { |
- XRaiseWindow(xdisplay_, xwindow_); |
-} |
- |
-void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) { |
- gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen(); |
- |
- // If |window_|'s transient parent bounds are big enough to contain |size|, |
- // use them instead. |
- if (corewm::GetTransientParent(content_window_)) { |
- gfx::Rect transient_parent_rect = |
- corewm::GetTransientParent(content_window_)->GetBoundsInScreen(); |
- if (transient_parent_rect.height() >= size.height() && |
- transient_parent_rect.width() >= size.width()) { |
- parent_bounds = transient_parent_rect; |
- } |
- } |
- |
- gfx::Rect window_bounds( |
- parent_bounds.x() + (parent_bounds.width() - size.width()) / 2, |
- parent_bounds.y() + (parent_bounds.height() - size.height()) / 2, |
- size.width(), |
- size.height()); |
- // Don't size the window bigger than the parent, otherwise the user may not be |
- // able to close or move it. |
- window_bounds.AdjustToFit(parent_bounds); |
- |
- SetBounds(window_bounds); |
-} |
- |
-void DesktopWindowTreeHostX11::GetWindowPlacement( |
- gfx::Rect* bounds, |
- ui::WindowShowState* show_state) const { |
- *bounds = bounds_; |
- |
- if (IsFullscreen()) { |
- *show_state = ui::SHOW_STATE_FULLSCREEN; |
- } else if (IsMinimized()) { |
- *show_state = ui::SHOW_STATE_MINIMIZED; |
- } else if (IsMaximized()) { |
- *show_state = ui::SHOW_STATE_MAXIMIZED; |
- } else if (!IsActive()) { |
- *show_state = ui::SHOW_STATE_INACTIVE; |
- } else { |
- *show_state = ui::SHOW_STATE_NORMAL; |
- } |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const { |
- return bounds_; |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const { |
- // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its |
- // needed for View::ConvertPointToScreen() to work |
- // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just |
- // asks windows what it thinks the client rect is. |
- // |
- // Attempts to calculate the rect by asking the NonClientFrameView what it |
- // thought its GetBoundsForClientView() were broke combobox drop down |
- // placement. |
- return bounds_; |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const { |
- // We can't reliably track the restored bounds of a window, but we can get |
- // the 90% case down. When *chrome* is the process that requests maximizing |
- // or restoring bounds, we can record the current bounds before we request |
- // maximization, and clear it when we detect a state change. |
- if (!restored_bounds_.IsEmpty()) |
- return restored_bounds_; |
- |
- return GetWindowBoundsInScreen(); |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const { |
- std::vector<int> value; |
- if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) && |
- value.size() >= 4) { |
- return gfx::Rect(value[0], value[1], value[2], value[3]); |
- } |
- |
- // Fetch the geometry of the root window. |
- Window root; |
- int x, y; |
- unsigned int width, height; |
- unsigned int border_width, depth; |
- if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, |
- &width, &height, &border_width, &depth)) { |
- NOTIMPLEMENTED(); |
- return gfx::Rect(0, 0, 10, 10); |
- } |
- |
- return gfx::Rect(x, y, width, height); |
-} |
- |
-void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) { |
- if (custom_window_shape_) |
- XDestroyRegion(custom_window_shape_); |
- custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region); |
- ResetWindowRegion(); |
- delete native_region; |
-} |
- |
-void DesktopWindowTreeHostX11::Activate() { |
- if (!window_mapped_) |
- return; |
- |
- X11DesktopHandler::get()->ActivateWindow(xwindow_); |
-} |
- |
-void DesktopWindowTreeHostX11::Deactivate() { |
- if (!IsActive()) |
- return; |
- |
- x11_capture_.reset(); |
- X11DesktopHandler::get()->DeactivateWindow(xwindow_); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsActive() const { |
- return X11DesktopHandler::get()->IsActiveWindow(xwindow_); |
-} |
- |
-void DesktopWindowTreeHostX11::Maximize() { |
- // When we're the process requesting the maximizing, we can accurately keep |
- // track of our restored bounds instead of relying on the heuristics that are |
- // in the PropertyNotify and ConfigureNotify handlers. |
- restored_bounds_ = bounds_; |
- |
- SetWMSpecState(true, |
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), |
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); |
-} |
- |
-void DesktopWindowTreeHostX11::Minimize() { |
- x11_capture_.reset(); |
- XIconifyWindow(xdisplay_, xwindow_, 0); |
-} |
- |
-void DesktopWindowTreeHostX11::Restore() { |
- SetWMSpecState(false, |
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), |
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsMaximized() const { |
- return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") && |
- HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ")); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsMinimized() const { |
- return HasWMSpecProperty("_NET_WM_STATE_HIDDEN"); |
-} |
- |
- |
-bool DesktopWindowTreeHostX11::HasCapture() const { |
- return g_current_capture == this; |
-} |
- |
-void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) { |
- is_always_on_top_ = always_on_top; |
- SetWMSpecState(always_on_top, |
- atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"), |
- None); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const { |
- return is_always_on_top_; |
-} |
- |
-bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) { |
- if (window_title_ == title) |
- return false; |
- window_title_ = title; |
- std::string utf8str = base::UTF16ToUTF8(title); |
- XChangeProperty(xdisplay_, |
- xwindow_, |
- atom_cache_.GetAtom("_NET_WM_NAME"), |
- atom_cache_.GetAtom("UTF8_STRING"), |
- 8, |
- PropModeReplace, |
- reinterpret_cast<const unsigned char*>(utf8str.c_str()), |
- utf8str.size()); |
- // TODO(erg): This is technically wrong. So XStoreName and friends expect |
- // this in Host Portable Character Encoding instead of UTF-8, which I believe |
- // is Compound Text. This shouldn't matter 90% of the time since this is the |
- // fallback to the UTF8 property above. |
- XStoreName(xdisplay_, xwindow_, utf8str.c_str()); |
- return true; |
-} |
- |
-void DesktopWindowTreeHostX11::ClearNativeFocus() { |
- // This method is weird and misnamed. Instead of clearing the native focus, |
- // it sets the focus to our |content_window_|, which will trigger a cascade |
- // of focus changes into views. |
- if (content_window_ && aura::client::GetFocusClient(content_window_) && |
- content_window_->Contains( |
- aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) { |
- aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_); |
- } |
-} |
- |
-Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop( |
- const gfx::Vector2d& drag_offset, |
- Widget::MoveLoopSource source, |
- Widget::MoveLoopEscapeBehavior escape_behavior) { |
- aura::client::WindowMoveSource window_move_source = |
- source == Widget::MOVE_LOOP_SOURCE_MOUSE ? |
- aura::client::WINDOW_MOVE_SOURCE_MOUSE : |
- aura::client::WINDOW_MOVE_SOURCE_TOUCH; |
- if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset, |
- window_move_source) == aura::client::MOVE_SUCCESSFUL) |
- return Widget::MOVE_LOOP_SUCCESSFUL; |
- |
- return Widget::MOVE_LOOP_CANCELED; |
-} |
- |
-void DesktopWindowTreeHostX11::EndMoveLoop() { |
- x11_window_move_client_->EndMoveLoop(); |
-} |
- |
-void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled( |
- bool value) { |
- // Much like the previous NativeWidgetGtk, we don't have anything to do here. |
-} |
- |
-bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const { |
- return use_native_frame_; |
-} |
- |
-bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const { |
- return false; |
-} |
- |
-void DesktopWindowTreeHostX11::FrameTypeChanged() { |
- Widget::FrameType new_type = |
- native_widget_delegate_->AsWidget()->frame_type(); |
- SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE); |
- // Replace the frame and layout the contents. Even though we don't have a |
- // swapable glass frame like on Windows, we still replace the frame because |
- // the button assets don't update otherwise. |
- native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(); |
-} |
- |
-NonClientFrameView* DesktopWindowTreeHostX11::CreateNonClientFrameView() { |
- return NULL; |
-} |
- |
-void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) { |
- is_fullscreen_ = fullscreen; |
- SetWMSpecState(fullscreen, |
- atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"), |
- None); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsFullscreen() const { |
- return is_fullscreen_; |
-} |
- |
-void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) { |
- // X server opacity is in terms of 32 bit unsigned int space, and counts from |
- // the opposite direction. |
- // XChangeProperty() expects "cardinality" to be long. |
- unsigned long cardinality = opacity * 0x1010101; |
- |
- if (cardinality == 0xffffffff) { |
- XDeleteProperty(xdisplay_, xwindow_, |
- atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY")); |
- } else { |
- XChangeProperty(xdisplay_, xwindow_, |
- atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"), |
- XA_CARDINAL, 32, |
- PropModeReplace, |
- reinterpret_cast<unsigned char*>(&cardinality), 1); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::SetWindowIcons( |
- const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { |
- // TODO(erg): The way we handle icons across different versions of chrome |
- // could be substantially improved. The Windows version does its own thing |
- // and only sometimes comes down this code path. The icon stuff in |
- // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard |
- // coded to be given two images instead of an arbitrary collection of images |
- // so that we can pass to the WM. |
- // |
- // All of this could be made much, much better. |
- std::vector<unsigned long> data; |
- |
- if (window_icon.HasRepresentation(1.0f)) |
- SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data); |
- |
- if (app_icon.HasRepresentation(1.0f)) |
- SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data); |
- |
- if (data.empty()) |
- XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON")); |
- else |
- ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data); |
-} |
- |
-void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) { |
- switch (modal_type) { |
- case ui::MODAL_TYPE_NONE: |
- break; |
- default: |
- // TODO(erg): Figure out under what situations |modal_type| isn't |
- // none. The comment in desktop_native_widget_aura.cc suggests that this |
- // is rare. |
- NOTIMPLEMENTED(); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
-} |
- |
-void DesktopWindowTreeHostX11::OnRootViewLayout() const { |
- if (!window_mapped_) |
- return; |
- |
- XSizeHints hints; |
- long supplied_return; |
- XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return); |
- |
- gfx::Size minimum = native_widget_delegate_->GetMinimumSize(); |
- if (minimum.IsEmpty()) { |
- hints.flags &= ~PMinSize; |
- } else { |
- hints.flags |= PMinSize; |
- hints.min_width = minimum.width(); |
- hints.min_height = minimum.height(); |
- } |
- |
- gfx::Size maximum = native_widget_delegate_->GetMaximumSize(); |
- if (maximum.IsEmpty()) { |
- hints.flags &= ~PMaxSize; |
- } else { |
- hints.flags |= PMaxSize; |
- hints.max_width = maximum.width(); |
- hints.max_height = maximum.height(); |
- } |
- |
- XSetWMNormalHints(xdisplay_, xwindow_, &hints); |
-} |
- |
-void DesktopWindowTreeHostX11::OnNativeWidgetFocus() { |
- native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus(); |
-} |
- |
-void DesktopWindowTreeHostX11::OnNativeWidgetBlur() { |
- if (xwindow_) { |
- x11_capture_.reset(); |
- native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur(); |
- } |
-} |
- |
-bool DesktopWindowTreeHostX11::IsAnimatingClosed() const { |
- return false; |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, aura::WindowTreeHost implementation: |
- |
-aura::RootWindow* DesktopWindowTreeHostX11::GetRootWindow() { |
- return root_window_; |
-} |
- |
-gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() { |
- return xwindow_; |
-} |
- |
-void DesktopWindowTreeHostX11::Show() { |
- ShowWindowWithState(ui::SHOW_STATE_NORMAL); |
-} |
- |
-void DesktopWindowTreeHostX11::Hide() { |
- if (window_mapped_) { |
- XWithdrawWindow(xdisplay_, xwindow_, 0); |
- window_mapped_ = false; |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::ToggleFullScreen() { |
- NOTIMPLEMENTED(); |
-} |
- |
-gfx::Rect DesktopWindowTreeHostX11::GetBounds() const { |
- return bounds_; |
-} |
- |
-void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) { |
- bool origin_changed = bounds_.origin() != bounds.origin(); |
- bool size_changed = bounds_.size() != bounds.size(); |
- XWindowChanges changes = {0}; |
- unsigned value_mask = 0; |
- |
- if (size_changed) { |
- // X11 will send an XError at our process if have a 0 sized window. |
- DCHECK_GT(bounds.width(), 0); |
- DCHECK_GT(bounds.height(), 0); |
- |
- changes.width = bounds.width(); |
- changes.height = bounds.height(); |
- value_mask |= CWHeight | CWWidth; |
- } |
- |
- if (origin_changed) { |
- changes.x = bounds.x(); |
- changes.y = bounds.y(); |
- value_mask |= CWX | CWY; |
- } |
- if (value_mask) |
- XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); |
- |
- // Assume that the resize will go through as requested, which should be the |
- // case if we're running without a window manager. If there's a window |
- // manager, it can modify or ignore the request, but (per ICCCM) we'll get a |
- // (possibly synthetic) ConfigureNotify about the actual size and correct |
- // |bounds_| later. |
- bounds_ = bounds; |
- |
- if (origin_changed) |
- native_widget_delegate_->AsWidget()->OnNativeWidgetMove(); |
- if (size_changed) |
- NotifyHostResized(bounds.size()); |
- else |
- compositor()->ScheduleRedrawRect(gfx::Rect(bounds.size())); |
-} |
- |
-gfx::Insets DesktopWindowTreeHostX11::GetInsets() const { |
- return gfx::Insets(); |
-} |
- |
-void DesktopWindowTreeHostX11::SetInsets(const gfx::Insets& insets) { |
-} |
- |
-gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const { |
- return bounds_.origin(); |
-} |
- |
-void DesktopWindowTreeHostX11::SetCapture() { |
- // This is vaguely based on the old NativeWidgetGtk implementation. |
- // |
- // X11's XPointerGrab() shouldn't be used for everything; it doesn't map |
- // cleanly to Windows' SetCapture(). GTK only provides a separate concept of |
- // a grab that wasn't the X11 pointer grab, but was instead a manual |
- // redirection of the event. (You need to drop into GDK if you want to |
- // perform a raw X11 grab). |
- |
- if (g_current_capture) |
- g_current_capture->OnCaptureReleased(); |
- |
- g_current_capture = this; |
- x11_capture_.reset(new X11ScopedCapture(xwindow_)); |
-} |
- |
-void DesktopWindowTreeHostX11::ReleaseCapture() { |
- if (g_current_capture == this) |
- g_current_capture->OnCaptureReleased(); |
-} |
- |
-void DesktopWindowTreeHostX11::SetCursor(gfx::NativeCursor cursor) { |
- XDefineCursor(xdisplay_, xwindow_, cursor.platform()); |
-} |
- |
-bool DesktopWindowTreeHostX11::QueryMouseLocation( |
- gfx::Point* location_return) { |
- aura::client::CursorClient* cursor_client = |
- aura::client::GetCursorClient(GetRootWindow()->window()); |
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { |
- *location_return = gfx::Point(0, 0); |
- return false; |
- } |
- |
- ::Window root_return, child_return; |
- int root_x_return, root_y_return, win_x_return, win_y_return; |
- unsigned int mask_return; |
- XQueryPointer(xdisplay_, |
- xwindow_, |
- &root_return, |
- &child_return, |
- &root_x_return, &root_y_return, |
- &win_x_return, &win_y_return, |
- &mask_return); |
- *location_return = gfx::Point( |
- std::max(0, std::min(bounds_.width(), win_x_return)), |
- std::max(0, std::min(bounds_.height(), win_y_return))); |
- return (win_x_return >= 0 && win_x_return < bounds_.width() && |
- win_y_return >= 0 && win_y_return < bounds_.height()); |
-} |
- |
-bool DesktopWindowTreeHostX11::ConfineCursorToRootWindow() { |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-void DesktopWindowTreeHostX11::UnConfineCursor() { |
- NOTIMPLEMENTED(); |
-} |
- |
-void DesktopWindowTreeHostX11::OnCursorVisibilityChanged(bool show) { |
- // TODO(erg): Conditional on us enabling touch on desktop linux builds, do |
- // the same tap-to-click disabling here that chromeos does. |
-} |
- |
-void DesktopWindowTreeHostX11::MoveCursorTo(const gfx::Point& location) { |
- XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, |
- bounds_.x() + location.x(), bounds_.y() + location.y()); |
-} |
- |
-void DesktopWindowTreeHostX11::PostNativeEvent( |
- const base::NativeEvent& native_event) { |
- DCHECK(xwindow_); |
- DCHECK(xdisplay_); |
- XEvent xevent = *native_event; |
- xevent.xany.display = xdisplay_; |
- xevent.xany.window = xwindow_; |
- |
- switch (xevent.type) { |
- case EnterNotify: |
- case LeaveNotify: |
- case MotionNotify: |
- case KeyPress: |
- case KeyRelease: |
- case ButtonPress: |
- case ButtonRelease: { |
- // The fields used below are in the same place for all of events |
- // above. Using xmotion from XEvent's unions to avoid repeating |
- // the code. |
- xevent.xmotion.root = x_root_window_; |
- xevent.xmotion.time = CurrentTime; |
- |
- gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); |
- ConvertPointToNativeScreen(&point); |
- xevent.xmotion.x_root = point.x(); |
- xevent.xmotion.y_root = point.y(); |
- } |
- default: |
- break; |
- } |
- XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); |
-} |
- |
-void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged( |
- float device_scale_factor) { |
-} |
- |
-void DesktopWindowTreeHostX11::PrepareForShutdown() { |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, ui::EventSource implementation: |
- |
-ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() { |
- return delegate_->GetEventProcessor(); |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, private: |
- |
-void DesktopWindowTreeHostX11::InitX11Window( |
- const Widget::InitParams& params) { |
- unsigned long attribute_mask = CWBackPixmap; |
- XSetWindowAttributes swa; |
- memset(&swa, 0, sizeof(swa)); |
- swa.background_pixmap = None; |
- |
- ::Atom window_type; |
- switch (params.type) { |
- case Widget::InitParams::TYPE_MENU: |
- swa.override_redirect = True; |
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU"); |
- break; |
- case Widget::InitParams::TYPE_TOOLTIP: |
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP"); |
- break; |
- case Widget::InitParams::TYPE_POPUP: |
- swa.override_redirect = True; |
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION"); |
- break; |
- case Widget::InitParams::TYPE_DRAG: |
- swa.override_redirect = True; |
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND"); |
- break; |
- default: |
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL"); |
- break; |
- } |
- if (swa.override_redirect) |
- attribute_mask |= CWOverrideRedirect; |
- |
- bounds_ = params.bounds; |
- xwindow_ = XCreateWindow( |
- xdisplay_, x_root_window_, |
- bounds_.x(), bounds_.y(), |
- bounds_.width(), bounds_.height(), |
- 0, // border width |
- CopyFromParent, // depth |
- InputOutput, |
- CopyFromParent, // visual |
- attribute_mask, |
- &swa); |
- base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_); |
- open_windows().push_back(xwindow_); |
- |
- // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL(). |
- |
- long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | |
- KeyPressMask | KeyReleaseMask | |
- EnterWindowMask | LeaveWindowMask | |
- ExposureMask | VisibilityChangeMask | |
- StructureNotifyMask | PropertyChangeMask | |
- PointerMotionMask; |
- XSelectInput(xdisplay_, xwindow_, event_mask); |
- XFlush(xdisplay_); |
- |
- if (ui::IsXInput2Available()) |
- ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); |
- |
- // TODO(erg): We currently only request window deletion events. We also |
- // should listen for activation events and anything else that GTK+ listens |
- // for, and do something useful. |
- ::Atom protocols[2]; |
- protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); |
- protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); |
- XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); |
- |
- // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with |
- // the desktop environment. |
- XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); |
- |
- // Likewise, the X server needs to know this window's pid so it knows which |
- // program to kill if the window hangs. |
- // XChangeProperty() expects "pid" to be long. |
- COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long); |
- long pid = getpid(); |
- XChangeProperty(xdisplay_, |
- xwindow_, |
- atom_cache_.GetAtom("_NET_WM_PID"), |
- XA_CARDINAL, |
- 32, |
- PropModeReplace, |
- reinterpret_cast<unsigned char*>(&pid), 1); |
- |
- XChangeProperty(xdisplay_, |
- xwindow_, |
- atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"), |
- XA_ATOM, |
- 32, |
- PropModeReplace, |
- reinterpret_cast<unsigned char*>(&window_type), 1); |
- |
- // List of window state properties (_NET_WM_STATE) to set, if any. |
- std::vector< ::Atom> state_atom_list; |
- |
- // Remove popup windows from taskbar unless overridden. |
- if ((params.type == Widget::InitParams::TYPE_POPUP || |
- params.type == Widget::InitParams::TYPE_BUBBLE) && |
- !params.force_show_in_taskbar) { |
- state_atom_list.push_back( |
- atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); |
- } |
- |
- // If the window should stay on top of other windows, add the |
- // _NET_WM_STATE_ABOVE property. |
- is_always_on_top_ = params.keep_on_top; |
- if (is_always_on_top_) |
- state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE")); |
- |
- // Setting _NET_WM_STATE by sending a message to the root_window (with |
- // SetWMSpecState) has no effect here since the window has not yet been |
- // mapped. So we manually change the state. |
- if (!state_atom_list.empty()) { |
- ui::SetAtomArrayProperty(xwindow_, |
- "_NET_WM_STATE", |
- "ATOM", |
- state_atom_list); |
- } |
- |
- if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) { |
- ui::SetWindowClassHint( |
- xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class); |
- } |
- if (!params.wm_role_name.empty() || |
- params.type == Widget::InitParams::TYPE_POPUP) { |
- const char kX11WindowRolePopup[] = "popup"; |
- ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ? |
- std::string(kX11WindowRolePopup) : params.wm_role_name); |
- } |
- |
- // If we have a parent, record the parent/child relationship. We use this |
- // data during destruction to make sure that when we try to close a parent |
- // window, we also destroy all child windows. |
- if (params.parent && params.parent->GetDispatcher()) { |
- XID parent_xid = |
- params.parent->GetDispatcher()->host()->GetAcceleratedWidget(); |
- window_parent_ = GetHostForXID(parent_xid); |
- DCHECK(window_parent_); |
- window_parent_->window_children_.insert(this); |
- } |
- |
- // If we have a delegate which is providing a default window icon, use that |
- // icon. |
- gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ? |
- ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL; |
- if (window_icon) { |
- SetWindowIcons(gfx::ImageSkia(), *window_icon); |
- } |
- CreateCompositor(GetAcceleratedWidget()); |
-} |
- |
-bool DesktopWindowTreeHostX11::IsWindowManagerPresent() { |
- // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
- // of WM_Sn selections (where n is a screen number). |
- return XGetSelectionOwner( |
- xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; |
-} |
- |
-void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled, |
- ::Atom state1, |
- ::Atom state2) { |
- XEvent xclient; |
- memset(&xclient, 0, sizeof(xclient)); |
- xclient.type = ClientMessage; |
- xclient.xclient.window = xwindow_; |
- xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE"); |
- xclient.xclient.format = 32; |
- xclient.xclient.data.l[0] = |
- enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE; |
- xclient.xclient.data.l[1] = state1; |
- xclient.xclient.data.l[2] = state2; |
- xclient.xclient.data.l[3] = 1; |
- xclient.xclient.data.l[4] = 0; |
- |
- XSendEvent(xdisplay_, x_root_window_, False, |
- SubstructureRedirectMask | SubstructureNotifyMask, |
- &xclient); |
-} |
- |
-bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const { |
- return window_properties_.find(atom_cache_.GetAtom(property)) != |
- window_properties_.end(); |
-} |
- |
-void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) { |
- use_native_frame_ = use_native_frame; |
- x11_window_event_filter_->SetUseHostWindowBorders(use_native_frame); |
-} |
- |
-void DesktopWindowTreeHostX11::OnCaptureReleased() { |
- x11_capture_.reset(); |
- g_current_capture = NULL; |
- delegate_->OnHostLostWindowCapture(); |
- native_widget_delegate_->OnMouseCaptureLost(); |
-} |
- |
-void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { |
- if (!g_current_capture || g_current_capture == this) { |
- SendEventToProcessor(event); |
- } else { |
- // Another DesktopWindowTreeHostX11 has installed itself as |
- // capture. Translate the event's location and dispatch to the other. |
- event->ConvertLocationToTarget(root_window_->window(), |
- g_current_capture->root_window_->window()); |
- g_current_capture->SendEventToProcessor(event); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) { |
- if (g_current_capture && g_current_capture != this && |
- event->type() == ui::ET_TOUCH_PRESSED) { |
- event->ConvertLocationToTarget(root_window_->window(), |
- g_current_capture->root_window_->window()); |
- g_current_capture->SendEventToProcessor(event); |
- } else { |
- SendEventToProcessor(event); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::ResetWindowRegion() { |
- // If a custom window shape was supplied then apply it. |
- if (custom_window_shape_) { |
- XShapeCombineRegion( |
- xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false); |
- return; |
- } |
- |
- if (!IsMaximized()) { |
- gfx::Path window_mask; |
- views::Widget* widget = native_widget_delegate_->AsWidget(); |
- if (widget->non_client_view()) { |
- // Some frame views define a custom (non-rectangular) window mask. If |
- // so, use it to define the window shape. If not, fall through. |
- widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask); |
- if (window_mask.countPoints() > 0) { |
- Region region = gfx::CreateRegionFromSkPath(window_mask); |
- XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, |
- 0, 0, region, false); |
- XDestroyRegion(region); |
- return; |
- } |
- } |
- } |
- |
- // If we didn't set the shape for any reason, reset the shaping information. |
- // How this is done depends on the border style, due to quirks and bugs in |
- // various window managers. |
- if (ShouldUseNativeFrame()) { |
- // If the window has system borders, the mask must be set to null (not a |
- // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will |
- // not put borders on a window with a custom shape. |
- XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet); |
- } else { |
- // Conversely, if the window does not have system borders, the mask must be |
- // manually set to a rectangle that covers the whole window (not null). This |
- // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null |
- // shape causes the hint to disable system borders to be ignored (resulting |
- // in a double border). |
- XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()), |
- static_cast<unsigned short>(bounds_.height())}; |
- XShapeCombineRectangles( |
- xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded); |
- } |
-} |
- |
-void DesktopWindowTreeHostX11::SerializeImageRepresentation( |
- const gfx::ImageSkiaRep& rep, |
- std::vector<unsigned long>* data) { |
- int width = rep.GetWidth(); |
- data->push_back(width); |
- |
- int height = rep.GetHeight(); |
- data->push_back(height); |
- |
- const SkBitmap& bitmap = rep.sk_bitmap(); |
- SkAutoLockPixels locker(bitmap); |
- |
- for (int y = 0; y < height; ++y) |
- for (int x = 0; x < width; ++x) |
- data->push_back(bitmap.getColor(x, y)); |
-} |
- |
-std::list<XID>& DesktopWindowTreeHostX11::open_windows() { |
- if (!open_windows_) |
- open_windows_ = new std::list<XID>(); |
- return *open_windows_; |
-} |
- |
-void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) { |
- if (show_state != ui::SHOW_STATE_DEFAULT && |
- show_state != ui::SHOW_STATE_NORMAL && |
- show_state != ui::SHOW_STATE_INACTIVE) { |
- // It will behave like SHOW_STATE_NORMAL. |
- NOTIMPLEMENTED(); |
- } |
- |
- // Before we map the window, set size hints. Otherwise, some window managers |
- // will ignore toplevel XMoveWindow commands. |
- XSizeHints size_hints; |
- size_hints.flags = PPosition; |
- size_hints.x = bounds_.x(); |
- size_hints.y = bounds_.y(); |
- XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); |
- |
- XWMHints wm_hints; |
- wm_hints.flags = InputHint | StateHint; |
- // If SHOW_STATE_INACTIVE, tell the window manager that the window is not |
- // focusable. This will make the window inactive upon creation. |
- wm_hints.input = show_state != ui::SHOW_STATE_INACTIVE; |
- wm_hints.initial_state = NormalState; |
- XSetWMHints(xdisplay_, xwindow_, &wm_hints); |
- |
- XMapWindow(xdisplay_, xwindow_); |
- |
- // We now block until our window is mapped. Some X11 APIs will crash and |
- // burn if passed |xwindow_| before the window is mapped, and XMapWindow is |
- // asynchronous. |
- base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_); |
- window_mapped_ = true; |
- |
- // The window has been created and mapped. It should now accept input. |
- if (show_state == ui::SHOW_STATE_INACTIVE) { |
- XWMHints wm_hints; |
- wm_hints.flags = InputHint; |
- wm_hints.input = true; |
- // Tell the window manager that the window is now focusable. |
- XSetWMHints(xdisplay_, xwindow_, &wm_hints); |
- } |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHostX11, MessagePumpDispatcher implementation: |
- |
-uint32_t DesktopWindowTreeHostX11::Dispatch(const base::NativeEvent& event) { |
- XEvent* xev = event; |
- |
- TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch", |
- "event->type", event->type); |
- |
- // May want to factor CheckXEventForConsistency(xev); into a common location |
- // since it is called here. |
- switch (xev->type) { |
- case EnterNotify: |
- case LeaveNotify: { |
- if (!g_current_capture) |
- X11DesktopHandler::get()->ProcessXEvent(xev); |
- ui::MouseEvent mouse_event(xev); |
- DispatchMouseEvent(&mouse_event); |
- break; |
- } |
- case Expose: { |
- gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, |
- xev->xexpose.width, xev->xexpose.height); |
- compositor()->ScheduleRedrawRect(damage_rect); |
- break; |
- } |
- case KeyPress: { |
- ui::KeyEvent keydown_event(xev, false); |
- SendEventToProcessor(&keydown_event); |
- break; |
- } |
- case KeyRelease: { |
- ui::KeyEvent keyup_event(xev, false); |
- SendEventToProcessor(&keyup_event); |
- break; |
- } |
- case ButtonPress: { |
- if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || |
- static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { |
- aura::client::UserActionClient* gesture_client = |
- aura::client::GetUserActionClient(root_window_->window()); |
- if (gesture_client) { |
- gesture_client->OnUserAction( |
- static_cast<int>(xev->xbutton.button) == kBackMouseButton ? |
- aura::client::UserActionClient::BACK : |
- aura::client::UserActionClient::FORWARD); |
- } |
- break; |
- } |
- } // fallthrough |
- case ButtonRelease: { |
- ui::EventType event_type = ui::EventTypeFromNative(xev); |
- switch (event_type) { |
- case ui::ET_MOUSEWHEEL: { |
- ui::MouseWheelEvent mouseev(xev); |
- DispatchMouseEvent(&mouseev); |
- break; |
- } |
- case ui::ET_MOUSE_PRESSED: |
- case ui::ET_MOUSE_RELEASED: { |
- ui::MouseEvent mouseev(xev); |
- DispatchMouseEvent(&mouseev); |
- break; |
- } |
- case ui::ET_UNKNOWN: |
- // No event is created for X11-release events for mouse-wheel buttons. |
- break; |
- default: |
- NOTREACHED() << event_type; |
- } |
- break; |
- } |
- case FocusOut: |
- if (xev->xfocus.mode != NotifyGrab) { |
- ReleaseCapture(); |
- delegate_->OnHostLostWindowCapture(); |
- } else { |
- delegate_->OnHostLostMouseGrab(); |
- } |
- break; |
- case FocusIn: |
- X11DesktopHandler::get()->ProcessXEvent(xev); |
- break; |
- case ConfigureNotify: { |
- DCHECK_EQ(xwindow_, xev->xconfigure.window); |
- DCHECK_EQ(xwindow_, xev->xconfigure.event); |
- // It's possible that the X window may be resized by some other means than |
- // from within aura (e.g. the X window manager can change the size). Make |
- // sure the root window size is maintained properly. |
- int translated_x = xev->xconfigure.x; |
- int translated_y = xev->xconfigure.y; |
- if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) { |
- Window unused; |
- XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, |
- 0, 0, &translated_x, &translated_y, &unused); |
- } |
- gfx::Rect bounds(translated_x, translated_y, |
- xev->xconfigure.width, xev->xconfigure.height); |
- bool size_changed = bounds_.size() != bounds.size(); |
- bool origin_changed = bounds_.origin() != bounds.origin(); |
- previous_bounds_ = bounds_; |
- bounds_ = bounds; |
- if (size_changed) |
- NotifyHostResized(bounds.size()); |
- if (origin_changed) |
- delegate_->OnHostMoved(bounds_.origin()); |
- ResetWindowRegion(); |
- break; |
- } |
- case GenericEvent: { |
- ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
- if (!factory->ShouldProcessXI2Event(xev)) |
- break; |
- |
- ui::EventType type = ui::EventTypeFromNative(xev); |
- XEvent last_event; |
- int num_coalesced = 0; |
- |
- switch (type) { |
- case ui::ET_TOUCH_MOVED: |
- num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
- if (num_coalesced > 0) |
- xev = &last_event; |
- // fallthrough |
- case ui::ET_TOUCH_PRESSED: |
- case ui::ET_TOUCH_RELEASED: { |
- ui::TouchEvent touchev(xev); |
- DispatchTouchEvent(&touchev); |
- break; |
- } |
- case ui::ET_MOUSE_MOVED: |
- case ui::ET_MOUSE_DRAGGED: |
- case ui::ET_MOUSE_PRESSED: |
- case ui::ET_MOUSE_RELEASED: |
- case ui::ET_MOUSE_ENTERED: |
- case ui::ET_MOUSE_EXITED: { |
- if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
- // If this is a motion event, we want to coalesce all pending motion |
- // events that are at the top of the queue. |
- num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); |
- if (num_coalesced > 0) |
- xev = &last_event; |
- } else if (type == ui::ET_MOUSE_PRESSED) { |
- XIDeviceEvent* xievent = |
- static_cast<XIDeviceEvent*>(xev->xcookie.data); |
- int button = xievent->detail; |
- if (button == kBackMouseButton || button == kForwardMouseButton) { |
- aura::client::UserActionClient* gesture_client = |
- aura::client::GetUserActionClient( |
- delegate_->AsRootWindow()->window()); |
- if (gesture_client) { |
- bool reverse_direction = |
- ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
- gesture_client->OnUserAction( |
- (button == kBackMouseButton && !reverse_direction) || |
- (button == kForwardMouseButton && reverse_direction) ? |
- aura::client::UserActionClient::BACK : |
- aura::client::UserActionClient::FORWARD); |
- } |
- break; |
- } |
- } else if (type == ui::ET_MOUSE_RELEASED) { |
- XIDeviceEvent* xievent = |
- static_cast<XIDeviceEvent*>(xev->xcookie.data); |
- int button = xievent->detail; |
- if (button == kBackMouseButton || button == kForwardMouseButton) { |
- // We've already passed the back/forward mouse down to the user |
- // action client; we want to swallow the corresponding release. |
- break; |
- } |
- } |
- ui::MouseEvent mouseev(xev); |
- DispatchMouseEvent(&mouseev); |
- break; |
- } |
- case ui::ET_MOUSEWHEEL: { |
- ui::MouseWheelEvent mouseev(xev); |
- DispatchMouseEvent(&mouseev); |
- break; |
- } |
- case ui::ET_SCROLL_FLING_START: |
- case ui::ET_SCROLL_FLING_CANCEL: |
- case ui::ET_SCROLL: { |
- ui::ScrollEvent scrollev(xev); |
- SendEventToProcessor(&scrollev); |
- break; |
- } |
- case ui::ET_UNKNOWN: |
- break; |
- default: |
- NOTREACHED(); |
- } |
- |
- // If we coalesced an event we need to free its cookie. |
- if (num_coalesced > 0) |
- XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
- break; |
- } |
- case MapNotify: { |
- FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, |
- observer_list_, |
- OnWindowMapped(xwindow_)); |
- break; |
- } |
- case UnmapNotify: { |
- FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, |
- observer_list_, |
- OnWindowUnmapped(xwindow_)); |
- break; |
- } |
- case ClientMessage: { |
- Atom message_type = xev->xclient.message_type; |
- if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) { |
- Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]); |
- if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { |
- // We have received a close message from the window manager. |
- root_window_->OnWindowTreeHostCloseRequested(); |
- } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) { |
- XEvent reply_event = *xev; |
- reply_event.xclient.window = x_root_window_; |
- |
- XSendEvent(xdisplay_, |
- reply_event.xclient.window, |
- False, |
- SubstructureRedirectMask | SubstructureNotifyMask, |
- &reply_event); |
- } |
- } else if (message_type == atom_cache_.GetAtom("XdndEnter")) { |
- drag_drop_client_->OnXdndEnter(xev->xclient); |
- } else if (message_type == atom_cache_.GetAtom("XdndLeave")) { |
- drag_drop_client_->OnXdndLeave(xev->xclient); |
- } else if (message_type == atom_cache_.GetAtom("XdndPosition")) { |
- drag_drop_client_->OnXdndPosition(xev->xclient); |
- } else if (message_type == atom_cache_.GetAtom("XdndStatus")) { |
- drag_drop_client_->OnXdndStatus(xev->xclient); |
- } else if (message_type == atom_cache_.GetAtom("XdndFinished")) { |
- drag_drop_client_->OnXdndFinished(xev->xclient); |
- } else if (message_type == atom_cache_.GetAtom("XdndDrop")) { |
- drag_drop_client_->OnXdndDrop(xev->xclient); |
- } |
- break; |
- } |
- case MappingNotify: { |
- switch (xev->xmapping.request) { |
- case MappingModifier: |
- case MappingKeyboard: |
- XRefreshKeyboardMapping(&xev->xmapping); |
- root_window_->OnKeyboardMappingChanged(); |
- break; |
- case MappingPointer: |
- ui::DeviceDataManager::GetInstance()->UpdateButtonMap(); |
- break; |
- default: |
- NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; |
- break; |
- } |
- break; |
- } |
- case MotionNotify: { |
- // Discard all but the most recent motion event that targets the same |
- // window with unchanged state. |
- XEvent last_event; |
- while (XPending(xev->xany.display)) { |
- XEvent next_event; |
- XPeekEvent(xev->xany.display, &next_event); |
- if (next_event.type == MotionNotify && |
- next_event.xmotion.window == xev->xmotion.window && |
- next_event.xmotion.subwindow == xev->xmotion.subwindow && |
- next_event.xmotion.state == xev->xmotion.state) { |
- XNextEvent(xev->xany.display, &last_event); |
- xev = &last_event; |
- } else { |
- break; |
- } |
- } |
- |
- ui::MouseEvent mouseev(xev); |
- DispatchMouseEvent(&mouseev); |
- break; |
- } |
- case PropertyNotify: { |
- // Get our new window property state if the WM has told us its changed. |
- ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE"); |
- |
- std::vector< ::Atom> atom_list; |
- if (xev->xproperty.atom == state && |
- ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) { |
- window_properties_.clear(); |
- std::copy(atom_list.begin(), atom_list.end(), |
- inserter(window_properties_, window_properties_.begin())); |
- |
- if (!restored_bounds_.IsEmpty() && !IsMaximized()) { |
- // If we have restored bounds, but WM_STATE no longer claims to be |
- // maximized, we should clear our restored bounds. |
- restored_bounds_ = gfx::Rect(); |
- } else if (IsMaximized() && restored_bounds_.IsEmpty()) { |
- // The request that we become maximized originated from a different |
- // process. |bounds_| already contains our maximized bounds. Do a |
- // best effort attempt to get restored bounds by setting it to our |
- // previously set bounds (and if we get this wrong, we aren't any |
- // worse off since we'd otherwise be returning our maximized bounds). |
- restored_bounds_ = previous_bounds_; |
- } |
- |
- is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN"); |
- is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE"); |
- |
- // Now that we have different window properties, we may need to |
- // relayout the window. (The windows code doesn't need this because |
- // their window change is synchronous.) |
- // |
- // TODO(erg): While this does work, there's a quick flash showing the |
- // tabstrip/toolbar/etc. when going into fullscreen mode before hiding |
- // those parts of the UI because we receive the sizing event from the |
- // window manager before we receive the event that changes the |
- // fullscreen state. Unsure what to do about that. |
- Widget* widget = native_widget_delegate_->AsWidget(); |
- NonClientView* non_client_view = widget->non_client_view(); |
- // non_client_view may be NULL, especially during creation. |
- if (non_client_view) { |
- non_client_view->client_view()->InvalidateLayout(); |
- non_client_view->InvalidateLayout(); |
- } |
- widget->GetRootView()->Layout(); |
- // Refresh the window's border, which may need to be updated if we have |
- // changed the window's maximization state. |
- ResetWindowRegion(); |
- } |
- break; |
- } |
- case SelectionNotify: { |
- drag_drop_client_->OnSelectionNotify(xev->xselection); |
- break; |
- } |
- } |
- return POST_DISPATCH_NONE; |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// DesktopWindowTreeHost, public: |
- |
-// static |
-DesktopWindowTreeHost* DesktopWindowTreeHost::Create( |
- internal::NativeWidgetDelegate* native_widget_delegate, |
- DesktopNativeWidgetAura* desktop_native_widget_aura) { |
- return new DesktopWindowTreeHostX11(native_widget_delegate, |
- desktop_native_widget_aura); |
-} |
- |
-// static |
-ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) { |
- const views::LinuxUI* linux_ui = views::LinuxUI::instance(); |
- if (linux_ui) { |
- ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(); |
- if (native_theme) |
- return native_theme; |
- } |
- |
- return ui::NativeTheme::instance(); |
-} |
- |
-} // namespace views |