#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/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "build/build_config.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h"
#include "ui/base/x/x11_cursor_factory.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/types/native_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/gbm_support_x11.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/atom_cache.h"
#include "ui/gfx/x/visual_manager.h"
#include "ui/linux/linux_ui_delegate.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
#include "ui/ozone/platform/x11/linux_ui_delegate_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.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/platform/x11/x11_window.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/stub_input_controller.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"
#if BUILDFLAG(IS_CHROMEOS)
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/base/ime/ash/input_method_ash.h"
#else
#include "ui/base/ime/linux/input_method_auralinux.h"
#include "ui/ozone/platform/x11/os_exchange_data_provider_x11.h"
#endif
namespace ui {
namespace {
bool g_multi_threaded_message_loop = false;
class OzonePlatformX11 : public OzonePlatform,
public OSExchangeDataProviderFactoryOzone {
public:
OzonePlatformX11() { SetInstance(this); }
OzonePlatformX11(const OzonePlatformX11&) = delete;
OzonePlatformX11& operator=(const OzonePlatformX11&) = delete;
~OzonePlatformX11() override = default;
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));
return std::move(window);
}
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
override {
return nullptr;
}
std::unique_ptr<PlatformScreen> CreateScreen() override {
return std::make_unique<X11ScreenOzone>();
}
void InitScreen(PlatformScreen* screen) override {
static_cast<X11ScreenOzone*>(screen)->Init();
}
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(
ImeKeyEventDispatcher* ime_key_event_dispatcher,
gfx::AcceleratedWidget widget) override {
#if BUILDFLAG(IS_CHROMEOS)
return std::make_unique<ash::InputMethodAsh>(ime_key_event_dispatcher);
#else
return std::make_unique<InputMethodAuraLinux>(ime_key_event_dispatcher,
widget);
#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,
std::optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget) override {
switch (type) {
case PlatformKeyboardHookTypes::kModifier:
return std::make_unique<X11KeyboardHook>(
std::move(dom_codes), std::move(callback), accelerated_widget);
case PlatformKeyboardHookTypes::kMedia:
return nullptr;
}
}
std::unique_ptr<OSExchangeDataProvider> CreateProvider() override {
#if BUILDFLAG(IS_CHROMEOS)
return std::make_unique<OSExchangeDataProviderNonBacked>();
#else
return std::make_unique<OSExchangeDataProviderX11>();
#endif
}
const PlatformProperties& GetPlatformProperties() override {
using SupportsForTest = OzonePlatform::PlatformProperties::SupportsForTest;
const auto& override_set_parent_for_non_top_level_windows_for_test =
OzonePlatform::PlatformProperties::
override_set_parent_for_non_top_level_windows_for_test;
static base::NoDestructor<OzonePlatform::PlatformProperties> properties;
static bool initialised = false;
if (!initialised) {
properties->custom_frame_pref_default = ui::GetCustomFramePrefDefault();
properties->message_pump_type_for_gpu = base::MessagePumpType::UI;
properties->message_pump_type_for_viz_compositor =
base::MessagePumpType::UI;
properties->supports_vulkan_swap_chain = true;
properties->skia_can_fall_back_to_x11 = true;
properties->platform_shows_drag_image = false;
properties->app_modal_dialogs_use_event_blocker = true;
properties->set_parent_for_non_top_level_windows =
override_set_parent_for_non_top_level_windows_for_test ==
SupportsForTest::kYes;
initialised = true;
}
return *properties;
}
const PlatformRuntimeProperties& GetPlatformRuntimeProperties() override {
static OzonePlatform::PlatformRuntimeProperties properties;
if (has_initialized_gpu() &&
ui::GBMSupportX11::GetInstance()->has_gbm_device()) {
properties.supports_native_pixmaps = true;
}
properties.supports_subwindows_as_accelerated_widgets = false;
properties.supports_system_tray_windowing = true;
properties.supports_server_window_menus =
x11::Connection::Get()->WmSupportsHint(
x11::GetAtom("_GTK_SHOW_WINDOW_MENU"));
properties.supports_global_application_menus = true;
return properties;
}
bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
gfx::BufferUsage usage) const override {
return false;
}
bool IsWindowCompositingSupported() const override {
return x11::Connection::Get()
->GetOrCreateVisualManager()
.ArgbVisualAvailable();
}
bool InitializeUI(const InitParams& params) override {
if (ShouldFailInitializeUIForTest()) {
LOG(ERROR) << "Failing for test";
return false;
}
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kHeadless) &&
!x11::Connection::Get()->Ready()) {
LOG(ERROR) << "Missing X server or $DISPLAY";
return false;
}
InitializeCommon(params);
CreatePlatformEventSource();
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = std::make_unique<StubInputController>();
clipboard_ = std::make_unique<X11ClipboardOzone>();
cursor_factory_ = std::make_unique<X11CursorFactory>();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>();
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
keyboard_layout_engine_.get());
TouchFactory::SetTouchDeviceListFromCommandLine();
#if BUILDFLAG(USE_GTK)
if (!g_multi_threaded_message_loop) {
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());
base::UmaHistogramBoolean(
"Linux.X11.XInput2",
x11::Connection::Get()->xinput_version().first == 2);
return true;
}
void InitializeGPU(const InitParams& params) override {
InitializeCommon(params);
if (params.enable_native_gpu_memory_buffers) {
base::ThreadPool::PostTask(FROM_HERE, base::BindOnce([]() {
ui::GBMSupportX11::GetInstance();
}));
}
if (!params.single_process)
CreatePlatformEventSource();
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,
scoped_refptr<base::SingleThreadTaskRunner>) override {
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:
void InitializeCommon(const InitParams& params) {
if (common_initialized_)
return;
common_initialized_ = true;
}
void CreatePlatformEventSource() {
if (event_source_)
return;
auto* connection = x11::Connection::Get();
event_source_ = std::make_unique<X11EventSource>(connection);
}
bool common_initialized_ = false;
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_;
std::unique_ptr<X11SurfaceFactory> surface_factory_ozone_;
std::unique_ptr<GLEGLUtilityX11> gl_egl_utility_;
std::unique_ptr<X11EventSource> event_source_;
#if BUILDFLAG(USE_GTK)
std::unique_ptr<LinuxUiDelegate> linux_ui_delegate_;
#endif
};
}
OzonePlatform* CreateOzonePlatformX11() {
return new OzonePlatformX11;
}
void SetMultiThreadedMessageLoopX11() {
g_multi_threaded_message_loop = true;
}
}