diff options
Diffstat (limited to 'chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc')
-rw-r--r-- | chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc | 1544 |
1 files changed, 0 insertions, 1544 deletions
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc deleted file mode 100644 index 545e0cde550..00000000000 --- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc +++ /dev/null @@ -1,1544 +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/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_window_event_filter.h" - -namespace views { - -DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture = - NULL; -std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL; - -DEFINE_WINDOW_PROPERTY_KEY( - aura::Window*, kViewsWindowForRootWindow, NULL); - -DEFINE_WINDOW_PROPERTY_KEY( - DesktopRootWindowHostX11*, 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 - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostX11, public: - -DesktopRootWindowHostX11::DesktopRootWindowHostX11( - 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), - 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) { -} - -DesktopRootWindowHostX11::~DesktopRootWindowHostX11() { - root_window_->window()->ClearProperty(kHostForRootWindow); - aura::client::SetWindowMoveClient(root_window_->window(), NULL); - desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_); - if (custom_window_shape_) - XDestroyRegion(custom_window_shape_); -} - -// static -aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) { - aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid); - return root ? root->window()->GetProperty(kViewsWindowForRootWindow) : NULL; -} - -// static -DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) { - aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid); - return root ? root->window()->GetProperty(kHostForRootWindow) : NULL; -} - -// static -std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() { - std::vector<aura::Window*> windows(open_windows().size()); - std::transform(open_windows().begin(), - open_windows().end(), - windows.begin(), - GetContentWindowForXID); - return windows; -} - -gfx::Rect DesktopRootWindowHostX11::GetX11RootWindowBounds() const { - return bounds_; -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::AddObserver( - views::DesktopRootWindowHostObserverX11* observer) { - observer_list_.AddObserver(observer); -} - -void DesktopRootWindowHostX11::RemoveObserver( - views::DesktopRootWindowHostObserverX11* observer) { - observer_list_.RemoveObserver(observer); -} - -void DesktopRootWindowHostX11::CleanUpWindowList() { - delete open_windows_; - open_windows_ = NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostX11, DesktopRootWindowHost implementation: - -void DesktopRootWindowHostX11::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 RootWindowHost 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 DesktopRootWindowHostX11::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) - parent->AddTransientChild(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)); - x11_window_event_filter_->SetUseHostWindowBorders(false); - 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> DesktopRootWindowHostX11::CreateTooltip() { - return scoped_ptr<corewm::Tooltip>( - new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE)); -} - -scoped_ptr<aura::client::DragDropClient> -DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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(&DesktopRootWindowHostX11::CloseNow, - close_widget_factory_.GetWeakPtr())); - } -} - -void DesktopRootWindowHostX11::CloseNow() { - if (xwindow_ == None) - return; - - native_widget_delegate_->OnNativeWidgetDestroying(); - - // If we have children, close them. Use a copy for iteration because they'll - // remove themselves. - std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_; - for (std::set<DesktopRootWindowHostX11*>::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()); - - 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::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() { - return this; -} - -void DesktopRootWindowHostX11::ShowWindowWithState( - ui::WindowShowState show_state) { - if (show_state != ui::SHOW_STATE_DEFAULT && - show_state != ui::SHOW_STATE_NORMAL) { - // Only forwarding to Show(). - NOTIMPLEMENTED(); - } - - Show(); -} - -void DesktopRootWindowHostX11::ShowMaximizedWithBounds( - const gfx::Rect& restored_bounds) { - restored_bounds_ = restored_bounds; - Maximize(); - Show(); -} - -bool DesktopRootWindowHostX11::IsVisible() const { - return window_mapped_; -} - -void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) { - // TODO(erg): - NOTIMPLEMENTED(); -} - -void DesktopRootWindowHostX11::StackAtTop() { - XRaiseWindow(xdisplay_, xwindow_); -} - -void DesktopRootWindowHostX11::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 (content_window_->transient_parent()) { - gfx::Rect transient_parent_rect = - content_window_->transient_parent()->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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::GetWindowBoundsInScreen() const { - return bounds_; -} - -gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const { - // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its - // needed for View::ConvertPointToScreen() to work - // correctly. DesktopRootWindowHostWin::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::Activate() { - X11DesktopHandler::get()->ActivateWindow(xwindow_); - native_widget_delegate_->AsWidget()->SetInitialFocus(); -} - -void DesktopRootWindowHostX11::Deactivate() { - // Deactivating a window means activating nothing. - X11DesktopHandler::get()->ActivateWindow(None); -} - -bool DesktopRootWindowHostX11::IsActive() const { - return X11DesktopHandler::get()->IsActiveWindow(xwindow_); -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::Minimize() { - XIconifyWindow(xdisplay_, xwindow_, 0); -} - -void DesktopRootWindowHostX11::Restore() { - SetWMSpecState(false, - atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), - atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); -} - -bool DesktopRootWindowHostX11::IsMaximized() const { - return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") && - HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ")); -} - -bool DesktopRootWindowHostX11::IsMinimized() const { - return HasWMSpecProperty("_NET_WM_STATE_HIDDEN"); -} - - -bool DesktopRootWindowHostX11::HasCapture() const { - return g_current_capture == this; -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::IsAlwaysOnTop() const { - return is_always_on_top_; -} - -bool DesktopRootWindowHostX11::SetWindowTitle(const string16& title) { - if (window_title_ == title) - return false; - window_title_ = title; - std::string utf8str = 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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::EndMoveLoop() { - x11_window_move_client_->EndMoveLoop(); -} - -void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled( - bool value) { - // Much like the previous NativeWidgetGtk, we don't have anything to do here. -} - -bool DesktopRootWindowHostX11::ShouldUseNativeFrame() { - return false; -} - -void DesktopRootWindowHostX11::FrameTypeChanged() { - // 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* DesktopRootWindowHostX11::CreateNonClientFrameView() { - return NULL; -} - -void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) { - is_fullscreen_ = fullscreen; - SetWMSpecState(fullscreen, - atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"), - None); -} - -bool DesktopRootWindowHostX11::IsFullscreen() const { - return is_fullscreen_; -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::FlashFrame(bool flash_frame) { - // TODO(erg): - NOTIMPLEMENTED(); -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::OnNativeWidgetFocus() { - native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus(); -} - -void DesktopRootWindowHostX11::OnNativeWidgetBlur() { - if (xwindow_) - native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur(); -} - -bool DesktopRootWindowHostX11::IsAnimatingClosed() const { - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostX11, aura::RootWindowHost implementation: - -aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() { - return root_window_; -} - -gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() { - return xwindow_; -} - -void DesktopRootWindowHostX11::Show() { - if (!window_mapped_) { - // 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); - - 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; - } - - native_widget_delegate_->AsWidget()->SetInitialFocus(); -} - -void DesktopRootWindowHostX11::Hide() { - if (window_mapped_) { - XWithdrawWindow(xdisplay_, xwindow_, 0); - window_mapped_ = false; - } -} - -void DesktopRootWindowHostX11::ToggleFullScreen() { - NOTIMPLEMENTED(); -} - -gfx::Rect DesktopRootWindowHostX11::GetBounds() const { - return bounds_; -} - -void DesktopRootWindowHostX11::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) - delegate_->OnHostResized(bounds.size()); - else - delegate_->OnHostPaint(gfx::Rect(bounds.size())); -} - -gfx::Insets DesktopRootWindowHostX11::GetInsets() const { - return gfx::Insets(); -} - -void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) { -} - -gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const { - return bounds_.origin(); -} - -void DesktopRootWindowHostX11::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; - - // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X - // pointer grab when our NativeWidget is of type Menu. However, things work - // without it. Clicking inside a chrome window causes a release capture, and - // clicking outside causes an activation change. Since previous attempts at - // using XPointerGrab() to implement this have locked my X server, I'm going - // to skip this for now. -} - -void DesktopRootWindowHostX11::ReleaseCapture() { - if (g_current_capture) - g_current_capture->OnCaptureReleased(); -} - -void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) { - XDefineCursor(xdisplay_, xwindow_, cursor.platform()); -} - -bool DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::ConfineCursorToRootWindow() { - NOTIMPLEMENTED(); - return false; -} - -void DesktopRootWindowHostX11::UnConfineCursor() { - NOTIMPLEMENTED(); -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) { - XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, - bounds_.x() + location.x(), bounds_.y() + location.y()); -} - -void DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::OnDeviceScaleFactorChanged( - float device_scale_factor) { -} - -void DesktopRootWindowHostX11::PrepareForShutdown() { -} - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostX11, private: - -void DesktopRootWindowHostX11::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. - if (params.type == Widget::InitParams::TYPE_POPUP || - params.type == Widget::InitParams::TYPE_BUBBLE) { - 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); - } -} - -bool DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::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 DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const { - return window_properties_.find(atom_cache_.GetAtom(property)) != - window_properties_.end(); -} - -void DesktopRootWindowHostX11::OnCaptureReleased() { - g_current_capture = NULL; - delegate_->OnHostLostWindowCapture(); - native_widget_delegate_->OnMouseCaptureLost(); -} - -void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) { - if (!g_current_capture || g_current_capture == this) { - delegate_->OnHostMouseEvent(event); - } else { - // Another DesktopRootWindowHostX11 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->delegate_->OnHostMouseEvent(event); - } -} - -void DesktopRootWindowHostX11::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->delegate_->OnHostTouchEvent(event); - } else { - delegate_->OnHostTouchEvent(event); - } -} - -void DesktopRootWindowHostX11::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 - // by ShapeSet-ing with our bounds rect. - 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 DesktopRootWindowHostX11::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>& DesktopRootWindowHostX11::open_windows() { - if (!open_windows_) - open_windows_ = new std::list<XID>(); - return *open_windows_; -} - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation: - -bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) { - XEvent* xev = event; - - TRACE_EVENT1("views", "DesktopRootWindowHostX11::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); - delegate_->OnHostPaint(damage_rect); - break; - } - case KeyPress: { - ui::KeyEvent keydown_event(xev, false); - delegate_->OnHostKeyEvent(&keydown_event); - break; - } - case KeyRelease: { - ui::KeyEvent keyup_event(xev, false); - delegate_->OnHostKeyEvent(&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 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) - delegate_->OnHostResized(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); - delegate_->OnHostScrollEvent(&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(DesktopRootWindowHostObserverX11, - observer_list_, - OnWindowMapped(xwindow_)); - break; - } - case UnmapNotify: { - FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11, - 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_->OnRootWindowHostCloseRequested(); - } 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(); - } - break; - } - case SelectionNotify: { - drag_drop_client_->OnSelectionNotify(xev->xselection); - break; - } - } - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHost, public: - -// static -DesktopRootWindowHost* DesktopRootWindowHost::Create( - internal::NativeWidgetDelegate* native_widget_delegate, - DesktopNativeWidgetAura* desktop_native_widget_aura) { - return new DesktopRootWindowHostX11(native_widget_delegate, - desktop_native_widget_aura); -} - -// static -ui::NativeTheme* DesktopRootWindowHost::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 |