| // 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/ozone/platform/x11/ozone_platform_x11.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/message_loop/message_pump_type.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/no_destructor.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/thread_pool.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "ui/base/buildflags.h" |
| #include "ui/base/cursor/cursor_factory.h" |
| #include "ui/base/dragdrop/os_exchange_data_provider_factory.h" |
| #include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h" |
| #include "ui/base/ime/linux/linux_input_method_context_factory.h" |
| #include "ui/base/linux/linux_ui_delegate.h" |
| #include "ui/base/x/x11_cursor_factory.h" |
| #include "ui/base/x/x11_util.h" |
| #include "ui/display/fake/fake_display_delegate.h" |
| #include "ui/events/devices/x11/touch_factory_x11.h" |
| #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" |
| #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" |
| #include "ui/events/platform/x11/x11_event_source.h" |
| #include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/gfx/switches.h" |
| #include "ui/ozone/common/stub_overlay_manager.h" |
| #include "ui/ozone/platform/x11/gl_egl_utility_x11.h" |
| #include "ui/ozone/platform/x11/x11_clipboard_ozone.h" |
| #include "ui/ozone/platform/x11/x11_global_shortcut_listener_ozone.h" |
| #include "ui/ozone/platform/x11/x11_keyboard_hook_ozone.h" |
| #include "ui/ozone/platform/x11/x11_menu_utils.h" |
| #include "ui/ozone/platform/x11/x11_screen_ozone.h" |
| #include "ui/ozone/platform/x11/x11_surface_factory.h" |
| #include "ui/ozone/platform/x11/x11_user_input_monitor.h" |
| #include "ui/ozone/platform/x11/x11_utils.h" |
| #include "ui/ozone/public/gpu_platform_support_host.h" |
| #include "ui/ozone/public/input_controller.h" |
| #include "ui/ozone/public/ozone_platform.h" |
| #include "ui/ozone/public/system_input_injector.h" |
| #include "ui/platform_window/platform_window.h" |
| #include "ui/platform_window/platform_window_init_properties.h" |
| #include "ui/platform_window/x11/x11_window.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h" |
| #include "ui/base/ime/chromeos/input_method_chromeos.h" |
| #else |
| #include "ui/base/ime/linux/input_method_auralinux.h" |
| #include "ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h" |
| #endif |
| |
| namespace ui { |
| |
| namespace { |
| |
| class LinuxUiDelegateX11 : public LinuxUiDelegate { |
| public: |
| ~LinuxUiDelegateX11() override = default; |
| |
| // LinuxUiDelegate: |
| LinuxUiBackend GetBackend() const override { return LinuxUiBackend::kX11; } |
| }; |
| |
| // Singleton OzonePlatform implementation for X11 platform. |
| class OzonePlatformX11 : public OzonePlatform, |
| public ui::OSExchangeDataProviderFactoryOzone { |
| public: |
| OzonePlatformX11() { SetInstance(this); } |
| |
| ~OzonePlatformX11() override = default; |
| |
| // OzonePlatform: |
| ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override { |
| return surface_factory_ozone_.get(); |
| } |
| |
| ui::OverlayManagerOzone* GetOverlayManager() override { |
| return overlay_manager_.get(); |
| } |
| |
| CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); } |
| |
| std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override { |
| return nullptr; |
| } |
| |
| InputController* GetInputController() override { |
| return input_controller_.get(); |
| } |
| |
| GpuPlatformSupportHost* GetGpuPlatformSupportHost() override { |
| return gpu_platform_support_host_.get(); |
| } |
| |
| std::unique_ptr<PlatformWindow> CreatePlatformWindow( |
| PlatformWindowDelegate* delegate, |
| PlatformWindowInitProperties properties) override { |
| auto window = std::make_unique<X11Window>(delegate); |
| window->Initialize(std::move(properties)); |
| window->SetTitle(u"Ozone X11"); |
| return std::move(window); |
| } |
| |
| std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate() |
| override { |
| return std::make_unique<display::FakeDisplayDelegate>(); |
| } |
| |
| std::unique_ptr<PlatformScreen> CreateScreen() override { |
| auto screen = std::make_unique<X11ScreenOzone>(); |
| screen->Init(); |
| return screen; |
| } |
| |
| PlatformClipboard* GetPlatformClipboard() override { |
| return clipboard_.get(); |
| } |
| |
| PlatformGLEGLUtility* GetPlatformGLEGLUtility() override { |
| if (!gl_egl_utility_) |
| gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>(); |
| return gl_egl_utility_.get(); |
| } |
| |
| std::unique_ptr<InputMethod> CreateInputMethod( |
| internal::InputMethodDelegate* delegate, |
| gfx::AcceleratedWidget) override { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| return std::make_unique<InputMethodChromeOS>(delegate); |
| #else |
| // This method is used by upper layer components (e.g: GtkUi) to determine |
| // if the LinuxInputMethodContextFactory instance is provided by the Ozone |
| // platform implementation, so we must consider the case that it is still |
| // not set at this point. |
| if (!ui::LinuxInputMethodContextFactory::instance()) |
| return nullptr; |
| return std::make_unique<InputMethodAuraLinux>(delegate); |
| #endif |
| } |
| |
| PlatformMenuUtils* GetPlatformMenuUtils() override { |
| return menu_utils_.get(); |
| } |
| |
| PlatformUtils* GetPlatformUtils() override { return x11_utils_.get(); } |
| |
| PlatformGlobalShortcutListener* GetPlatformGlobalShortcutListener( |
| PlatformGlobalShortcutListenerDelegate* delegate) override { |
| if (!global_shortcut_listener_) { |
| global_shortcut_listener_ = |
| std::make_unique<X11GlobalShortcutListenerOzone>(delegate); |
| } |
| return global_shortcut_listener_.get(); |
| } |
| |
| std::unique_ptr<PlatformKeyboardHook> CreateKeyboardHook( |
| PlatformKeyboardHookTypes type, |
| base::RepeatingCallback<void(KeyEvent* event)> callback, |
| absl::optional<base::flat_set<DomCode>> dom_codes, |
| gfx::AcceleratedWidget accelerated_widget) override { |
| switch (type) { |
| case PlatformKeyboardHookTypes::kModifier: |
| return std::make_unique<X11KeyboardHookOzone>( |
| std::move(dom_codes), std::move(callback), accelerated_widget); |
| case PlatformKeyboardHookTypes::kMedia: |
| return nullptr; |
| } |
| } |
| |
| std::unique_ptr<OSExchangeDataProvider> CreateProvider() override { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| return std::make_unique<OSExchangeDataProviderNonBacked>(); |
| #else |
| return std::make_unique<X11OSExchangeDataProviderOzone>(); |
| #endif |
| } |
| |
| const PlatformProperties& GetPlatformProperties() override { |
| static base::NoDestructor<OzonePlatform::PlatformProperties> properties; |
| static bool initialised = false; |
| if (!initialised) { |
| properties->custom_frame_pref_default = ui::GetCustomFramePrefDefault(); |
| |
| // When the Ozone X11 backend is running, use a UI loop to grab Expose |
| // events. See GLSurfaceGLX and https://crbug.com/326995. |
| properties->message_pump_type_for_gpu = base::MessagePumpType::UI; |
| // When the Ozone X11 backend is running, use a UI loop to dispatch |
| // SHM completion events. |
| properties->message_pump_type_for_viz_compositor = |
| base::MessagePumpType::UI; |
| properties->supports_vulkan_swap_chain = true; |
| properties->uses_external_vulkan_image_factory = true; |
| properties->skia_can_fall_back_to_x11 = true; |
| properties->platform_shows_drag_image = false; |
| properties->supports_global_application_menus = true; |
| properties->app_modal_dialogs_use_event_blocker = true; |
| properties->fetch_buffer_formats_for_gmb_on_gpu = true; |
| |
| initialised = true; |
| } |
| |
| return *properties; |
| } |
| |
| bool IsNativePixmapConfigSupported(gfx::BufferFormat format, |
| gfx::BufferUsage usage) const override { |
| // Native pixmap support is determined on gpu process via gpu extra info |
| // that gets this information from GpuMemoryBufferSupportX11. |
| return false; |
| } |
| |
| void InitializeUI(const InitParams& params) override { |
| // If opening the connection failed there is nothing we can do. Crash here |
| // instead of crashing later. If you are crashing here, make sure there is |
| // an X server running and $DISPLAY is set. |
| // In case of non-Ozone/X11, the very same check happens during the |
| // BrowserMainLoop::InitializeToolkit call. |
| if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) |
| CHECK(x11::Connection::Get()->Ready()) << "Missing X server or $DISPLAY"; |
| |
| InitializeCommon(params); |
| CreatePlatformEventSource(); |
| overlay_manager_ = std::make_unique<StubOverlayManager>(); |
| input_controller_ = CreateStubInputController(); |
| clipboard_ = std::make_unique<X11ClipboardOzone>(); |
| cursor_factory_ = std::make_unique<X11CursorFactory>(); |
| gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); |
| |
| // TODO(crbug.com/987939): Support XKB. |
| keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>(); |
| KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( |
| keyboard_layout_engine_.get()); |
| |
| TouchFactory::SetTouchDeviceListFromCommandLine(); |
| |
| #if BUILDFLAG(USE_GTK) |
| linux_ui_delegate_ = std::make_unique<LinuxUiDelegateX11>(); |
| #endif |
| |
| menu_utils_ = std::make_unique<X11MenuUtils>(); |
| x11_utils_ = std::make_unique<X11Utils>(); |
| |
| base::UmaHistogramEnumeration("Linux.WindowManager", GetWindowManagerUMA()); |
| } |
| |
| void InitializeGPU(const InitParams& params) override { |
| InitializeCommon(params); |
| if (params.enable_native_gpu_memory_buffers) { |
| base::ThreadPool::PostTask( |
| FROM_HERE, base::BindOnce([]() { |
| SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime"); |
| ui::GpuMemoryBufferSupportX11::GetInstance(); |
| })); |
| } |
| // In single process mode either the UI thread will create an event source |
| // or it's a test and an event source isn't desired. |
| if (!params.single_process) |
| CreatePlatformEventSource(); |
| |
| // Set up the X11 connection before the sandbox gets set up. This cannot be |
| // done later since opening the connection requires socket() and connect(). |
| auto connection = x11::Connection::Get()->Clone(); |
| connection->DetachFromSequence(); |
| surface_factory_ozone_ = |
| std::make_unique<X11SurfaceFactory>(std::move(connection)); |
| } |
| |
| void PostCreateMainMessageLoop( |
| base::OnceCallback<void()> shutdown_cb) override { |
| // Installs the X11 error handlers for the UI process after the |
| // main message loop has started. This will allow us to exit cleanly |
| // if X exits before we do. |
| x11::Connection::Get()->SetIOErrorHandler(std::move(shutdown_cb)); |
| } |
| |
| std::unique_ptr<PlatformUserInputMonitor> GetPlatformUserInputMonitor( |
| const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
| override { |
| return std::make_unique<X11UserInputMonitor>(std::move(io_task_runner)); |
| } |
| |
| private: |
| // Performs initialization steps need by both UI and GPU. |
| void InitializeCommon(const InitParams& params) { |
| if (common_initialized_) |
| return; |
| |
| common_initialized_ = true; |
| } |
| |
| // Creates |event_source_| if it doesn't already exist. |
| void CreatePlatformEventSource() { |
| if (event_source_) |
| return; |
| |
| auto* connection = x11::Connection::Get(); |
| event_source_ = std::make_unique<X11EventSource>(connection); |
| } |
| |
| bool common_initialized_ = false; |
| |
| // Objects in the UI process. |
| std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_; |
| std::unique_ptr<OverlayManagerOzone> overlay_manager_; |
| std::unique_ptr<InputController> input_controller_; |
| std::unique_ptr<X11ClipboardOzone> clipboard_; |
| std::unique_ptr<CursorFactory> cursor_factory_; |
| std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_; |
| std::unique_ptr<X11MenuUtils> menu_utils_; |
| std::unique_ptr<X11Utils> x11_utils_; |
| std::unique_ptr<PlatformGlobalShortcutListener> global_shortcut_listener_; |
| |
| // Objects in the GPU process. |
| std::unique_ptr<X11SurfaceFactory> surface_factory_ozone_; |
| std::unique_ptr<GLEGLUtilityX11> gl_egl_utility_; |
| |
| // Objects in both UI and GPU process. |
| std::unique_ptr<X11EventSource> event_source_; |
| |
| #if BUILDFLAG(USE_GTK) |
| std::unique_ptr<LinuxUiDelegate> linux_ui_delegate_; |
| #endif |
| |
| DISALLOW_COPY_AND_ASSIGN(OzonePlatformX11); |
| }; |
| |
| } // namespace |
| |
| OzonePlatform* CreateOzonePlatformX11() { |
| return new OzonePlatformX11; |
| } |
| |
| } // namespace ui |