diff options
Diffstat (limited to 'ui')
24 files changed, 961 insertions, 521 deletions
diff --git a/ui/aura/window_tree_host_x11.cc b/ui/aura/window_tree_host_x11.cc index 43f7265..a5675e9 100644 --- a/ui/aura/window_tree_host_x11.cc +++ b/ui/aura/window_tree_host_x11.cc @@ -45,6 +45,7 @@ #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/platform/platform_event_observer.h" +#include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/screen.h" diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc index 457ba6b..90fa7c2 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc @@ -13,7 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/dragdrop/file_info.h" -#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/x11/x11_event_source_glib.h" #include "url/gurl.h" const char kFileURL[] = "file:///home/user/file.txt"; @@ -39,7 +39,7 @@ class OSExchangeDataProviderAuraX11Test : public testing::Test { protected: base::MessageLoopForUI message_loop; - X11EventSource event_source; + X11EventSourceGlib event_source; ui::OSExchangeDataProviderAuraX11 provider; }; diff --git a/ui/events/platform/x11/BUILD.gn b/ui/events/platform/x11/BUILD.gn index e55afc7..929613c 100644 --- a/ui/events/platform/x11/BUILD.gn +++ b/ui/events/platform/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_events_platform" @@ -12,8 +13,6 @@ component("x11") { sources = [ "x11_event_source.cc", "x11_event_source.h", - "x11_event_source_glib.cc", - "x11_event_source_libevent.cc", "x11_hotplug_event_handler.cc", "x11_hotplug_event_handler.h", ] @@ -27,6 +26,7 @@ component("x11") { "//ui/events:events_base", "//ui/events/devices", "//ui/events/platform", + "//ui/events/x", "//ui/gfx/x", ] @@ -34,11 +34,17 @@ component("x11") { "//base", ] - if (is_linux) { - sources -= [ "x11_event_source_libevent.cc" ] + if (use_glib) { + sources += [ + "x11_event_source_glib.cc", + "x11_event_source_glib.h", + ] configs += [ "//build/config/linux:glib" ] } else { - sources -= [ "x11_event_source_glib.cc" ] + sources += [ + "x11_event_source_libevent.cc", + "x11_event_source_libevent.h", + ] } } diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc index ba55e0b..f450227 100644 --- a/ui/events/platform/x11/x11_event_source.cc +++ b/ui/events/platform/x11/x11_event_source.cc @@ -4,51 +4,19 @@ #include "ui/events/platform/x11/x11_event_source.h" -#include <X11/extensions/XInput2.h> -#include <X11/X.h> -#include <X11/Xlib.h> #include <X11/XKBlib.h> +#include <X11/Xlib.h> #include "base/logging.h" #include "ui/events/devices/x11/device_data_manager_x11.h" #include "ui/events/event_utils.h" #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/x11/x11_hotplug_event_handler.h" -#include "ui/gfx/x/x11_types.h" namespace ui { namespace { -int g_xinput_opcode = -1; - -bool InitializeXInput2(XDisplay* display) { - if (!display) - return false; - - int event, err; - - int xiopcode; - if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { - DVLOG(1) << "X Input extension not available."; - return false; - } - g_xinput_opcode = xiopcode; - - int major = 2, minor = 2; - if (XIQueryVersion(display, &major, &minor) == BadRequest) { - DVLOG(1) << "XInput2 not supported in the server."; - return false; - } - if (major < 2 || (major == 2 && minor < 2)) { - DVLOG(1) << "XI version on server is " << major << "." << minor << ". " - << "But 2.2 is required."; - return false; - } - - return true; -} - bool InitializeXkb(XDisplay* display) { if (!display) return false; @@ -74,21 +42,29 @@ bool InitializeXkb(XDisplay* display) { } // namespace -X11EventSource::X11EventSource(XDisplay* display) - : display_(display), - continue_stream_(true) { - CHECK(display_); +X11EventSource* X11EventSource::instance_ = nullptr; + +X11EventSource::X11EventSource(X11EventSourceDelegate* delegate, + XDisplay* display) + : delegate_(delegate), display_(display), continue_stream_(true) { + DCHECK(!instance_); + instance_ = this; + + DCHECK(delegate_); + DCHECK(display_); DeviceDataManagerX11::CreateInstance(); - InitializeXInput2(display_); InitializeXkb(display_); } X11EventSource::~X11EventSource() { + DCHECK_EQ(this, instance_); + instance_ = nullptr; } // static X11EventSource* X11EventSource::GetInstance() { - return static_cast<X11EventSource*>(PlatformEventSource::GetInstance()); + DCHECK(instance_); + return instance_; } //////////////////////////////////////////////////////////////////////////////// @@ -118,22 +94,21 @@ void X11EventSource::BlockUntilWindowMapped(XID window) { } //////////////////////////////////////////////////////////////////////////////// -// X11EventSource, private +// X11EventSource, protected -uint32_t X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { +void X11EventSource::ExtractCookieDataDispatchEvent(XEvent* xevent) { bool have_cookie = false; if (xevent->type == GenericEvent && XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { have_cookie = true; } - uint32_t action = DispatchEvent(xevent); + delegate_->ProcessXEvent(xevent); + PostDispatchEvent(xevent); if (have_cookie) XFreeEventData(xevent->xgeneric.display, &xevent->xcookie); - return action; } -uint32_t X11EventSource::DispatchEvent(XEvent* xevent) { - uint32_t action = PlatformEventSource::DispatchEvent(xevent); +void X11EventSource::PostDispatchEvent(XEvent* xevent) { if (xevent->type == GenericEvent && (xevent->xgeneric.evtype == XI_HierarchyChanged || xevent->xgeneric.evtype == XI_DeviceChanged)) { @@ -147,7 +122,6 @@ uint32_t X11EventSource::DispatchEvent(XEvent* xevent) { // Clear stored scroll data ui::DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses(); } - return action; } void X11EventSource::StopCurrentEventStream() { diff --git a/ui/events/platform/x11/x11_event_source.h b/ui/events/platform/x11/x11_event_source.h index 26d6460..5816908 100644 --- a/ui/events/platform/x11/x11_event_source.h +++ b/ui/events/platform/x11/x11_event_source.h @@ -10,11 +10,8 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "ui/events/events_export.h" -#include "ui/events/platform/platform_event_source.h" #include "ui/gfx/x/x11_types.h" -typedef struct _GPollFD GPollFD; -typedef struct _GSource GSource; typedef union _XEvent XEvent; typedef unsigned long XID; @@ -22,16 +19,30 @@ namespace ui { class X11HotplugEventHandler; -// A PlatformEventSource implementation for reading events from X11 server and -// dispatching the events to the appropriate dispatcher. -class EVENTS_EXPORT X11EventSource : public PlatformEventSource { +// Responsible for notifying X11EventSource when new XEvents are available and +// processing/dispatching XEvents. Implementations will likely be a +// PlatformEventSource. +class X11EventSourceDelegate { public: - explicit X11EventSource(XDisplay* display); - ~X11EventSource() override; + X11EventSourceDelegate() = default; + + // Processes (if necessary) and handles dispatching XEvents. + virtual void ProcessXEvent(XEvent* xevent) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(X11EventSourceDelegate); +}; + +// Receives X11 events and sends them to X11EventSourceDelegate. Handles +// receiving, pre-process and post-processing XEvents. +class EVENTS_EXPORT X11EventSource { + public: + X11EventSource(X11EventSourceDelegate* delegate, XDisplay* display); + ~X11EventSource(); static X11EventSource* GetInstance(); - // Called by the glib source dispatch function. Processes all (if any) + // Called when there is a new XEvent available. Processes all (if any) // available X events. void DispatchXEvents(); @@ -46,26 +57,31 @@ class EVENTS_EXPORT X11EventSource : public PlatformEventSource { // functions which require a mapped window. void BlockUntilWindowMapped(XID window); - protected: XDisplay* display() { return display_; } - private: + void StopCurrentEventStream(); + void OnDispatcherListChanged(); + + protected: // Extracts cookie data from |xevent| if it's of GenericType, and dispatches // the event. This function also frees up the cookie data after dispatch is // complete. - uint32_t ExtractCookieDataDispatchEvent(XEvent* xevent); + void ExtractCookieDataDispatchEvent(XEvent* xevent); + + // Handles updates after event has been dispatched. + void PostDispatchEvent(XEvent* xevent); + + private: + static X11EventSource* instance_; - // PlatformEventSource: - uint32_t DispatchEvent(XEvent* xevent) override; - void StopCurrentEventStream() override; - void OnDispatcherListChanged() override; + X11EventSourceDelegate* delegate_; // The connection to the X11 server used to receive the events. XDisplay* display_; // Keeps track of whether this source should continue to dispatch all the // available events. - bool continue_stream_; + bool continue_stream_ = true; scoped_ptr<X11HotplugEventHandler> hotplug_event_handler_; diff --git a/ui/events/platform/x11/x11_event_source_glib.cc b/ui/events/platform/x11/x11_event_source_glib.cc index 2151601..1eb272a 100644 --- a/ui/events/platform/x11/x11_event_source_glib.cc +++ b/ui/events/platform/x11/x11_event_source_glib.cc @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/macros.h" -#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/x11/x11_event_source_glib.h" #include <glib.h> #include <X11/Xlib.h> @@ -48,52 +47,52 @@ GSourceFuncs XSourceFuncs = { NULL }; -class X11EventSourceGlib : public X11EventSource { - public: - explicit X11EventSourceGlib(XDisplay* display) - : X11EventSource(display), - x_source_(NULL) { - InitXSource(ConnectionNumber(display)); - } - - ~X11EventSourceGlib() override { - g_source_destroy(x_source_); - g_source_unref(x_source_); - } - - private: - void InitXSource(int fd) { - CHECK(!x_source_); - CHECK(display()) << "Unable to get connection to X server"; - - x_poll_.reset(new GPollFD()); - x_poll_->fd = fd; - x_poll_->events = G_IO_IN; - x_poll_->revents = 0; - - GLibX11Source* glib_x_source = static_cast<GLibX11Source*> - (g_source_new(&XSourceFuncs, sizeof(GLibX11Source))); - glib_x_source->display = display(); - glib_x_source->poll_fd = x_poll_.get(); - - x_source_ = glib_x_source; - g_source_add_poll(x_source_, x_poll_.get()); - g_source_set_can_recurse(x_source_, TRUE); - g_source_set_callback(x_source_, NULL, this, NULL); - g_source_attach(x_source_, g_main_context_default()); - } - - // The GLib event source for X events. - GSource* x_source_; - - // The poll attached to |x_source_|. - scoped_ptr<GPollFD> x_poll_; - - DISALLOW_COPY_AND_ASSIGN(X11EventSourceGlib); -}; - } // namespace +X11EventSourceGlib::X11EventSourceGlib(XDisplay* display) + : event_source_(this, display) { + InitXSource(ConnectionNumber(display)); +} + +X11EventSourceGlib::~X11EventSourceGlib() { + g_source_destroy(x_source_); + g_source_unref(x_source_); +} + +void X11EventSourceGlib::ProcessXEvent(XEvent* xevent) { + DispatchEvent(xevent); +} + +void X11EventSourceGlib::StopCurrentEventStream() { + event_source_.StopCurrentEventStream(); +} + +void X11EventSourceGlib::OnDispatcherListChanged() { + event_source_.OnDispatcherListChanged(); +} + +void X11EventSourceGlib::InitXSource(int fd) { + DCHECK(!x_source_); + DCHECK(event_source_.display()) << "Unable to get connection to X server"; + + x_poll_.reset(new GPollFD()); + x_poll_->fd = fd; + x_poll_->events = G_IO_IN; + x_poll_->revents = 0; + + GLibX11Source* glib_x_source = static_cast<GLibX11Source*>( + g_source_new(&XSourceFuncs, sizeof(GLibX11Source))); + glib_x_source->display = event_source_.display(); + glib_x_source->poll_fd = x_poll_.get(); + + x_source_ = glib_x_source; + g_source_add_poll(x_source_, x_poll_.get()); + g_source_set_can_recurse(x_source_, TRUE); + g_source_set_callback(x_source_, NULL, &event_source_, NULL); + g_source_attach(x_source_, g_main_context_default()); +} + +// static scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() { return make_scoped_ptr(new X11EventSourceGlib(gfx::GetXDisplay())); } diff --git a/ui/events/platform/x11/x11_event_source_glib.h b/ui/events/platform/x11/x11_event_source_glib.h new file mode 100644 index 0000000..67a38b1 --- /dev/null +++ b/ui/events/platform/x11/x11_event_source_glib.h @@ -0,0 +1,53 @@ +// 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_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_GLIB_H_ +#define UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_GLIB_H_ + +#include <stdint.h> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "ui/events/events_export.h" +#include "ui/events/platform/platform_event_source.h" +#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/x/x11_types.h" + +typedef struct _GPollFD GPollFD; +typedef struct _GSource GSource; + +namespace ui { + +// A PlatformEventSource implementation for X11. Dispatches XEvents and uses +// Glib to be notified for incoming XEvents. +class EVENTS_EXPORT X11EventSourceGlib : public X11EventSourceDelegate, + public PlatformEventSource { + public: + explicit X11EventSourceGlib(XDisplay* display); + ~X11EventSourceGlib() override; + + // X11EventSourceDelegate: + void ProcessXEvent(XEvent* xevent) override; + + private: + // PlatformEventSource: + void StopCurrentEventStream() override; + void OnDispatcherListChanged() override; + + void InitXSource(int fd); + + X11EventSource event_source_; + + // The GLib event source for X events. + GSource* x_source_ = nullptr; + + // The poll attached to |x_source_|. + scoped_ptr<GPollFD> x_poll_; + + DISALLOW_COPY_AND_ASSIGN(X11EventSourceGlib); +}; + +} // namespace ui + +#endif // UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_GLIB_H_ diff --git a/ui/events/platform/x11/x11_event_source_libevent.cc b/ui/events/platform/x11/x11_event_source_libevent.cc index a3ff7a5..0dfbf3f 100644 --- a/ui/events/platform/x11/x11_event_source_libevent.cc +++ b/ui/events/platform/x11/x11_event_source_libevent.cc @@ -2,67 +2,197 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/x11/x11_event_source_libevent.h" #include <X11/Xlib.h> +#include <X11/extensions/XInput2.h> -#include "base/macros.h" #include "base/message_loop/message_loop.h" -#include "base/message_loop/message_pump_libevent.h" +#include "ui/events/event.h" +#include "ui/events/keycodes/keyboard_code_conversion_x.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/x/events_x_utils.h" namespace ui { namespace { -class X11EventSourceLibevent : public X11EventSource, - public base::MessagePumpLibevent::Watcher { - public: - explicit X11EventSourceLibevent(XDisplay* display) - : X11EventSource(display), - initialized_(false) { - AddEventWatcher(); +// Translates XI2 XEvent into a ui::Event. +scoped_ptr<ui::Event> TranslateXI2EventToEvent(const XEvent& xev) { + EventType event_type = EventTypeFromXEvent(xev); + switch (event_type) { + case ET_KEY_PRESSED: + case ET_KEY_RELEASED: + return make_scoped_ptr(new KeyEvent(event_type, + KeyboardCodeFromXKeyEvent(&xev), + EventFlagsFromXEvent(xev))); + case ET_MOUSE_PRESSED: + case ET_MOUSE_MOVED: + case ET_MOUSE_DRAGGED: + case ET_MOUSE_RELEASED: + return make_scoped_ptr( + new MouseEvent(event_type, EventLocationFromXEvent(xev), + EventSystemLocationFromXEvent(xev), + EventTimeFromXEvent(xev), EventFlagsFromXEvent(xev), + GetChangedMouseButtonFlagsFromXEvent(xev))); + case ET_MOUSEWHEEL: + return make_scoped_ptr(new MouseWheelEvent( + GetMouseWheelOffsetFromXEvent(xev), EventLocationFromXEvent(xev), + EventSystemLocationFromXEvent(xev), EventTimeFromXEvent(xev), + EventFlagsFromXEvent(xev), + GetChangedMouseButtonFlagsFromXEvent(xev))); + case ET_SCROLL_FLING_START: + case ET_SCROLL_FLING_CANCEL: { + float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; + GetFlingDataFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, + &y_offset_ordinal, nullptr); + return make_scoped_ptr(new ScrollEvent( + event_type, EventLocationFromXEvent(xev), EventTimeFromXEvent(xev), + EventFlagsFromXEvent(xev), x_offset, y_offset, x_offset_ordinal, + y_offset_ordinal, 0)); + } + case ET_SCROLL: { + float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; + int finger_count; + GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, + &y_offset_ordinal, &finger_count); + return make_scoped_ptr(new ScrollEvent( + event_type, EventLocationFromXEvent(xev), EventTimeFromXEvent(xev), + EventFlagsFromXEvent(xev), x_offset, y_offset, x_offset_ordinal, + y_offset_ordinal, finger_count)); + } + case ET_TOUCH_MOVED: + case ET_TOUCH_PRESSED: + case ET_TOUCH_CANCELLED: + case ET_TOUCH_RELEASED: + return make_scoped_ptr( + new TouchEvent(event_type, EventLocationFromXEvent(xev), + GetTouchIdFromXEvent(xev), EventTimeFromXEvent(xev))); + case ET_UNKNOWN: + return nullptr; + default: + break; } + return nullptr; +} - ~X11EventSourceLibevent() override { +// Translates a XEvent into a ui::Event. +scoped_ptr<ui::Event> TranslateXEventToEvent(const XEvent& xev) { + int flags = EventFlagsFromXEvent(xev); + switch (xev.type) { + case LeaveNotify: + case EnterNotify: + // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is + // not real mouse move event. + if (xev.type == EnterNotify) + flags |= EF_IS_SYNTHESIZED; + return make_scoped_ptr( + new MouseEvent(ET_MOUSE_MOVED, EventLocationFromXEvent(xev), + EventSystemLocationFromXEvent(xev), + EventTimeFromXEvent(xev), flags, 0)); + + case KeyPress: + case KeyRelease: + return make_scoped_ptr(new KeyEvent( + EventTypeFromXEvent(xev), KeyboardCodeFromXKeyEvent(&xev), flags)); + + case ButtonPress: + case ButtonRelease: { + switch (EventTypeFromXEvent(xev)) { + case ET_MOUSEWHEEL: + return make_scoped_ptr(new MouseWheelEvent( + GetMouseWheelOffsetFromXEvent(xev), EventLocationFromXEvent(xev), + EventSystemLocationFromXEvent(xev), EventTimeFromXEvent(xev), + flags, 0)); + case ET_MOUSE_PRESSED: + case ET_MOUSE_RELEASED: + return make_scoped_ptr(new MouseEvent( + EventTypeFromXEvent(xev), EventLocationFromXEvent(xev), + EventSystemLocationFromXEvent(xev), EventTimeFromXEvent(xev), + flags, GetChangedMouseButtonFlagsFromXEvent(xev))); + case ET_UNKNOWN: + // No event is created for X11-release events for mouse-wheel + // buttons. + break; + default: + NOTREACHED(); + } + break; + } + + case GenericEvent: + return TranslateXI2EventToEvent(xev); } + return nullptr; +} - private: - void AddEventWatcher() { - if (initialized_) - return; - if (!base::MessageLoop::current()) - return; - - int fd = ConnectionNumber(display()); - base::MessageLoopForUI::current()->WatchFileDescriptor(fd, true, - base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, this); - initialized_ = true; - } +} // namespace - // PlatformEventSource: - void OnDispatcherListChanged() override { - AddEventWatcher(); - } +X11EventSourceLibevent::X11EventSourceLibevent(XDisplay* display) + : event_source_(this, display) { + AddEventWatcher(); +} + +X11EventSourceLibevent::~X11EventSourceLibevent() {} - // base::MessagePumpLibevent::Watcher: - void OnFileCanReadWithoutBlocking(int fd) override { - DispatchXEvents(); +void X11EventSourceLibevent::AddXEventDispatcher(XEventDispatcher* dispatcher) { + dispatchers_xevent_.AddObserver(dispatcher); +} + +void X11EventSourceLibevent::RemoveXEventDispatcher( + XEventDispatcher* dispatcher) { + dispatchers_xevent_.RemoveObserver(dispatcher); +} + +void X11EventSourceLibevent::ProcessXEvent(XEvent* xevent) { + scoped_ptr<ui::Event> translated_event = TranslateXEventToEvent(*xevent); + if (translated_event) { + DispatchEvent(translated_event.get()); + } else { + // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent + // directly to XEventDispatchers. + DispatchXEventToXEventDispatchers(xevent); } +} - void OnFileCanWriteWithoutBlocking(int fd) override { - NOTREACHED(); +void X11EventSourceLibevent::AddEventWatcher() { + if (initialized_) + return; + if (!base::MessageLoop::current()) + return; + + int fd = ConnectionNumber(event_source_.display()); + base::MessageLoopForUI::current()->WatchFileDescriptor( + fd, true, base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, + this); + initialized_ = true; +} + +void X11EventSourceLibevent::DispatchXEventToXEventDispatchers(XEvent* xevent) { + if (dispatchers_xevent_.might_have_observers()) { + base::ObserverList<XEventDispatcher>::Iterator iter(&dispatchers_xevent_); + while (XEventDispatcher* dispatcher = iter.GetNext()) { + if (dispatcher->DispatchXEvent(xevent)) + break; + } } +} - base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_; - bool initialized_; +void X11EventSourceLibevent::StopCurrentEventStream() { + event_source_.StopCurrentEventStream(); +} - DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent); -}; +void X11EventSourceLibevent::OnDispatcherListChanged() { + AddEventWatcher(); + event_source_.OnDispatcherListChanged(); +} -} // namespace +void X11EventSourceLibevent::OnFileCanReadWithoutBlocking(int fd) { + event_source_.DispatchXEvents(); +} -scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() { - return make_scoped_ptr(new X11EventSourceLibevent(gfx::GetXDisplay())); +void X11EventSourceLibevent::OnFileCanWriteWithoutBlocking(int fd) { + NOTREACHED(); } } // namespace ui diff --git a/ui/events/platform/x11/x11_event_source_libevent.h b/ui/events/platform/x11/x11_event_source_libevent.h new file mode 100644 index 0000000..b9f2eba --- /dev/null +++ b/ui/events/platform/x11/x11_event_source_libevent.h @@ -0,0 +1,79 @@ +// 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_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_LIBEVENT_H_ +#define UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_LIBEVENT_H_ + +#include "base/macros.h" +#include "base/message_loop/message_pump_libevent.h" +#include "ui/events/events_export.h" +#include "ui/events/platform/platform_event_source.h" +#include "ui/events/platform/x11/x11_event_source.h" + +namespace ui { + +// Interface for classes that want to receive XEvent directly. Only used with +// Ozone X11 currently and only events that can't be translated into ui::Events +// are sent via this path. +class EVENTS_EXPORT XEventDispatcher { + public: + // Sends XEvent to XEventDispatcher for handling. Returns true if the XEvent + // was dispatched, otherwise false. After the first XEventDispatcher returns + // true XEvent dispatching stops. + virtual bool DispatchXEvent(XEvent* xevent) = 0; + + protected: + virtual ~XEventDispatcher() {} +}; + +// A PlatformEventSource implementation for Ozone X11. Converts XEvents to +// ui::Events before dispatching. For X11 specific events a separate list of +// XEventDispatchers is maintained. Uses Libevent to be notified for incoming +// XEvents. +class EVENTS_EXPORT X11EventSourceLibevent + : public X11EventSourceDelegate, + public PlatformEventSource, + public base::MessagePumpLibevent::Watcher { + public: + explicit X11EventSourceLibevent(XDisplay* display); + ~X11EventSourceLibevent() override; + + // Adds a XEvent dispatcher to the XEvent dispatcher list. + void AddXEventDispatcher(XEventDispatcher* dispatcher); + + // Removes a XEvent dispatcher fERrom the XEvent dispatcher list. + void RemoveXEventDispatcher(XEventDispatcher* dispatcher); + + // X11EventSourceDelegate: + void ProcessXEvent(XEvent* xevent) override; + + private: + // Registers event watcher with Libevent. + void AddEventWatcher(); + + // Sends XEvent to registered XEventDispatchers. + void DispatchXEventToXEventDispatchers(XEvent* xevent); + + // PlatformEventSource: + void StopCurrentEventStream() override; + void OnDispatcherListChanged() override; + + // base::MessagePumpLibevent::Watcher: + void OnFileCanReadWithoutBlocking(int fd) override; + void OnFileCanWriteWithoutBlocking(int fd) override; + + X11EventSource event_source_; + + // Keep track of all XEventDispatcher to send XEvents directly to. + base::ObserverList<XEventDispatcher> dispatchers_xevent_; + + base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_; + bool initialized_ = false; + + DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent); +}; + +} // namespace ui + +#endif // UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_LIBEVENT_H_ diff --git a/ui/events/platform/x11/x11_events_platform.gyp b/ui/events/platform/x11/x11_events_platform.gyp index cb1bbcd..a624722 100644 --- a/ui/events/platform/x11/x11_events_platform.gyp +++ b/ui/events/platform/x11/x11_events_platform.gyp @@ -20,13 +20,12 @@ '../../devices/events_devices.gyp:events_devices', '../../events.gyp:events', '../../events.gyp:events_base', + '../../x/events_x.gyp:events_x', '../events_platform.gyp:events_platform', ], 'sources': [ 'x11_event_source.cc', 'x11_event_source.h', - 'x11_event_source_glib.cc', - 'x11_event_source_libevent.cc', 'x11_hotplug_event_handler.cc', 'x11_hotplug_event_handler.h', ], @@ -35,13 +34,15 @@ 'dependencies': [ '../../../../build/linux/system.gyp:glib', ], - 'sources!': [ - 'x11_event_source_libevent.cc', + 'sources': [ + 'x11_event_source_glib.cc', + 'x11_event_source_glib.h', ], }, { # use_glib == 0 - 'sources!': [ - 'x11_event_source_glib.cc', + 'sources': [ + 'x11_event_source_libevent.cc', + 'x11_event_source_libevent.h', ], }], ], diff --git a/ui/events/x/BUILD.gn b/ui/events/x/BUILD.gn index 2329946..991ce6e 100644 --- a/ui/events/x/BUILD.gn +++ b/ui/events/x/BUILD.gn @@ -16,8 +16,5 @@ component("x") { "//ui/events/devices", "//ui/gfx/x", ] - configs += [ - "//build/config/linux:glib", - "//build/config/linux:x11", - ] + configs += [ "//build/config/linux:x11" ] } diff --git a/ui/events/x/events_x_utils.h b/ui/events/x/events_x_utils.h index 15c4e38..0a07061 100644 --- a/ui/events/x/events_x_utils.h +++ b/ui/events/x/events_x_utils.h @@ -16,16 +16,16 @@ typedef union _XEvent XEvent; namespace ui { -// Get the EventType from a XEvent. +// Gets the EventType from a XEvent. EVENTS_X_EXPORT EventType EventTypeFromXEvent(const XEvent& xev); -// Get the EventFlags from a XEvent. +// Gets the EventFlags from a XEvent. EVENTS_X_EXPORT int EventFlagsFromXEvent(const XEvent& xev); -// Get the timestamp from a XEvent. +// Gets the timestamp from a XEvent. EVENTS_X_EXPORT base::TimeDelta EventTimeFromXEvent(const XEvent& xev); -// Get the location from a XEvent. The coordinate system of the resultant +// Gets the location from a XEvent. The coordinate system of the resultant // |Point| has the origin at top-left of the "root window". The nature of // this "root window" and how it maps to platform-specific drawing surfaces is // defined in ui/aura/root_window.* and ui/aura/window_tree_host*. diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn index b853381..fdffd9f 100644 --- a/ui/ozone/platform/x11/BUILD.gn +++ b/ui/ozone/platform/x11/BUILD.gn @@ -22,11 +22,13 @@ source_set("x11") { "//ui/events/devices", "//ui/events/ozone:events_ozone", "//ui/events/platform", + "//ui/events/platform/x11", "//ui/events/x", "//ui/gfx", "//ui/gfx/geometry", "//ui/gfx/x", "//ui/ozone:ozone_base", + "//ui/platform_window/x11", ] configs += [ "//build/config/linux:x11" ] diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc index 9dca688..34db2f3 100644 --- a/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/ui/ozone/platform/x11/ozone_platform_x11.cc @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" +#include "ui/events/platform/x11/x11_event_source_libevent.h" #include "ui/ozone/common/native_display_delegate_ozone.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/platform/x11/x11_surface_factory.h" @@ -17,6 +18,7 @@ #include "ui/ozone/public/ozone_platform.h" // nogncheck #include "ui/ozone/public/system_input_injector.h" #include "ui/platform_window/platform_window.h" +#include "ui/platform_window/x11/x11_window_ozone.h" namespace ui { @@ -60,9 +62,11 @@ class OzonePlatformX11 : public OzonePlatform { scoped_ptr<PlatformWindow> CreatePlatformWindow( PlatformWindowDelegate* delegate, const gfx::Rect& bounds) override { - // TODO(kylechar): Add PlatformWindow creation here. - NOTREACHED(); - return nullptr; + scoped_ptr<X11WindowOzone> window = + make_scoped_ptr(new X11WindowOzone(event_source_.get(), delegate)); + window->SetBounds(bounds); + window->Create(); + return std::move(window); } scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override { @@ -74,7 +78,7 @@ class OzonePlatformX11 : public OzonePlatform { } void InitializeUI() override { - // TODO(kylechar): Add PlatformEventSource creation here. + event_source_.reset(new X11EventSourceLibevent(gfx::GetXDisplay())); surface_factory_ozone_.reset(new X11SurfaceFactory()); overlay_manager_.reset(new StubOverlayManager()); input_controller_ = CreateStubInputController(); @@ -89,6 +93,7 @@ class OzonePlatformX11 : public OzonePlatform { private: // Objects in the Browser process. + scoped_ptr<X11EventSourceLibevent> event_source_; scoped_ptr<OverlayManagerOzone> overlay_manager_; scoped_ptr<InputController> input_controller_; scoped_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_; 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_ diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc index 162cf3c..327c3d5 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc @@ -24,7 +24,7 @@ #include "ui/base/hit_test.h" #include "ui/base/x/x11_util.h" #include "ui/events/devices/x11/touch_factory_x11.h" -#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/x11/x11_event_source_glib.h" #include "ui/events/test/platform_event_source_test_api.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc index a33f12f..34eb824 100644 --- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc +++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc @@ -22,6 +22,7 @@ #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_code_conversion_x.h" +#include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/scoped_event_dispatcher.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/views/widget/desktop_aura/x11_pointer_grab.h" |