diff options
author | kylechar <kylechar@chromium.org> | 2016-02-09 14:38:33 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-09 22:39:48 +0000 |
commit | 456fe8e2a64b676531e9d4f24a5268e2523a4d22 (patch) | |
tree | 1292b56a6a0ba0ab2a6016ee524b04ebc768f9f2 /ui/platform_window/x11 | |
parent | 2935096c867e2793db3d551e8dca89071ebd211a (diff) | |
download | chromium_src-456fe8e2a64b676531e9d4f24a5268e2523a4d22.zip chromium_src-456fe8e2a64b676531e9d4f24a5268e2523a4d22.tar.gz chromium_src-456fe8e2a64b676531e9d4f24a5268e2523a4d22.tar.bz2 |
Add PlatformWindow/Event related code for Ozone X11.
The bigger changes here are to X11EventSource and X11Window. For both
classes the current implementation is for PlatformEvent=XEvent* but with
Ozone PlatformEvent=void*=ui::Event*. Most of the implementation will be
the same between X11 and Ozone X11 otherwise. Both classes have been split
into a shared base class and compile specific implementation.
X11EventSource is now the base class. There were two possible listener
implementations, Glib vs Libevent, with Libevent being unused so far. The
X11 implementation is X11EventSourceGlib and uses Glib. The Ozone X11
implementation is X11EventSourceLibevent and uses Libevent. Since the Ozone
X11 implementation is dispatching ui::Events there is a separate dispatcher
list for XEventDispatchers added to send XEvents where necessary.
X11WindowBase is now the base class. The X11 implementation is still called
X11Window. The X11 Ozone implementation is X11WindowOzone. The X11 Ozone
version registers itself as both a PlatformEventDispatcher and
XEventDispatcher.
Compile with the following gn args:
use_ozone = true
ozone_platform_x11 = true
target_os = "chromeos"
TBR=rockot@chromium.org
BUG=361137
Review URL: https://codereview.chromium.org/1602173005
Cr-Commit-Position: refs/heads/master@{#374502}
Diffstat (limited to 'ui/platform_window/x11')
-rw-r--r-- | ui/platform_window/x11/BUILD.gn | 19 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window.cc | 305 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window.gyp | 2 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window.h | 65 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window_base.cc | 284 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window_base.h | 100 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window_ozone.cc | 51 | ||||
-rw-r--r-- | ui/platform_window/x11/x11_window_ozone.h | 42 |
8 files changed, 522 insertions, 346 deletions
diff --git a/ui/platform_window/x11/BUILD.gn b/ui/platform_window/x11/BUILD.gn index 4775aa7..002f6de 100644 --- a/ui/platform_window/x11/BUILD.gn +++ b/ui/platform_window/x11/BUILD.gn @@ -3,8 +3,9 @@ # found in the LICENSE file. import("//build/config/ui.gni") +import("//ui/ozone/ozone.gni") -assert(use_x11) +assert(use_x11 || ozone_platform_x11) component("x11") { output_name = "x11_window" @@ -25,8 +26,20 @@ component("x11") { defines = [ "X11_WINDOW_IMPLEMENTATION" ] sources = [ - "x11_window.cc", - "x11_window.h", + "x11_window_base.cc", + "x11_window_base.h", "x11_window_export.h", ] + + if (ozone_platform_x11) { + sources += [ + "x11_window_ozone.cc", + "x11_window_ozone.h", + ] + } else if (use_x11) { + sources += [ + "x11_window.cc", + "x11_window.h", + ] + } } diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc index 6900a44..f54b416 100644 --- a/ui/platform_window/x11/x11_window.cc +++ b/ui/platform_window/x11/x11_window.cc @@ -5,74 +5,30 @@ #include "ui/platform_window/x11/x11_window.h" #include <X11/extensions/XInput2.h> -#include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include "base/strings/utf_string_conversions.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -#include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/gfx/x/x11_types.h" #include "ui/platform_window/platform_window_delegate.h" namespace ui { -namespace { - -const char* kAtomsToCache[] = { - "UTF8_STRING", - "WM_DELETE_WINDOW", - "_NET_WM_NAME", - "_NET_WM_PID", - "_NET_WM_PING", - NULL -}; - -XID FindXEventTarget(XEvent* xevent) { - XID target = xevent->xany.window; - if (xevent->type == GenericEvent) - target = static_cast<XIDeviceEvent*>(xevent->xcookie.data)->event; - return target; -} - -bool g_override_redirect = false; - -} // namespace - X11Window::X11Window(PlatformWindowDelegate* delegate) - : delegate_(delegate), - xdisplay_(gfx::GetXDisplay()), - xwindow_(None), - xroot_window_(DefaultRootWindow(xdisplay_)), - atom_cache_(xdisplay_, kAtomsToCache), - window_mapped_(false) { - CHECK(delegate_); - TouchFactory::SetTouchDeviceListFromCommandLine(); + : X11WindowBase(delegate) { + DCHECK(PlatformEventSource::GetInstance()); + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); } X11Window::~X11Window() { - Destroy(); -} - -void X11Window::Destroy() { - if (xwindow_ == None) - return; - - // Stop processing events. PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); - XID xwindow = xwindow_; - XDisplay* xdisplay = xdisplay_; - xwindow_ = None; - delegate_->OnClosed(); - // |this| might be deleted because of the above call. +} - XDestroyWindow(xdisplay, xwindow); +void X11Window::SetCursor(PlatformCursor cursor) { + XDefineCursor(xdisplay(), xwindow(), cursor); } void X11Window::ProcessXInput2Event(XEvent* xev) { @@ -83,7 +39,7 @@ void X11Window::ProcessXInput2Event(XEvent* xev) { case ET_KEY_PRESSED: case ET_KEY_RELEASED: { KeyEvent key_event(xev); - delegate_->DispatchEvent(&key_event); + delegate()->DispatchEvent(&key_event); break; } case ET_MOUSE_PRESSED: @@ -91,19 +47,19 @@ void X11Window::ProcessXInput2Event(XEvent* xev) { case ET_MOUSE_DRAGGED: case ET_MOUSE_RELEASED: { MouseEvent mouse_event(xev); - delegate_->DispatchEvent(&mouse_event); + delegate()->DispatchEvent(&mouse_event); break; } case ET_MOUSEWHEEL: { MouseWheelEvent wheel_event(xev); - delegate_->DispatchEvent(&wheel_event); + delegate()->DispatchEvent(&wheel_event); break; } case ET_SCROLL_FLING_START: case ET_SCROLL_FLING_CANCEL: case ET_SCROLL: { ScrollEvent scroll_event(xev); - delegate_->DispatchEvent(&scroll_event); + delegate()->DispatchEvent(&scroll_event); break; } case ET_TOUCH_MOVED: @@ -111,7 +67,7 @@ void X11Window::ProcessXInput2Event(XEvent* xev) { case ET_TOUCH_CANCELLED: case ET_TOUCH_RELEASED: { TouchEvent touch_event(xev); - delegate_->DispatchEvent(&touch_event); + delegate()->DispatchEvent(&touch_event); break; } default: @@ -119,182 +75,8 @@ void X11Window::ProcessXInput2Event(XEvent* xev) { } } -void X11Window::Show() { - if (window_mapped_) - return; - - CHECK(PlatformEventSource::GetInstance()); - PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - - XSetWindowAttributes swa; - memset(&swa, 0, sizeof(swa)); - swa.background_pixmap = None; - swa.bit_gravity = NorthWestGravity; - swa.override_redirect = g_override_redirect; - xwindow_ = XCreateWindow(xdisplay_, - xroot_window_, - requested_bounds_.x(), - requested_bounds_.y(), - requested_bounds_.width(), - requested_bounds_.height(), - 0, // border width - CopyFromParent, // depth - InputOutput, - CopyFromParent, // visual - CWBackPixmap | CWBitGravity | CWOverrideRedirect, - &swa); - - long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | - KeyPressMask | KeyReleaseMask | EnterWindowMask | - LeaveWindowMask | ExposureMask | VisibilityChangeMask | - StructureNotifyMask | PropertyChangeMask | - PointerMotionMask; - XSelectInput(xdisplay_, xwindow_, event_mask); - - unsigned char mask[XIMaskLen(XI_LASTEVENT)]; - memset(mask, 0, sizeof(mask)); - - XISetMask(mask, XI_TouchBegin); - XISetMask(mask, XI_TouchUpdate); - XISetMask(mask, XI_TouchEnd); - XISetMask(mask, XI_ButtonPress); - XISetMask(mask, XI_ButtonRelease); - XISetMask(mask, XI_Motion); - XISetMask(mask, XI_KeyPress); - XISetMask(mask, XI_KeyRelease); - - XIEventMask evmask; - evmask.deviceid = XIAllDevices; - evmask.mask_len = sizeof(mask); - evmask.mask = mask; - XISelectEvents(xdisplay_, xwindow_, &evmask, 1); - XFlush(xdisplay_); - - ::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. - static_assert(sizeof(long) >= sizeof(pid_t), - "pid_t should not be larger than long"); - long pid = getpid(); - XChangeProperty(xdisplay_, - xwindow_, - atom_cache_.GetAtom("_NET_WM_PID"), - XA_CARDINAL, - 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&pid), - 1); - // Before we map the window, set size hints. Otherwise, some window managers - // will ignore toplevel XMoveWindow commands. - XSizeHints size_hints; - size_hints.flags = PPosition | PWinGravity; - size_hints.x = requested_bounds_.x(); - size_hints.y = requested_bounds_.y(); - // Set StaticGravity so that the window position is not affected by the - // frame width when running with window manager. - size_hints.win_gravity = StaticGravity; - 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. - if (X11EventSource::GetInstance()) - X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_); - window_mapped_ = true; - - // TODO(sky): provide real scale factor. - delegate_->OnAcceleratedWidgetAvailable(xwindow_, 1.f); -} - -void X11Window::Hide() { - if (!window_mapped_) - return; - XWithdrawWindow(xdisplay_, xwindow_, 0); - window_mapped_ = false; -} - -void X11Window::Close() { - Destroy(); -} - -void X11Window::SetBounds(const gfx::Rect& bounds) { - requested_bounds_ = bounds; - if (!window_mapped_) - return; - XWindowChanges changes = {0}; - unsigned value_mask = CWX | CWY | CWWidth | CWHeight; - changes.x = bounds.x(); - changes.y = bounds.y(); - changes.width = bounds.width(); - changes.height = bounds.height(); - XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); -} - -gfx::Rect X11Window::GetBounds() { - return confirmed_bounds_; -} - -void X11Window::SetTitle(const base::string16& title) { - if (window_title_ == title) - return; - 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()); - XTextProperty xtp; - char *c_utf8_str = const_cast<char *>(utf8str.c_str()); - if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, - XUTF8StringStyle, &xtp) == Success) { - XSetWMName(xdisplay_, xwindow_, &xtp); - XFree(xtp.value); - } -} - -void X11Window::SetCapture() {} - -void X11Window::ReleaseCapture() {} - -void X11Window::ToggleFullscreen() {} - -void X11Window::Maximize() {} - -void X11Window::Minimize() {} - -void X11Window::Restore() {} - -void X11Window::SetCursor(PlatformCursor cursor) { - XDefineCursor(xdisplay_, xwindow_, cursor); -} - -void X11Window::MoveCursorTo(const gfx::Point& location) {} - -void X11Window::ConfineCursorToBounds(const gfx::Rect& bounds) { -} - -PlatformImeController* X11Window::GetPlatformImeController() { - return nullptr; -} - -bool X11Window::CanDispatchEvent(const PlatformEvent& event) { - return FindXEventTarget(event) == xwindow_; +bool X11Window::CanDispatchEvent(const PlatformEvent& xev) { + return IsEventForXWindow(*xev); } uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { @@ -306,28 +88,19 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { MouseEvent mouse_event(xev); CHECK_EQ(ET_MOUSE_MOVED, mouse_event.type()); mouse_event.set_flags(mouse_event.flags() | EF_IS_SYNTHESIZED); - delegate_->DispatchEvent(&mouse_event); + delegate()->DispatchEvent(&mouse_event); break; } case LeaveNotify: { MouseEvent mouse_event(xev); - delegate_->DispatchEvent(&mouse_event); - break; - } - - case Expose: { - gfx::Rect damage_rect(xev->xexpose.x, - xev->xexpose.y, - xev->xexpose.width, - xev->xexpose.height); - delegate_->OnDamageRect(damage_rect); + delegate()->DispatchEvent(&mouse_event); break; } case KeyPress: case KeyRelease: { KeyEvent key_event(xev); - delegate_->DispatchEvent(&key_event); + delegate()->DispatchEvent(&key_event); break; } @@ -336,13 +109,13 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { switch (EventTypeFromNative(xev)) { case ET_MOUSEWHEEL: { MouseWheelEvent mouseev(xev); - delegate_->DispatchEvent(&mouseev); + delegate()->DispatchEvent(&mouseev); break; } case ET_MOUSE_PRESSED: case ET_MOUSE_RELEASED: { MouseEvent mouseev(xev); - delegate_->DispatchEvent(&mouseev); + delegate()->DispatchEvent(&mouseev); break; } case ET_UNKNOWN: @@ -355,40 +128,11 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { break; } + case Expose: case FocusOut: - if (xev->xfocus.mode != NotifyGrab) - delegate_->OnLostCapture(); - break; - - case ConfigureNotify: { - DCHECK_EQ(xwindow_, xev->xconfigure.event); - DCHECK_EQ(xwindow_, xev->xconfigure.window); - gfx::Rect bounds(xev->xconfigure.x, - xev->xconfigure.y, - xev->xconfigure.width, - xev->xconfigure.height); - if (confirmed_bounds_ != bounds) { - confirmed_bounds_ = bounds; - delegate_->OnBoundsChanged(confirmed_bounds_); - } - break; - } - + case ConfigureNotify: case ClientMessage: { - Atom message = static_cast<Atom>(xev->xclient.data.l[0]); - if (message == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { - delegate_->OnCloseRequest(); - } else if (message == atom_cache_.GetAtom("_NET_WM_PING")) { - XEvent reply_event = *xev; - reply_event.xclient.window = xroot_window_; - - XSendEvent(xdisplay_, - reply_event.xclient.window, - False, - SubstructureRedirectMask | SubstructureNotifyMask, - &reply_event); - XFlush(xdisplay_); - } + ProcessXWindowEvent(xev); break; } @@ -400,11 +144,4 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { return POST_DISPATCH_STOP_PROPAGATION; } -namespace test { - -void SetUseOverrideRedirectWindowByDefault(bool override_redirect) { - g_override_redirect = override_redirect; -} - -} // namespace test } // namespace ui diff --git a/ui/platform_window/x11/x11_window.gyp b/ui/platform_window/x11/x11_window.gyp index 0dd840a..f4b948a 100644 --- a/ui/platform_window/x11/x11_window.gyp +++ b/ui/platform_window/x11/x11_window.gyp @@ -26,6 +26,8 @@ 'sources': [ 'x11_window.cc', 'x11_window.h', + 'x11_window_base.cc', + 'x11_window_base.h', 'x11_window_export.h', ], }], diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h index 54bbed8..c3f15cf 100644 --- a/ui/platform_window/x11/x11_window.h +++ b/ui/platform_window/x11/x11_window.h @@ -5,86 +5,33 @@ #ifndef UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_ #define UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_ -#include <stdint.h> - #include "base/macros.h" #include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/platform_window/platform_window.h" -#include "ui/platform_window/platform_window_delegate.h" +#include "ui/platform_window/x11/x11_window_base.h" #include "ui/platform_window/x11/x11_window_export.h" -typedef struct _XDisplay XDisplay; -typedef unsigned long XID; - namespace ui { -class X11_WINDOW_EXPORT X11Window : public PlatformWindow, +// PlatformWindow implementation for X11. PlatformEvents are XEvents. +class X11_WINDOW_EXPORT X11Window : public X11WindowBase, public PlatformEventDispatcher { public: explicit X11Window(PlatformWindowDelegate* delegate); ~X11Window() override; - private: - void Destroy(); - - void ProcessXInput2Event(XEvent* xevent); - // PlatformWindow: - void Show() override; - void Hide() override; - void Close() override; - void SetBounds(const gfx::Rect& bounds) override; - gfx::Rect GetBounds() override; - void SetTitle(const base::string16& title) override; - void SetCapture() override; - void ReleaseCapture() override; - void ToggleFullscreen() override; - void Maximize() override; - void Minimize() override; - void Restore() override; void SetCursor(PlatformCursor cursor) override; - void MoveCursorTo(const gfx::Point& location) override; - void ConfineCursorToBounds(const gfx::Rect& bounds) override; - PlatformImeController* GetPlatformImeController() override; + + private: + void ProcessXInput2Event(XEvent* xev); // PlatformEventDispatcher: bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; - PlatformWindowDelegate* delegate_; - - XDisplay* xdisplay_; - XID xwindow_; - XID xroot_window_; - X11AtomCache atom_cache_; - - base::string16 window_title_; - - // Setting the bounds is an asynchronous operation in X11. |requested_bounds_| - // is the bounds requested using XConfigureWindow, and |confirmed_bounds_| is - // the bounds the X11 server has set on the window. - gfx::Rect requested_bounds_; - gfx::Rect confirmed_bounds_; - - bool window_mapped_; - DISALLOW_COPY_AND_ASSIGN(X11Window); }; -namespace test { - -// Sets the value of the |override_redirect| flag when creating an X11 window. -// It is necessary to set this flag on for various tests, otherwise the call to -// X11Window::Show() blocks because it never receives the MapNotify event. It is -// unclear why this is necessary, but might be related to calls to -// XInitThreads(). -X11_WINDOW_EXPORT void SetUseOverrideRedirectWindowByDefault( - bool override_redirect); - -} // namespace test - } // namespace ui #endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_ diff --git a/ui/platform_window/x11/x11_window_base.cc b/ui/platform_window/x11/x11_window_base.cc new file mode 100644 index 0000000..4c24d7e --- /dev/null +++ b/ui/platform_window/x11/x11_window_base.cc @@ -0,0 +1,284 @@ +// Copyright 2016 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/platform_window/x11/x11_window_base.h" + +#include <X11/extensions/XInput2.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <string> + +#include "base/strings/utf_string_conversions.h" +#include "ui/events/devices/x11/touch_factory_x11.h" +#include "ui/events/event.h" +#include "ui/events/event_utils.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/platform_event_source.h" +#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/x11_types.h" +#include "ui/platform_window/platform_window_delegate.h" + +namespace ui { + +namespace { + +const char* kAtomsToCache[] = {"UTF8_STRING", "WM_DELETE_WINDOW", + "_NET_WM_NAME", "_NET_WM_PID", + "_NET_WM_PING", NULL}; + +bool g_override_redirect = false; + +XID FindXEventTarget(const XEvent& xev) { + XID target = xev.xany.window; + if (xev.type == GenericEvent) + target = static_cast<XIDeviceEvent*>(xev.xcookie.data)->event; + return target; +} + +} // namespace + +X11WindowBase::X11WindowBase(PlatformWindowDelegate* delegate) + : delegate_(delegate), + xdisplay_(gfx::GetXDisplay()), + xwindow_(None), + xroot_window_(DefaultRootWindow(xdisplay_)), + atom_cache_(xdisplay_, kAtomsToCache) { + DCHECK(delegate_); + TouchFactory::SetTouchDeviceListFromCommandLine(); +} + +X11WindowBase::~X11WindowBase() { + Destroy(); +} + +void X11WindowBase::Destroy() { + if (xwindow_ == None) + return; + + // Stop processing events. + XID xwindow = xwindow_; + XDisplay* xdisplay = xdisplay_; + xwindow_ = None; + delegate_->OnClosed(); + // |this| might be deleted because of the above call. + + XDestroyWindow(xdisplay, xwindow); +} + +void X11WindowBase::Create() { + XSetWindowAttributes swa; + memset(&swa, 0, sizeof(swa)); + swa.background_pixmap = None; + swa.bit_gravity = NorthWestGravity; + swa.override_redirect = g_override_redirect; + xwindow_ = XCreateWindow( + xdisplay_, xroot_window_, requested_bounds_.x(), requested_bounds_.y(), + requested_bounds_.width(), requested_bounds_.height(), + 0, // border width + CopyFromParent, // depth + InputOutput, + CopyFromParent, // visual + CWBackPixmap | CWBitGravity | CWOverrideRedirect, &swa); + + long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | + KeyPressMask | KeyReleaseMask | EnterWindowMask | + LeaveWindowMask | ExposureMask | VisibilityChangeMask | + StructureNotifyMask | PropertyChangeMask | + PointerMotionMask; + XSelectInput(xdisplay_, xwindow_, event_mask); + + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; + memset(mask, 0, sizeof(mask)); + + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchEnd); + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); + XISetMask(mask, XI_KeyPress); + XISetMask(mask, XI_KeyRelease); + + XIEventMask evmask; + evmask.deviceid = XIAllDevices; + evmask.mask_len = sizeof(mask); + evmask.mask = mask; + XISelectEvents(xdisplay_, xwindow_, &evmask, 1); + XFlush(xdisplay_); + + ::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. + static_assert(sizeof(long) >= sizeof(pid_t), + "pid_t should not be larger than long"); + long pid = getpid(); + XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_PID"), + XA_CARDINAL, 32, PropModeReplace, + reinterpret_cast<unsigned char*>(&pid), 1); + // Before we map the window, set size hints. Otherwise, some window managers + // will ignore toplevel XMoveWindow commands. + XSizeHints size_hints; + size_hints.flags = PPosition | PWinGravity; + size_hints.x = requested_bounds_.x(); + size_hints.y = requested_bounds_.y(); + // Set StaticGravity so that the window position is not affected by the + // frame width when running with window manager. + size_hints.win_gravity = StaticGravity; + XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); + + // TODO(sky): provide real scale factor. + delegate_->OnAcceleratedWidgetAvailable(xwindow_, 1.f); +} + +void X11WindowBase::Show() { + if (window_mapped_) + return; + if (xwindow_ == None) + Create(); + + 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. + if (X11EventSource::GetInstance()) + X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_); + window_mapped_ = true; +} + +void X11WindowBase::Hide() { + if (!window_mapped_) + return; + XWithdrawWindow(xdisplay_, xwindow_, 0); + window_mapped_ = false; +} + +void X11WindowBase::Close() { + Destroy(); +} + +void X11WindowBase::SetBounds(const gfx::Rect& bounds) { + requested_bounds_ = bounds; + if (!window_mapped_ || bounds == confirmed_bounds_) + return; + XWindowChanges changes = {0}; + unsigned value_mask = CWX | CWY | CWWidth | CWHeight; + changes.x = bounds.x(); + changes.y = bounds.y(); + changes.width = bounds.width(); + changes.height = bounds.height(); + XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); +} + +gfx::Rect X11WindowBase::GetBounds() { + return confirmed_bounds_; +} + +void X11WindowBase::SetTitle(const base::string16& title) { + if (window_title_ == title) + return; + 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()); + XTextProperty xtp; + char* c_utf8_str = const_cast<char*>(utf8str.c_str()); + if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, XUTF8StringStyle, + &xtp) == Success) { + XSetWMName(xdisplay_, xwindow_, &xtp); + XFree(xtp.value); + } +} + +void X11WindowBase::SetCapture() {} + +void X11WindowBase::ReleaseCapture() {} + +void X11WindowBase::ToggleFullscreen() {} + +void X11WindowBase::Maximize() {} + +void X11WindowBase::Minimize() {} + +void X11WindowBase::Restore() {} + +void X11WindowBase::MoveCursorTo(const gfx::Point& location) {} + +void X11WindowBase::ConfineCursorToBounds(const gfx::Rect& bounds) {} + +PlatformImeController* X11WindowBase::GetPlatformImeController() { + return nullptr; +} + +bool X11WindowBase::IsEventForXWindow(const XEvent& xev) const { + return xwindow_ != None && FindXEventTarget(xev) == xwindow_; +} + +void X11WindowBase::ProcessXWindowEvent(XEvent* xev) { + switch (xev->type) { + case Expose: { + gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, xev->xexpose.width, + xev->xexpose.height); + delegate_->OnDamageRect(damage_rect); + break; + } + + case FocusOut: + if (xev->xfocus.mode != NotifyGrab) + delegate_->OnLostCapture(); + break; + + case ConfigureNotify: { + DCHECK_EQ(xwindow_, xev->xconfigure.event); + DCHECK_EQ(xwindow_, xev->xconfigure.window); + gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, + xev->xconfigure.width, xev->xconfigure.height); + if (confirmed_bounds_ != bounds) { + confirmed_bounds_ = bounds; + delegate_->OnBoundsChanged(confirmed_bounds_); + } + break; + } + + case ClientMessage: { + Atom message = static_cast<Atom>(xev->xclient.data.l[0]); + if (message == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { + delegate_->OnCloseRequest(); + } else if (message == atom_cache_.GetAtom("_NET_WM_PING")) { + XEvent reply_event = *xev; + reply_event.xclient.window = xroot_window_; + + XSendEvent(xdisplay_, reply_event.xclient.window, False, + SubstructureRedirectMask | SubstructureNotifyMask, + &reply_event); + XFlush(xdisplay_); + } + break; + } + } +} + +namespace test { + +void SetUseOverrideRedirectWindowByDefault(bool override_redirect) { + g_override_redirect = override_redirect; +} + +} // namespace test +} // namespace ui diff --git a/ui/platform_window/x11/x11_window_base.h b/ui/platform_window/x11/x11_window_base.h new file mode 100644 index 0000000..da35725 --- /dev/null +++ b/ui/platform_window/x11/x11_window_base.h @@ -0,0 +1,100 @@ +// Copyright 2016 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. + +#ifndef UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_ +#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_ + +#include <stdint.h> + +#include "base/callback.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/x/x11_atom_cache.h" +#include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_delegate.h" +#include "ui/platform_window/x11/x11_window_export.h" + +typedef struct _XDisplay XDisplay; +typedef unsigned long XID; +typedef union _XEvent XEvent; + +namespace ui { + +// Abstract base implementation for a X11 based PlatformWindow. Methods that +// are platform specific are left unimplemented. +class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow { + public: + explicit X11WindowBase(PlatformWindowDelegate* delegate); + ~X11WindowBase() override; + + // Creates new underlying XWindow. Does not map XWindow. + void Create(); + + // PlatformWindow: + void Show() override; + void Hide() override; + void Close() override; + void SetBounds(const gfx::Rect& bounds) override; + gfx::Rect GetBounds() override; + void SetTitle(const base::string16& title) override; + void SetCapture() override; + void ReleaseCapture() override; + void ToggleFullscreen() override; + void Maximize() override; + void Minimize() override; + void Restore() override; + void MoveCursorTo(const gfx::Point& location) override; + void ConfineCursorToBounds(const gfx::Rect& bounds) override; + PlatformImeController* GetPlatformImeController() override; + + protected: + void Destroy(); + + PlatformWindowDelegate* delegate() { return delegate_; } + XDisplay* xdisplay() { return xdisplay_; } + XID xwindow() const { return xwindow_; } + + // Checks if XEvent is for this XWindow. + bool IsEventForXWindow(const XEvent& xev) const; + + // Processes events for this XWindow. + void ProcessXWindowEvent(XEvent* xev); + + private: + PlatformWindowDelegate* delegate_; + + XDisplay* xdisplay_; + XID xwindow_; + XID xroot_window_; + X11AtomCache atom_cache_; + + base::string16 window_title_; + + // Setting the bounds is an asynchronous operation in X11. |requested_bounds_| + // is the bounds requested using XConfigureWindow, and |confirmed_bounds_| is + // the bounds the X11 server has set on the window. + gfx::Rect requested_bounds_; + gfx::Rect confirmed_bounds_; + + bool window_mapped_ = false; + + DISALLOW_COPY_AND_ASSIGN(X11WindowBase); +}; + +namespace test { + +// Sets the value of the |override_redirect| flag when creating an X11 window. +// It is necessary to set this flag on for various tests, otherwise the call to +// X11WindowBase::Show() blocks because it never receives the MapNotify event. +// It is +// unclear why this is necessary, but might be related to calls to +// XInitThreads(). +X11_WINDOW_EXPORT void SetUseOverrideRedirectWindowByDefault( + bool override_redirect); + +} // namespace test + +} // namespace ui + +#endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_ diff --git a/ui/platform_window/x11/x11_window_ozone.cc b/ui/platform_window/x11/x11_window_ozone.cc new file mode 100644 index 0000000..6193b1f --- /dev/null +++ b/ui/platform_window/x11/x11_window_ozone.cc @@ -0,0 +1,51 @@ +// Copyright 2016 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/platform_window/x11/x11_window_ozone.h" + +#include <X11/Xlib.h> + +#include "ui/events/event.h" +#include "ui/events/ozone/events_ozone.h" +#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/geometry/point.h" + +namespace ui { + +X11WindowOzone::X11WindowOzone(X11EventSourceLibevent* event_source, + PlatformWindowDelegate* delegate) + : X11WindowBase(delegate), event_source_(event_source) { + DCHECK(event_source_); + event_source_->AddPlatformEventDispatcher(this); + event_source_->AddXEventDispatcher(this); +} + +X11WindowOzone::~X11WindowOzone() { + event_source_->RemovePlatformEventDispatcher(this); + event_source_->RemoveXEventDispatcher(this); +} + +void X11WindowOzone::SetCursor(PlatformCursor cursor) {} + +bool X11WindowOzone::DispatchXEvent(XEvent* xev) { + if (!IsEventForXWindow(*xev)) + return false; + + ProcessXWindowEvent(xev); + return true; +} + +bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& event) { + // TODO(kylechar): This is broken, there is no way to include XID of XWindow + // in ui::Event. Fix or use similar hack to DrmWindowHost. + return xwindow() != None; +} + +uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& platform_event) { + Event* event = static_cast<Event*>(platform_event); + delegate()->DispatchEvent(event); + return POST_DISPATCH_STOP_PROPAGATION; +} + +} // namespace ui diff --git a/ui/platform_window/x11/x11_window_ozone.h b/ui/platform_window/x11/x11_window_ozone.h new file mode 100644 index 0000000..b6c4573 --- /dev/null +++ b/ui/platform_window/x11/x11_window_ozone.h @@ -0,0 +1,42 @@ +// Copyright 2016 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. + +#ifndef UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ +#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ + +#include "base/macros.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/x11/x11_event_source_libevent.h" +#include "ui/platform_window/x11/x11_window_base.h" + +namespace ui { + +// PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events. +class X11_WINDOW_EXPORT X11WindowOzone : public X11WindowBase, + public PlatformEventDispatcher, + public XEventDispatcher { + public: + X11WindowOzone(X11EventSourceLibevent* event_source, + PlatformWindowDelegate* delegate); + ~X11WindowOzone() override; + + // PlatformWindow: + void SetCursor(PlatformCursor cursor) override; + + // XEventDispatcher: + bool DispatchXEvent(XEvent* event) override; + + private: + // PlatformEventDispatcher: + bool CanDispatchEvent(const PlatformEvent& event) override; + uint32_t DispatchEvent(const PlatformEvent& event) override; + + X11EventSourceLibevent* event_source_; + + DISALLOW_COPY_AND_ASSIGN(X11WindowOzone); +}; + +} // namespace ui + +#endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ |