Phase 0: browser X11-overlay inventory + mpv reference cell + tooling installs

Source-level verdict: no browser in the matrix has a code path
to hand NV12 to the X server for plane scanout. Chromium ozone-x11
wires StubOverlayManager (ozone_platform_x11.cc:262); Brave 147 +
chromium-fourier 149 inherit unchanged. Firefox WindowSurfaceX11
is RGB-only. The campaign's load-bearing hypothesis is structurally
weakened — what the X11 cells will measure for browsers is
KWin's per-frame RGB-recomposite cost, not the original
"force-GL-composite of NV12" framing. mpv --vo=xv becomes the
matrix's only direct test of the operator-supplied mechanism.

Matrix updated: 12 cells -> 16 cells (+8 mpv VO sub-points).
revert.log entries 1-5 capture all package + per-user state
mutations from this turn (measurement tools, openbox, XFCE +
xfwm4-no-comp pre-seed, firefox + AUR xtrace, XFCE rotation
+ touchscreen mapping); single SSH-driveable revert chain
returns ohm to its pre-campaign 1169-package state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 11:14:46 +00:00
parent 5d34a957ee
commit d2e11be430
30 changed files with 13176 additions and 35 deletions
@@ -0,0 +1,24 @@
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/common/stub_overlay_manager.h"
#include <memory>
#include "ui/ozone/public/overlay_candidates_ozone.h"
namespace ui {
StubOverlayManager::StubOverlayManager() {
}
StubOverlayManager::~StubOverlayManager() {
}
std::unique_ptr<OverlayCandidatesOzone>
StubOverlayManager::CreateOverlayCandidates(gfx::AcceleratedWidget w) {
return nullptr;
}
} // namespace ui
@@ -0,0 +1,30 @@
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
#define UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
#include <memory>
#include "ui/ozone/public/overlay_manager_ozone.h"
namespace ui {
class StubOverlayManager : public OverlayManagerOzone {
public:
StubOverlayManager();
StubOverlayManager(const StubOverlayManager&) = delete;
StubOverlayManager& operator=(const StubOverlayManager&) = delete;
~StubOverlayManager() override;
// OverlayManagerOzone:
std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget w) override;
};
} // namespace ui
#endif // UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
@@ -0,0 +1,204 @@
# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
import("//gpu/vulkan/features.gni")
import("//ui/base/ui_features.gni")
visibility = [ "//ui/ozone/*" ]
assert(is_linux || is_chromeos)
source_set("x11") {
sources = [
"client_native_pixmap_factory_x11.cc",
"client_native_pixmap_factory_x11.h",
"gl_egl_utility_x11.cc",
"gl_egl_utility_x11.h",
"gl_surface_egl_readback_x11.cc",
"gl_surface_egl_readback_x11.h",
"hit_test_x11.cc",
"hit_test_x11.h",
"native_pixmap_egl_x11_binding.cc",
"native_pixmap_egl_x11_binding.h",
"os_exchange_data_provider_x11.cc",
"os_exchange_data_provider_x11.h",
"ozone_platform_x11.cc",
"ozone_platform_x11.h",
"x11_canvas_surface.cc",
"x11_canvas_surface.h",
"x11_clipboard_ozone.cc",
"x11_clipboard_ozone.h",
"x11_global_shortcut_listener_ozone.cc",
"x11_global_shortcut_listener_ozone.h",
"x11_keyboard_hook.cc",
"x11_keyboard_hook.h",
"x11_menu_utils.cc",
"x11_menu_utils.h",
"x11_screen_ozone.cc",
"x11_screen_ozone.h",
"x11_surface_factory.cc",
"x11_surface_factory.h",
"x11_user_input_monitor.cc",
"x11_user_input_monitor.h",
"x11_utils.cc",
"x11_utils.h",
"x11_window.cc",
"x11_window.h",
"x11_window_manager.cc",
"x11_window_manager.h",
]
deps = [
"//base",
"//build:chromecast_buildflags",
"//components/viz/common/resources:shared_image_format",
"//gpu/vulkan:buildflags",
"//net",
"//skia",
"//third_party/angle:includes",
"//ui/base",
"//ui/base:buildflags",
"//ui/base:data_exchange",
"//ui/base:hit_test",
"//ui/base:wm_role_names",
"//ui/base/clipboard:clipboard_types",
"//ui/base/cursor",
"//ui/base/data_transfer_policy",
"//ui/base/dragdrop:types",
"//ui/base/dragdrop/mojom",
"//ui/base/ime",
"//ui/base/x",
"//ui/base/x:gl",
"//ui/display/types",
"//ui/events",
"//ui/events:dom_keycode_converter",
"//ui/events/devices",
"//ui/events/devices/x11",
"//ui/events/ozone",
"//ui/events/ozone/layout",
"//ui/events/platform",
"//ui/events/platform/x11",
"//ui/events/x",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/gfx/linux:gbm",
"//ui/gfx/linux:gbm_support_x11",
"//ui/gfx/x",
"//ui/gl",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
"//ui/platform_window",
"//ui/platform_window/common",
"//ui/platform_window/wm",
]
if (is_linux) {
sources += [
"linux_ui_delegate_x11.cc",
"linux_ui_delegate_x11.h",
]
deps += [
"//components/dbus",
"//ui/base/clipboard:clipboard_util_linux",
"//ui/linux:linux_ui",
]
}
if (is_chromeos) {
deps += [ "//ui/base/ime/ash" ]
} else {
deps += [ "//ui/base/ime/linux" ]
}
if (enable_vulkan) {
sources += [
"vulkan_implementation_x11.cc",
"vulkan_implementation_x11.h",
"vulkan_surface_x11.cc",
"vulkan_surface_x11.h",
]
deps += [ "//gpu/vulkan" ]
}
if (use_xkbcommon) {
configs += [ "//ui/events/ozone/layout:xkbcommon" ]
}
if (use_atk) {
sources += [
"atk_event_conversion.cc",
"atk_event_conversion.h",
]
configs += [ "//build/config/linux/atk" ]
deps += [ "//ui/events/x" ]
}
}
source_set("x11_unittests") {
testonly = true
sources = [
"test/device_data_manager_x11_unittest.cc",
"test/events_x_unittest.cc",
"test/x11_event_translation_unittest.cc",
"test/x11_window_unittest.cc",
"x11_screen_ozone_unittest.cc",
"x11_window_ozone_unittest.cc",
]
deps = [
":x11",
"//base",
"//base/test:test_support",
"//skia",
"//testing/gmock",
"//testing/gtest",
"//ui/base",
"//ui/base:features",
"//ui/base/dragdrop:types",
"//ui/base/x",
"//ui/base/x:test_support",
"//ui/base/x:unittests",
"//ui/display:test_support",
"//ui/events:test_support",
"//ui/events/devices/x11",
"//ui/events/platform/x11",
"//ui/events/x",
"//ui/gfx:test_support",
"//ui/gfx/x",
"//ui/gfx/x:unit_test",
"//ui/ozone:platform",
"//ui/ozone:test_support",
"//ui/ozone/common",
]
if (!is_chromeos) {
sources += [ "test/os_exchange_data_provider_x11_unittest.cc" ]
deps += [ "//ui/base/clipboard:clipboard_types" ]
# ChromeOS uses a non-backed exchange data provider while the tests actually
# expect to use a normal X11 provider. Running these tests with a non-backed
# provided results in crashes when ownership selection call is made.
# Moreover, X11 on ChromeOS is used only for dev purposes and it doesn't
# support DnD between X11 windows. Instead, all the dnd operations are
# performed within a single native windows, where ash spawns number of own
# internal windows.
sources += [ "test/x11_drag_drop_client_unittest.cc" ]
}
}
source_set("test_support") {
testonly = true
sources = [
"x11_ozone_ui_controls_test_helper.cc",
"x11_ozone_ui_controls_test_helper.h",
]
deps = [
"//ui/aura",
"//ui/base/x",
"//ui/base/x:test_support",
]
}
@@ -0,0 +1,16 @@
include_rules = [
"+components/dbus",
"+components/viz/common/resources/shared_image_format.h",
"+components/viz/common/resources/shared_image_format_utils.h",
"+dbus/bus.h",
"+net/base/network_interfaces.h",
"+ui/base/x",
"+ui/base",
"+ui/linux",
]
specific_include_rules = {
"x11_ozone_ui_controls_test_helper.cc": [
"+ui/aura",
]
}
@@ -0,0 +1,375 @@
// Copyright 2016 The Chromium Authors
// 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/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 {
// Singleton OzonePlatform implementation for X11 platform.
class OzonePlatformX11 : public OzonePlatform,
public OSExchangeDataProviderFactoryOzone {
public:
OzonePlatformX11() { SetInstance(this); }
OzonePlatformX11(const OzonePlatformX11&) = delete;
OzonePlatformX11& operator=(const OzonePlatformX11&) = delete;
~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));
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 {
// InitScreen is always called with the same screen that CreateScreen
// hands back, so it is safe to cast here.
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();
// 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->skia_can_fall_back_to_x11 = true;
properties->platform_shows_drag_image = false;
properties->app_modal_dialogs_use_event_blocker = true;
// Defaults to false unless explicitly enabled for testing.
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()) {
// This property is set when the GetPlatformRuntimeProperties is
// called on the gpu process side.
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(viz::SharedImageFormat 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 opening the connection failed, we can not do anything. The platform
// cannot initialise.
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());
// TODO(crbug.com/41472924): 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());
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();
}));
}
// 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,
scoped_refptr<base::SingleThreadTaskRunner>) 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
};
} // namespace
OzonePlatform* CreateOzonePlatformX11() {
return new OzonePlatformX11;
}
} // namespace ui
@@ -0,0 +1,17 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_
#define UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_
namespace ui {
class OzonePlatform;
// Constructor hook for use in ozone_platform_list.cc
OzonePlatform* CreateOzonePlatformX11();
} // namespace ui
#endif // UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_
@@ -0,0 +1,267 @@
// Copyright 2016 The Chromium Authors
// 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/x11_surface_factory.h"
#include <memory>
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/vulkan/buildflags.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/linux/gbm_buffer.h"
#include "ui/gfx/linux/gbm_support_x11.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_egl_x11_gles2.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
#include "ui/ozone/common/native_pixmap_egl_binding.h"
#include "ui/ozone/platform/x11/gl_surface_egl_readback_x11.h"
#include "ui/ozone/platform/x11/native_pixmap_egl_x11_binding.h"
#include "ui/ozone/platform/x11/x11_canvas_surface.h"
#if BUILDFLAG(ENABLE_VULKAN)
#include "ui/ozone/platform/x11/vulkan_implementation_x11.h"
#endif
namespace ui {
namespace {
enum class NativePixmapSupportType {
// Importing native pixmaps not supported.
kNone,
// Native pixmaps are imported directly into EGL using the
// EGL_EXT_image_dma_buf_import extension.
kDMABuf,
// Native pixmaps are first imported as X11 pixmaps using DRI3 and then into
// EGL.
kX11Pixmap,
};
NativePixmapSupportType GetNativePixmapSupportType() {
if (gl::GLSurfaceEGL::GetGLDisplayEGL()
->ext->b_EGL_EXT_image_dma_buf_import) {
return NativePixmapSupportType::kDMABuf;
} else if (NativePixmapEGLX11Binding::CanImportNativeGLXPixmap()) {
return NativePixmapSupportType::kX11Pixmap;
} else {
return NativePixmapSupportType::kNone;
}
}
class GLOzoneEGLX11 : public GLOzoneEGL {
public:
GLOzoneEGLX11() = default;
GLOzoneEGLX11(const GLOzoneEGLX11&) = delete;
GLOzoneEGLX11& operator=(const GLOzoneEGLX11&) = delete;
~GLOzoneEGLX11() override = default;
// GLOzone:
bool InitializeStaticGLBindings(
const gl::GLImplementationParts& implementation) override {
is_swiftshader_ = gl::IsSoftwareGLImplementation(implementation);
return GLOzoneEGL::InitializeStaticGLBindings(implementation);
}
bool CanImportNativePixmap(viz::SharedImageFormat format) override {
if (GetNativePixmapSupportType() == NativePixmapSupportType::kNone) {
return false;
}
switch (GetNativePixmapSupportType()) {
case NativePixmapSupportType::kDMABuf: {
return NativePixmapEGLBinding::IsSharedImageFormatSupported(format);
}
case NativePixmapSupportType::kX11Pixmap: {
return NativePixmapEGLX11Binding::IsSharedImageFormatSupported(format);
}
default:
return false;
}
}
scoped_refptr<gl::GLSurface> CreateViewGLSurface(
gl::GLDisplay* display,
gfx::AcceleratedWidget window) override {
if (is_swiftshader_) {
return gl::InitializeGLSurface(
base::MakeRefCounted<GLSurfaceEglReadbackX11>(
display->GetAs<gl::GLDisplayEGL>(), window));
} else {
switch (gl::GetGLImplementation()) {
case gl::kGLImplementationEGLGLES2:
DCHECK(window != gfx::kNullAcceleratedWidget);
return gl::InitializeGLSurface(new gl::NativeViewGLSurfaceEGLX11GLES2(
display->GetAs<gl::GLDisplayEGL>(),
static_cast<x11::Window>(window)));
case gl::kGLImplementationEGLANGLE:
DCHECK(window != gfx::kNullAcceleratedWidget);
return gl::InitializeGLSurface(new gl::NativeViewGLSurfaceEGLX11(
display->GetAs<gl::GLDisplayEGL>(),
static_cast<x11::Window>(window)));
default:
NOTREACHED();
}
}
}
scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface(
gl::GLDisplay* display,
const gfx::Size& size) override {
gl::GLDisplayEGL* egl_display = display->GetAs<gl::GLDisplayEGL>();
if (egl_display->IsEGLSurfacelessContextSupported() && size.width() == 0 &&
size.height() == 0) {
return InitializeGLSurface(new gl::SurfacelessEGL(egl_display, size));
} else {
return InitializeGLSurface(
new gl::PbufferGLSurfaceEGL(egl_display, size));
}
}
protected:
// GLOzoneEGL:
gl::EGLDisplayPlatform GetNativeDisplay() override {
return gl::EGLDisplayPlatform(reinterpret_cast<EGLNativeDisplayType>(
x11::Connection::Get()->GetXlibDisplay().display()));
}
bool LoadGLES2Bindings(
const gl::GLImplementationParts& implementation) override {
return LoadDefaultEGLGLES2Bindings(implementation);
}
private:
std::unique_ptr<NativePixmapGLBinding> ImportNativePixmap(
scoped_refptr<gfx::NativePixmap> pixmap,
viz::SharedImageFormat plane_format,
std::optional<int> plane_index,
gfx::Size plane_size,
const gfx::ColorSpace& color_space,
GLenum target,
GLuint texture_id) override {
switch (GetNativePixmapSupportType()) {
case NativePixmapSupportType::kDMABuf: {
return NativePixmapEGLBinding::Create(pixmap, plane_format, plane_index,
plane_size, color_space, target,
texture_id);
}
case NativePixmapSupportType::kX11Pixmap: {
return NativePixmapEGLX11Binding::Create(
pixmap, plane_format, plane_size, target, texture_id);
}
default:
return nullptr;
}
}
bool is_swiftshader_ = false;
};
} // namespace
X11SurfaceFactory::X11SurfaceFactory(
std::unique_ptr<x11::Connection> connection)
: egl_implementation_(std::make_unique<GLOzoneEGLX11>()),
connection_(std::move(connection)) {}
X11SurfaceFactory::~X11SurfaceFactory() = default;
std::vector<gl::GLImplementationParts>
X11SurfaceFactory::GetAllowedGLImplementations() {
return std::vector<gl::GLImplementationParts>{
gl::GLImplementationParts(gl::kGLImplementationEGLANGLE),
};
}
GLOzone* X11SurfaceFactory::GetGLOzone(
const gl::GLImplementationParts& implementation) {
switch (implementation.gl) {
case gl::kGLImplementationEGLANGLE:
return egl_implementation_.get();
default:
return nullptr;
}
}
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
X11SurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
bool allow_protected_memory) {
return std::make_unique<VulkanImplementationX11>(use_swiftshader);
}
#endif
std::unique_ptr<SurfaceOzoneCanvas> X11SurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget) {
// X11SoftwareBitmapPresenter (created via X11CanvasSurface) requres a
// Connection TLS instance and a PlatformEventSource.
if (connection_) {
auto* connection = connection_.get();
x11::Connection::Set(std::move(connection_));
connection->platform_event_source =
std::make_unique<X11EventSource>(connection);
}
return std::make_unique<X11CanvasSurface>(widget);
}
scoped_refptr<gfx::NativePixmap> X11SurfaceFactory::CreateNativePixmap(
gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
viz::SharedImageFormat format,
gfx::BufferUsage usage,
std::optional<gfx::Size> framebuffer_size) {
scoped_refptr<gfx::NativePixmapDmaBuf> pixmap;
auto buffer =
ui::GBMSupportX11::GetInstance()->CreateBuffer(format, size, usage);
if (buffer) {
gfx::NativePixmapHandle handle = buffer->ExportHandle();
if (handle.planes.empty()) {
return nullptr;
}
pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format,
std::move(handle));
}
// CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
// and return the result with the provided callback.
return pixmap;
}
bool X11SurfaceFactory::CanCreateNativePixmapForFormat(
viz::SharedImageFormat format) {
return ui::GBMSupportX11::GetInstance()->CanCreateBufferForFormat(format);
}
scoped_refptr<gfx::NativePixmap>
X11SurfaceFactory::CreateNativePixmapFromHandle(
gfx::AcceleratedWidget widget,
gfx::Size size,
viz::SharedImageFormat format,
gfx::NativePixmapHandle handle) {
scoped_refptr<gfx::NativePixmapDmaBuf> pixmap;
auto buffer = ui::GBMSupportX11::GetInstance()->CreateBufferFromHandle(
size, format, std::move(handle));
if (buffer) {
gfx::NativePixmapHandle buffer_handle = buffer->ExportHandle();
if (buffer_handle.planes.empty()) {
return nullptr;
}
pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(
size, format, std::move(buffer_handle));
}
return pixmap;
}
bool X11SurfaceFactory::IsFormatSupportedForTexturing(
viz::SharedImageFormat format) const {
return ui::GBMSupportX11::GetInstance()->CanCreateBufferForFormat(format);
}
} // namespace ui
@@ -0,0 +1,65 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_X11_X11_SURFACE_FACTORY_H_
#define UI_OZONE_PLATFORM_X11_X11_SURFACE_FACTORY_H_
#include <memory>
#include <vector>
#include "components/viz/common/resources/shared_image_format.h"
#include "gpu/vulkan/buildflags.h"
#include "ui/gfx/x/connection.h"
#include "ui/gl/gl_surface.h"
#include "ui/ozone/public/gl_ozone.h"
#include "ui/ozone/public/surface_factory_ozone.h"
namespace ui {
// Handles GL initialization and surface/context creation for X11.
class X11SurfaceFactory : public SurfaceFactoryOzone {
public:
explicit X11SurfaceFactory(std::unique_ptr<x11::Connection> connection);
X11SurfaceFactory(const X11SurfaceFactory&) = delete;
X11SurfaceFactory& operator=(const X11SurfaceFactory&) = delete;
~X11SurfaceFactory() override;
// SurfaceFactoryOzone:
std::vector<gl::GLImplementationParts> GetAllowedGLImplementations() override;
GLOzone* GetGLOzone(const gl::GLImplementationParts& implementation) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
bool use_swiftshader,
bool allow_protected_memory) override;
#endif
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
viz::SharedImageFormat format,
gfx::BufferUsage usage,
std::optional<gfx::Size> framebuffer_size = std::nullopt) override;
bool CanCreateNativePixmapForFormat(viz::SharedImageFormat format) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
gfx::AcceleratedWidget widget,
gfx::Size size,
viz::SharedImageFormat format,
gfx::NativePixmapHandle handle) override;
bool IsFormatSupportedForTexturing(
viz::SharedImageFormat format) const override;
private:
std::unique_ptr<GLOzone> egl_implementation_;
std::unique_ptr<x11::Connection> connection_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_X11_X11_SURFACE_FACTORY_H_
@@ -0,0 +1,521 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_H_
#define UI_OZONE_PLATFORM_X11_X11_WINDOW_H_
#include <array>
#include <memory>
#include <string>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/base/x/x11_desktop_window_move_client.h"
#include "ui/base/x/x11_drag_drop_client.h"
#include "ui/base/x/x11_move_loop_delegate.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/sync.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
#include "ui/platform_window/extensions/workspace_extension.h"
#include "ui/platform_window/extensions/x11_extension.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/platform_window/wm/wm_drag_handler.h"
#include "ui/platform_window/wm/wm_move_loop_handler.h"
#include "ui/platform_window/wm/wm_move_resize_handler.h"
class SkPath;
namespace x11 {
class GeometryCache;
class WmSync;
} // namespace x11
namespace ui {
class PlatformWindowDelegate;
class X11ExtensionDelegate;
class X11MoveLoop;
class WorkspaceExtensionDelegate;
// PlatformWindow implementation for X11.
class X11Window : public PlatformWindow,
public WmMoveResizeHandler,
public PlatformEventDispatcher,
public x11::EventObserver,
public WorkspaceExtension,
public X11Extension,
public WmDragHandler,
public XDragDropClient::Delegate,
public X11MoveLoopDelegate,
public WmMoveLoopHandler,
public X11DesktopWindowMoveClient::Delegate {
public:
explicit X11Window(PlatformWindowDelegate* platform_window_delegate);
X11Window(const X11Window&) = delete;
X11Window& operator=(const X11Window&) = delete;
~X11Window() override;
virtual void Initialize(PlatformWindowInitProperties properties);
// X11WindowManager calls this.
void OnXWindowLostCapture();
void OnCursorUpdate();
gfx::AcceleratedWidget GetWidget() const;
gfx::Rect GetOuterBounds() const;
void SetTransientWindow(x11::Window window);
bool has_pointer() const { return has_pointer_; }
// PlatformWindow:
void Show(bool inactive) override;
void Hide() override;
void Close() override;
bool IsVisible() const override;
void PrepareForShutdown() override;
void SetBoundsInPixels(const gfx::Rect& bounds) override;
gfx::Rect GetBoundsInPixels() const override;
void SetBoundsInDIP(const gfx::Rect& bounds) override;
gfx::Rect GetBoundsInDIP() const override;
void SetTitle(const std::u16string& title) override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
void SetFullscreen(bool fullscreen, int64_t target_display_id) override;
void Maximize() override;
void Minimize() override;
void Restore() override;
void ShowWindowControlsMenu(const gfx::Point& point) override;
PlatformWindowState GetPlatformWindowState() const override;
void Activate() override;
void Deactivate() override;
void SetUseNativeFrame(bool use_native_frame) override;
bool ShouldUseNativeFrame() const override;
void SetCursor(scoped_refptr<PlatformCursor> cursor) override;
void MoveCursorTo(const gfx::Point& location) override;
void ConfineCursorToBounds(const gfx::Rect& bounds) override;
void SetRestoredBoundsInDIP(const gfx::Rect& bounds) final;
gfx::Rect GetRestoredBoundsInDIP() const final;
bool ShouldWindowContentsBeTransparent() const override;
void SetZOrderLevel(ZOrderLevel order) override;
ZOrderLevel GetZOrderLevel() const override;
void StackAbove(gfx::AcceleratedWidget widget) override;
void StackAtTop() override;
void FlashFrame(bool flash_frame) override;
void SetShape(std::unique_ptr<ShapeRects> native_shape,
const gfx::Transform& transform) override;
void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void SizeConstraintsChanged() override;
void SetOpacity(float opacity) override;
bool CanSetDecorationInsets() const override;
void SetOpaqueRegion(
std::optional<std::vector<gfx::Rect>> region_px) override;
void SetInputRegion(std::optional<std::vector<gfx::Rect>> region_px) override;
void NotifyStartupComplete(const std::string& startup_id) override;
// WorkspaceExtension:
std::string GetWorkspace() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
bool IsVisibleOnAllWorkspaces() const override;
void SetWorkspaceExtensionDelegate(
WorkspaceExtensionDelegate* delegate) override;
// X11Extension:
bool IsSyncExtensionAvailable() const override;
bool IsWmTiling() const override;
void OnCompleteSwapAfterResize(const gfx::Size& new_size) override;
gfx::Rect GetXRootWindowOuterBounds() const override;
void LowerXWindow() override;
void SetOverrideRedirect(bool override_redirect) override;
bool CanResetOverrideRedirect() const override;
void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) override;
bool IsWmSyncActiveForTest() override;
// x11::EventObserver:
void OnEvent(const x11::Event& event) override;
protected:
PlatformWindowDelegate* platform_window_delegate() const {
return platform_window_delegate_;
}
void OnXWindowStateChanged();
void OnXWindowDamageEvent(const gfx::Rect& damage_rect);
void OnXWindowCloseRequested();
void OnXWindowIsActiveChanged(bool active);
void OnXWindowWorkspaceChanged();
void OnXWindowLostPointerGrab();
void OnXWindowSelectionEvent(const x11::SelectionNotifyEvent& xev);
void OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev);
std::optional<gfx::Size> GetMinimumSizeForXWindow();
std::optional<gfx::Size> GetMaximumSizeForXWindow();
SkPath GetWindowMaskForXWindow();
private:
FRIEND_TEST_ALL_PREFIXES(X11WindowTest, Shape);
FRIEND_TEST_ALL_PREFIXES(X11WindowTest, WindowManagerTogglesFullscreen);
FRIEND_TEST_ALL_PREFIXES(X11WindowTest,
ToggleMinimizePropogateToPlatformWindowDelegate);
void UpdateDecorationInsets();
// PlatformEventDispatcher:
bool CanDispatchEvent(const PlatformEvent& event) override;
uint32_t DispatchEvent(const PlatformEvent& event) override;
void DispatchUiEvent(ui::Event* event, const x11::Event& xev);
// WmMoveResizeHandler
void DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& pointer_location_in_px) override;
// WmMoveLoopHandler:
bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
void EndMoveLoop() override;
// WmDragHandler:
bool StartDrag(const OSExchangeData& data,
int operations,
mojom::DragEventSource source,
gfx::NativeCursor cursor,
bool can_grab_pointer,
base::OnceClosure drag_started_callback,
WmDragHandler::DragFinishedCallback drag_finished_callback,
WmDragHandler::LocationDelegate* delegate) override;
void CancelDrag() override;
void UpdateDragImage(const gfx::ImageSkia& image,
const gfx::Vector2d& offset) override;
// XDragDropClient::Delegate
std::optional<gfx::AcceleratedWidget> GetDragWidget() override;
int UpdateDrag(const gfx::Point& screen_point) override;
void UpdateCursor(mojom::DragOperation negotiated_operation) override;
void OnBeginForeignDrag(x11::Window window) override;
void OnEndForeignDrag() override;
void OnBeforeDragLeave() override;
mojom::DragOperation PerformDrop() override;
void EndDragLoop() override;
// X11MoveLoopDelegate
void OnMouseMovement(const gfx::Point& screen_point,
int flags,
base::TimeTicks event_time) override;
void OnMouseReleased() override;
void OnMoveLoopEnded() override;
// X11DesktopWindowMoveClient::Delegate:
void SetBoundsOnMove(const gfx::Rect& requested_bounds) override;
scoped_refptr<X11Cursor> GetLastCursor() override;
gfx::Size GetSize() override;
void QuitDragLoop();
// Handles `event` as an Atk Key Event
bool HandleAsAtkEvent(const x11::Event& event);
// Adjusts |requested_size_in_pixels| to avoid the WM "feature" where setting
// the window size to the monitor size causes the WM to set the EWMH for
// fullscreen.
gfx::Size AdjustSizeForDisplay(const gfx::Size& requested_size_in_pixels);
// Creates the X window with the given properties.
// Depending on presence of the compositing manager and window type, may
// change the opacity, in which case returns the final opacity type through
// |opacity|.
void CreateXWindow(const PlatformWindowInitProperties& properties);
void CloseXWindow();
void Map(bool inactive = false);
void SetWMStateFullscreen(bool fullscreen);
void SetWMStateMaximize(bool maximize);
bool IsActive() const;
bool IsTargetedBy(const x11::Event& xev) const;
void HandleEvent(const x11::Event& xev);
bool IsMinimized() const;
bool IsMaximized() const;
bool IsFullscreen() const;
void SetFlashFrameHint(bool flash_frame);
void UpdateMinAndMaxSize();
void DispatchResize(bool origin_changed);
void CancelResize();
// Resets the window region for the current window bounds if necessary.
void ResetWindowRegion();
x11::Window window() const { return xwindow_; }
x11::Window root_window() const { return x_root_window_; }
std::vector<x11::Rectangle>* shape() const { return window_shape_.get(); }
// Updates |xwindow_|'s _NET_WM_USER_TIME if |xwindow_| is active.
void UpdateWMUserTime(ui::Event* event);
// Called on an XFocusInEvent, XFocusOutEvent, XIFocusInEvent, or an
// XIFocusOutEvent.
void OnFocusEvent(bool focus_in,
x11::NotifyMode mode,
x11::NotifyDetail detail);
// Called on an XEnterWindowEvent, XLeaveWindowEvent, XIEnterEvent, or an
// XILeaveEvent.
void OnCrossingEvent(bool enter,
bool focus_in_window_or_ancestor,
x11::NotifyMode mode,
x11::NotifyDetail detail);
// Called when |xwindow_|'s _NET_WM_STATE property is updated.
void OnWMStateUpdated();
WindowTiledEdges GetTiledState() const;
// Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
void OnFrameExtentsUpdated();
void OnConfigureEvent(const x11::ConfigureNotifyEvent& event);
void OnWorkspaceUpdated();
void OnWindowMapped();
// Record the activation state.
void BeforeActivationStateChanged();
// Handle the state change since BeforeActivationStateChanged().
void AfterActivationStateChanged();
void MaybeUpdateOcclusionState();
void DelayedResize(bool origin_changed);
// If mapped, sends a message to the window manager to enable or disable the
// states |state1| and |state2|. Otherwise, the states will be enabled or
// disabled on the next map. It's the caller's responsibility to make sure
// atoms are set and unset in the appropriate pairs. For example, if a caller
// sets (_NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ), it would
// be invalid to unset the maximized state by making two calls like
// (_NET_WM_STATE_MAXIMIZED_VERT, x11::None), (_NET_WM_STATE_MAXIMIZED_HORZ,
// x11::None).
void SetWMSpecState(bool enabled, x11::Atom state1, x11::Atom state2);
// Updates |window_properties_| with |new_window_properties|.
void UpdateWindowProperties(
const base::flat_set<x11::Atom>& new_window_properties);
void UnconfineCursor();
void UpdateWindowRegion(std::unique_ptr<std::vector<x11::Rectangle>> region);
void NotifyBoundsChanged(bool origin_changed);
// Initializes as a status icon window.
bool InitializeAsStatusIcon();
void SetBoundsWithWmSync(const gfx::Rect& bounds_px);
void OnWmSynced();
void OnBoundsChanged(const std::optional<gfx::Rect>& old_bounds_px,
const gfx::Rect& new_bounds_px);
void MaybeUpdateSyncCounter();
// Stores current state of this window.
PlatformWindowState state_ = PlatformWindowState::kUnknown;
WindowTiledEdges tiled_state_;
const raw_ptr<PlatformWindowDelegate> platform_window_delegate_;
raw_ptr<WorkspaceExtensionDelegate, DanglingUntriaged>
workspace_extension_delegate_ = nullptr;
raw_ptr<X11ExtensionDelegate, DanglingUntriaged> x11_extension_delegate_ =
nullptr;
// Tells if the window got a ::Close call.
bool is_shutting_down_ = false;
// The z-order level of the window; the window exhibits "always on top"
// behavior if > 0.
ui::ZOrderLevel z_order_ = ui::ZOrderLevel::kNormal;
// The bounds of our window before the window was maximized.
gfx::Rect restored_bounds_in_pixels_;
std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
// Whether the drop handler has notified that the drag has entered.
bool notified_enter_ = false;
// Keeps the last negotiated operations returned by the drop handler.
int allowed_drag_operations_ = 0;
// Handles XDND events going through this window.
std::unique_ptr<XDragDropClient> drag_drop_client_;
WmDragHandler::DragFinishedCallback drag_finished_callback_;
raw_ptr<WmDragHandler::LocationDelegate, DanglingUntriaged>
drag_location_delegate_ = nullptr;
// Run loop used while dragging from this window.
std::unique_ptr<X11MoveLoop> drag_loop_;
// Events that we have selected on the source window of the incoming drag.
x11::ScopedEventSelector source_window_events_;
// The display and the native X window hosting the root window.
const raw_ref<x11::Connection> connection_;
x11::Window xwindow_ = x11::Window::None;
x11::Window x_root_window_ = x11::Window::None;
// Any native, modal dialog hanging from this window.
x11::Window transient_window_ = x11::Window::None;
// Events selected on |xwindow_|.
x11::ScopedEventSelector xwindow_events_;
// The window manager state bits.
base::flat_set<x11::Atom> window_properties_;
// Is this window able to receive focus?
bool activatable_ = true;
// Was this window initialized with the override_redirect window attribute?
bool override_redirect_ = false;
std::optional<std::u16string> window_title_;
// Whether the window is visible with respect to Aura.
bool window_mapped_in_client_ = false;
// Whether the window is mapped with respect to the X server.
bool window_mapped_in_server_ = false;
// The bounds of `xwindow_`. If `bounds_wm_sync_` is active, then
// `last_set_bounds_px_` should be treated as the current bounds. Otherwise,
// the bounds from `geometry_cache_` should be used.
gfx::Rect last_set_bounds_px_;
std::unique_ptr<x11::WmSync> bounds_wm_sync_;
std::unique_ptr<x11::GeometryCache> geometry_cache_;
x11::VisualId visual_id_{};
// Whether we used an ARGB visual for our window.
bool visual_has_alpha_ = false;
// The workspace containing |xwindow_|. This will be std::nullopt when
// _NET_WM_DESKTOP is unset.
std::optional<int> workspace_;
// True if the window should stay on top of most other windows.
bool is_always_on_top_ = false;
// True if the window is security-sensitive. Implies |is_always_on_top_|.
bool is_security_surface_ = false;
// True if the window is fully obscured by another window.
bool is_occluded_ = false;
PlatformWindowOcclusionState occlusion_state_ =
PlatformWindowOcclusionState::kUnknown;
// Does |xwindow_| have the pointer grab (XI2 or normal)?
bool has_pointer_grab_ = false;
// The focus-tracking state variables are as described in
// gtk/docs/focus_tracking.txt
//
// |xwindow_| is active iff:
// (|has_window_focus_| || |has_pointer_focus_|) &&
// !|ignore_keyboard_input_|
// Is the pointer in |xwindow_| or one of its children?
bool has_pointer_ = false;
// Is |xwindow_| or one of its children focused?
bool has_window_focus_ = false;
// (An ancestor window or the PointerRoot is focused) && |has_pointer_|.
// |has_pointer_focus_| == true is the odd case where we will receive keyboard
// input when |has_window_focus_| == false. |has_window_focus_| and
// |has_pointer_focus_| are mutually exclusive.
bool has_pointer_focus_ = false;
// X11 does not support defocusing windows; you can only focus a different
// window. If we would like to be defocused, we just ignore keyboard input we
// no longer care about.
bool ignore_keyboard_input_ = false;
// Used for tracking activation state in {Before|After}ActivationStateChanged.
bool was_active_ = false;
bool had_pointer_ = false;
bool had_pointer_grab_ = false;
bool had_window_focus_ = false;
// True if a Maximize() call should be done after mapping the window.
bool should_maximize_after_map_ = false;
// True if GrabPointer() should be called after mapping the window.
bool should_grab_pointer_after_map_ = false;
// Whether we currently are flashing our frame. This feature is implemented
// by setting the urgency hint with the window manager, which can draw
// attention to the window or completely ignore the hint. We stop flashing
// the frame when |xwindow_| gains focus or handles a mouse button event.
bool urgency_hint_set_ = false;
// |xwindow_|'s minimum size.
gfx::Size min_size_in_pixels_;
// |xwindow_|'s maximum size.
gfx::Size max_size_in_pixels_;
// The window shape if the window is non-rectangular.
std::unique_ptr<std::vector<x11::Rectangle>> window_shape_;
// Whether |window_shape_| was set via SetShape().
bool custom_window_shape_ = false;
// True if the window has title-bar / borders provided by the window manager.
bool use_native_frame_ = false;
// The size of the window manager provided borders (if any).
gfx::Insets native_window_frame_borders_in_pixels_;
// Used for synchronizing between `xwindow_` and the WM during resizing.
x11::Sync::Counter update_counter_{};
std::optional<x11::Sync::Int64> configure_counter_value_;
std::optional<gfx::Size> last_configure_size_;
std::optional<gfx::Size> last_swapped_size_;
base::CancelableOnceClosure delayed_resize_task_;
// Keep track of barriers to confine cursor.
bool has_pointer_barriers_ = false;
std::array<x11::XFixes::Barrier, 4> pointer_barriers_;
scoped_refptr<X11Cursor> last_cursor_;
base::CancelableOnceCallback<void(x11::Cursor)> on_cursor_loaded_;
base::WeakPtrFactory<X11Window> weak_ptr_factory_{this};
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_H_
@@ -0,0 +1,101 @@
// Copyright 2019 The Chromium Authors
// 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/x11_window_manager.h"
#include "ui/ozone/platform/x11/x11_window.h"
namespace ui {
namespace {
X11WindowManager* g_instance = nullptr;
} // namespace
X11WindowManager::X11WindowManager() {
DCHECK(!g_instance) << "There should only be a single X11WindowManager";
g_instance = this;
}
X11WindowManager::~X11WindowManager() = default;
// static
X11WindowManager* X11WindowManager::GetInstance() {
if (!g_instance) {
auto manager = std::make_unique<X11WindowManager>();
X11WindowManager* manager_ptr = manager.release();
DCHECK_EQ(g_instance, manager_ptr);
}
return g_instance;
}
void X11WindowManager::GrabEvents(X11Window* window) {
DCHECK_NE(located_events_grabber_, window);
// Grabbing the mouse is asynchronous. However, we synchronously start
// forwarding all mouse events received by Chrome to the
// aura::WindowEventDispatcher which has capture. This makes capture
// synchronous for all intents and purposes if either:
// - |located_events_grabber_| is set to have capture.
// OR
// - The topmost window underneath the mouse is managed by Chrome.
auto* old_grabber = located_events_grabber_.get();
// Update |located_events_grabber_| prior to calling OnXWindowLostCapture() to
// avoid releasing pointer grab.
located_events_grabber_ = window;
if (old_grabber)
old_grabber->OnXWindowLostCapture();
// the X11Window calls GrabPointer by itself.
}
void X11WindowManager::UngrabEvents(X11Window* window) {
DCHECK_EQ(located_events_grabber_, window);
// Release mouse grab asynchronously. A window managed by Chrome is likely
// the topmost window underneath the mouse so the capture release being
// asynchronous is likely inconsequential.
auto* old_grabber = located_events_grabber_.get();
located_events_grabber_ = nullptr;
old_grabber->OnXWindowLostCapture();
}
void X11WindowManager::AddWindow(X11Window* window) {
DCHECK(window);
auto widget = window->GetWidget();
DCHECK_NE(gfx::kNullAcceleratedWidget, widget);
DCHECK(!windows_.contains(widget));
windows_.emplace(widget, window);
}
void X11WindowManager::RemoveWindow(X11Window* window) {
DCHECK(window);
auto widget = window->GetWidget();
auto it = windows_.find(widget);
// The XWindow might not have been initialized due to some errors.
if (widget == gfx::kNullAcceleratedWidget) {
DCHECK(it == windows_.end());
} else {
CHECK(it != windows_.end());
if (window_mouse_currently_on_ == it->second)
window_mouse_currently_on_ = nullptr;
windows_.erase(it);
}
}
X11Window* X11WindowManager::GetWindow(gfx::AcceleratedWidget widget) const {
auto it = windows_.find(widget);
return it != windows_.end() ? it->second : nullptr;
}
void X11WindowManager::MouseOnWindow(X11Window* window) {
if (window_mouse_currently_on_ == window)
return;
window_mouse_currently_on_ = window;
window->OnCursorUpdate();
}
} // namespace ui
@@ -0,0 +1,61 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_H_
#define UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_H_
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "ui/gfx/native_ui_types.h"
namespace ui {
class X11Window;
class X11WindowManager {
public:
X11WindowManager();
X11WindowManager(const X11WindowManager&) = delete;
X11WindowManager& operator=(const X11WindowManager&) = delete;
~X11WindowManager();
// Returns instance of X11WindowManager.
static X11WindowManager* GetInstance();
// Sets a given X11Window as the recipient for events and calls
// OnLostCapture for another |located_events_grabber_| if it has been set
// previously.
void GrabEvents(X11Window* window);
// Unsets a given X11Window as the recipient for events and calls
// OnLostCapture.
void UngrabEvents(X11Window* window);
// Gets the current X11PlatformWindow recipient of mouse events.
X11Window* located_events_grabber() const { return located_events_grabber_; }
// Gets the window corresponding to the AcceleratedWidget |widget|.
void AddWindow(X11Window* window);
void RemoveWindow(X11Window* window);
X11Window* GetWindow(gfx::AcceleratedWidget widget) const;
void MouseOnWindow(X11Window* delegate);
const X11Window* window_mouse_currently_on_for_test() const {
return window_mouse_currently_on_;
}
private:
raw_ptr<X11Window> located_events_grabber_ = nullptr;
raw_ptr<X11Window> window_mouse_currently_on_ = nullptr;
base::flat_map<gfx::AcceleratedWidget, raw_ptr<X11Window, CtnExperimental>>
windows_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_H_
@@ -0,0 +1,46 @@
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_
#define UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_
#include <memory>
#include "ui/gfx/native_ui_types.h"
namespace ui {
class OverlayCandidatesOzone;
// Responsible for providing the oracles used to decide when overlays can be
// used.
class OverlayManagerOzone {
public:
virtual ~OverlayManagerOzone() {}
// Get the hal struct to check for overlay support.
virtual std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget w) = 0;
bool allow_sync_and_real_buffer_page_flip_testing() const {
return allow_sync_and_real_buffer_page_flip_testing_;
}
// Tell the manager that the overlay delegation is enabled. This is only
// useful for Wayland as checking for overlay support depends on
// features::IsDelegatedCompositingEnabled, which cannot be accessed from
// //ui/ozone.
// TODO(msisov, petermcneeley): remove this once Wayland uses only delegated
// context.
virtual void SetContextDelegated() {}
protected:
// TODO(fangzhoug): Some Chrome OS boards still use the legacy video decoder.
// Remove this once ChromeOSVideoDecoder is on everywhere.
bool allow_sync_and_real_buffer_page_flip_testing_ = false;
};
} // namespace ui
#endif // UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_