Commit 74d5d8b0 authored by Maksim Sisov's avatar Maksim Sisov Committed by Commit Bot

ozone/wayland: gtk: support modality for file dialogs

This CL is based on previous Nick's work (https://crrev.com/c/2051187)
and fixed modality for gtk file dialogs by leveraging xdg-foreign
protocol extension.

XdgForeignWrapper has been added to ease usage of the protocol.

Bug: 963419, 1008755
Change-Id: I68eb5818a6bb8e7dbf28a13f46e86926dc4cfdda
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2397575
Commit-Queue: Maksim Sisov (GMT+3) <msisov@igalia.com>
Reviewed-by: default avatarNick Yamane <nickdiego@igalia.com>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806078}
parent fe51fcb5
...@@ -115,3 +115,7 @@ wayland_protocol("wayland_drm_protocol") { ...@@ -115,3 +115,7 @@ wayland_protocol("wayland_drm_protocol") {
wayland_protocol("color_space_protocol") { wayland_protocol("color_space_protocol") {
sources = [ "unstable/color-space/color-space-unstable-v1.xml" ] sources = [ "unstable/color-space/color-space-unstable-v1.xml" ]
} }
wayland_protocol("xdg_foreign") {
sources = [ "src/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml" ]
}
...@@ -124,6 +124,8 @@ source_set("wayland") { ...@@ -124,6 +124,8 @@ source_set("wayland") {
"host/wayland_window_observer.h", "host/wayland_window_observer.h",
"host/wayland_zwp_linux_dmabuf.cc", "host/wayland_zwp_linux_dmabuf.cc",
"host/wayland_zwp_linux_dmabuf.h", "host/wayland_zwp_linux_dmabuf.h",
"host/xdg_foreign_wrapper.cc",
"host/xdg_foreign_wrapper.h",
"host/xdg_popup_wrapper_impl.cc", "host/xdg_popup_wrapper_impl.cc",
"host/xdg_popup_wrapper_impl.h", "host/xdg_popup_wrapper_impl.h",
"host/xdg_surface_wrapper_impl.cc", "host/xdg_surface_wrapper_impl.cc",
...@@ -156,6 +158,7 @@ source_set("wayland") { ...@@ -156,6 +158,7 @@ source_set("wayland") {
"//third_party/wayland-protocols:presentation_time_protocol", "//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol", "//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:wayland_drm_protocol", "//third_party/wayland-protocols:wayland_drm_protocol",
"//third_party/wayland-protocols:xdg_foreign",
"//third_party/wayland-protocols:xdg_shell_protocol", "//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base", "//ui/base",
"//ui/base:buildflags", "//ui/base:buildflags",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <presentation-time-client-protocol.h> #include <presentation-time-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h> #include <text-input-unstable-v1-client-protocol.h>
#include <wayland-drm-client-protocol.h> #include <wayland-drm-client-protocol.h>
#include <xdg-foreign-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h> #include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h> #include <xdg-shell-unstable-v6-client-protocol.h>
...@@ -269,4 +270,14 @@ const wl_interface* ObjectTraits<zwp_text_input_v1>::interface = ...@@ -269,4 +270,14 @@ const wl_interface* ObjectTraits<zwp_text_input_v1>::interface =
void (*ObjectTraits<zwp_text_input_v1>::deleter)(zwp_text_input_v1*) = void (*ObjectTraits<zwp_text_input_v1>::deleter)(zwp_text_input_v1*) =
&zwp_text_input_v1_destroy; &zwp_text_input_v1_destroy;
const wl_interface* ObjectTraits<zxdg_exporter_v1>::interface =
&zxdg_exporter_v1_interface;
void (*ObjectTraits<zxdg_exporter_v1>::deleter)(zxdg_exporter_v1*) =
&zxdg_exporter_v1_destroy;
const wl_interface* ObjectTraits<zxdg_exported_v1>::interface =
&zxdg_exported_v1_interface;
void (*ObjectTraits<zxdg_exported_v1>::deleter)(zxdg_exported_v1*) =
&zxdg_exported_v1_destroy;
} // namespace wl } // namespace wl
...@@ -55,6 +55,8 @@ struct zxdg_popup_v6; ...@@ -55,6 +55,8 @@ struct zxdg_popup_v6;
struct zxdg_positioner_v6; struct zxdg_positioner_v6;
struct zwp_text_input_manager_v1; struct zwp_text_input_manager_v1;
struct zwp_text_input_v1; struct zwp_text_input_v1;
struct zxdg_exporter_v1;
struct zxdg_exported_v1;
namespace wl { namespace wl {
...@@ -343,6 +345,18 @@ struct ObjectTraits<zwp_text_input_v1> { ...@@ -343,6 +345,18 @@ struct ObjectTraits<zwp_text_input_v1> {
static void (*deleter)(zwp_text_input_v1*); static void (*deleter)(zwp_text_input_v1*);
}; };
template <>
struct ObjectTraits<zxdg_exporter_v1> {
static const wl_interface* interface;
static void (*deleter)(zxdg_exporter_v1*);
};
template <>
struct ObjectTraits<zxdg_exported_v1> {
static const wl_interface* interface;
static void (*deleter)(zxdg_exported_v1*);
};
struct Deleter { struct Deleter {
template <typename T> template <typename T>
void operator()(T* obj) { void operator()(T* obj) {
......
...@@ -7,9 +7,21 @@ ...@@ -7,9 +7,21 @@
#include <gdk/gdkwayland.h> #include <gdk/gdkwayland.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <memory>
#include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
#include "ui/platform_window/platform_window_init_properties.h"
#define WEAK_GTK_FN(x) extern "C" __attribute__((weak)) decltype(x) x
WEAK_GTK_FN(gdk_wayland_window_set_transient_for_exported);
namespace ui { namespace ui {
...@@ -39,12 +51,29 @@ GdkWindow* GtkUiDelegateWayland::GetGdkWindow( ...@@ -39,12 +51,29 @@ GdkWindow* GtkUiDelegateWayland::GetGdkWindow(
bool GtkUiDelegateWayland::SetGdkWindowTransientFor( bool GtkUiDelegateWayland::SetGdkWindowTransientFor(
GdkWindow* window, GdkWindow* window,
gfx::AcceleratedWidget parent) { gfx::AcceleratedWidget parent) {
NOTIMPLEMENTED_LOG_ONCE(); if (!gdk_wayland_window_set_transient_for_exported) {
return false; LOG(WARNING) << "set_transient_for_exported not supported in GTK version "
<< GTK_MAJOR_VERSION << '.' << GTK_MINOR_VERSION << '.'
<< GTK_MICRO_VERSION;
return false;
}
auto* parent_window =
connection_->wayland_window_manager()->GetWindow(parent);
auto* foreign = connection_->xdg_foreign();
if (!parent_window || !foreign)
return false;
DCHECK_EQ(parent_window->type(), PlatformWindowType::kWindow);
foreign->ExportSurfaceToForeign(
parent_window, base::BindOnce(&GtkUiDelegateWayland::OnHandle,
weak_factory_.GetWeakPtr(), window));
return true;
} }
void GtkUiDelegateWayland::ClearTransientFor(gfx::AcceleratedWidget parent) { void GtkUiDelegateWayland::ClearTransientFor(gfx::AcceleratedWidget parent) {
NOTIMPLEMENTED_LOG_ONCE(); // Nothing to do here.
} }
void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) { void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
...@@ -53,4 +82,10 @@ void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) { ...@@ -53,4 +82,10 @@ void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
gtk_window_present(window); gtk_window_present(window);
} }
void GtkUiDelegateWayland::OnHandle(GdkWindow* window,
const std::string& handle) {
gdk_wayland_window_set_transient_for_exported(
window, const_cast<char*>(handle.c_str()));
}
} // namespace ui } // namespace ui
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_
#include <string>
#include "base/memory/weak_ptr.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/gtk/gtk_ui_delegate.h" #include "ui/gtk/gtk_ui_delegate.h"
...@@ -29,7 +32,13 @@ class GtkUiDelegateWayland : public GtkUiDelegate { ...@@ -29,7 +32,13 @@ class GtkUiDelegateWayland : public GtkUiDelegate {
void ShowGtkWindow(GtkWindow* window) override; void ShowGtkWindow(GtkWindow* window) override;
private: private:
// Called when xdg-foreign exports a parent window passed in
// SetGdkWindowTransientFor.
void OnHandle(GdkWindow* window, const std::string& handle);
WaylandConnection* const connection_; WaylandConnection* const connection_;
base::WeakPtrFactory<GtkUiDelegateWayland> weak_factory_{this};
}; };
} // namespace ui } // namespace ui
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h" #include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
namespace ui { namespace ui {
...@@ -367,6 +368,10 @@ void WaylandConnection::Global(void* data, ...@@ -367,6 +368,10 @@ void WaylandConnection::Global(void* data,
LOG(ERROR) << "Failed to bind to zwp_text_input_manager_v1 global"; LOG(ERROR) << "Failed to bind to zwp_text_input_manager_v1 global";
return; return;
} }
} else if (!connection->xdg_foreign_ &&
strcmp(interface, "zxdg_exporter_v1") == 0) {
connection->xdg_foreign_ = std::make_unique<XdgForeignWrapper>(
connection, wl::Bind<zxdg_exporter_v1>(registry, name, version));
} else if (!connection->drm_ && (strcmp(interface, "wl_drm") == 0) && } else if (!connection->drm_ && (strcmp(interface, "wl_drm") == 0) &&
version >= kMinWlDrmVersion) { version >= kMinWlDrmVersion) {
auto wayland_drm = wl::Bind<struct wl_drm>(registry, name, version); auto wayland_drm = wl::Bind<struct wl_drm>(registry, name, version);
......
...@@ -36,6 +36,7 @@ class WaylandDataDeviceManager; ...@@ -36,6 +36,7 @@ class WaylandDataDeviceManager;
class WaylandCursorPosition; class WaylandCursorPosition;
class WaylandWindowDragController; class WaylandWindowDragController;
class GtkPrimarySelectionDeviceManager; class GtkPrimarySelectionDeviceManager;
class XdgForeignWrapper;
class WaylandConnection { class WaylandConnection {
public: public:
...@@ -133,6 +134,8 @@ class WaylandConnection { ...@@ -133,6 +134,8 @@ class WaylandConnection {
return window_drag_controller_.get(); return window_drag_controller_.get();
} }
XdgForeignWrapper* xdg_foreign() const { return xdg_foreign_.get(); }
// Returns true when dragging is entered or started. // Returns true when dragging is entered or started.
bool IsDragInProgress() const; bool IsDragInProgress() const;
...@@ -202,6 +205,7 @@ class WaylandConnection { ...@@ -202,6 +205,7 @@ class WaylandConnection {
std::unique_ptr<WaylandDrm> drm_; std::unique_ptr<WaylandDrm> drm_;
std::unique_ptr<WaylandShm> shm_; std::unique_ptr<WaylandShm> shm_;
std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_; std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_;
std::unique_ptr<XdgForeignWrapper> xdg_foreign_;
std::unique_ptr<GtkPrimarySelectionDeviceManager> std::unique_ptr<GtkPrimarySelectionDeviceManager>
primary_selection_device_manager_; primary_selection_device_manager_;
......
// Copyright 2020 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/wayland/host/xdg_foreign_wrapper.h"
#include <xdg-foreign-unstable-v1-client-protocol.h>
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
struct XdgForeignWrapper::ExportedSurface {
ExportedSurface(wl_surface* surface, OnHandleExported cb);
ExportedSurface(ExportedSurface&& buffer);
ExportedSurface& operator=(ExportedSurface&& buffer);
~ExportedSurface();
// Surface that is exported.
wl_surface* surface_for_export = nullptr;
// Exported |surface|.
wl::Object<zxdg_exported_v1> exported;
// Handle of the exported |surface|.
std::string exported_handle;
// The cb that will be executed when |handle| is exported.
std::vector<OnHandleExported> callbacks;
};
XdgForeignWrapper::ExportedSurface::ExportedSurface(wl_surface* surface,
OnHandleExported cb)
: surface_for_export(surface) {
callbacks.emplace_back((std::move(cb)));
}
XdgForeignWrapper::ExportedSurface::ExportedSurface(ExportedSurface&& buffer) =
default;
XdgForeignWrapper::ExportedSurface&
XdgForeignWrapper::ExportedSurface::operator=(ExportedSurface&& buffer) =
default;
XdgForeignWrapper::ExportedSurface::~ExportedSurface() = default;
XdgForeignWrapper::XdgForeignWrapper(WaylandConnection* connection,
wl::Object<zxdg_exporter_v1> exporter_v1)
: connection_(connection), exporter_v1_(std::move(exporter_v1)) {}
XdgForeignWrapper::~XdgForeignWrapper() = default;
void XdgForeignWrapper::ExportSurfaceToForeign(WaylandWindow* window,
OnHandleExported cb) {
DCHECK_EQ(window->type(), PlatformWindowType::kWindow);
auto* surface = window->root_surface()->surface();
auto* exported_surface = GetExportedSurface(surface);
if (!exported_surface) {
// The |surface| has never been exported. Export it and return the handle
// via the |cb|.
ExportSurfaceInternal(surface, std::move(cb));
} else if (exported_surface->exported_handle.empty()) {
// The |surface| has already been exported, but its handle hasn't been
// received yet. Store the |cb| and execute when the handle is obtained.
exported_surface->callbacks.emplace_back(std::move(cb));
} else {
// The |surface| has already been exported and its handle has been received.
// Execute the |cb| and send the handle.
DCHECK(!exported_surface->exported_handle.empty());
std::move(cb).Run(exported_surface->exported_handle);
}
}
XdgForeignWrapper::ExportedSurface* XdgForeignWrapper::GetExportedSurface(
wl_surface* surface) {
for (auto& item : exported_surfaces_) {
if (item.surface_for_export == surface)
return &item;
}
return nullptr;
}
void XdgForeignWrapper::ExportSurfaceInternal(wl_surface* surface,
OnHandleExported cb) {
static const struct zxdg_exported_v1_listener kExportedListener = {
&XdgForeignWrapper::OnExported};
ExportedSurface exported_surface(surface, std::move(cb));
exported_surface.exported.reset(
zxdg_exporter_v1_export(exporter_v1_.get(), surface));
zxdg_exported_v1_add_listener(exported_surface.exported.get(),
&kExportedListener, this);
exported_surfaces_.emplace_back(std::move(exported_surface));
connection_->ScheduleFlush();
}
void XdgForeignWrapper::OnWindowRemoved(WaylandWindow* window) {
auto it = std::find_if(exported_surfaces_.begin(), exported_surfaces_.end(),
[window](const auto& surface) {
return window->root_surface()->surface() ==
surface.surface_for_export;
});
if (it != exported_surfaces_.end())
exported_surfaces_.erase(it);
}
// static
void XdgForeignWrapper::OnExported(void* data,
zxdg_exported_v1* exported,
const char* handle) {
auto* self = static_cast<XdgForeignWrapper*>(data);
DCHECK(self);
auto exported_surface_it = std::find_if(
self->exported_surfaces_.begin(), self->exported_surfaces_.end(),
[exported](const auto& item) { return item.exported.get() == exported; });
DCHECK(exported_surface_it != self->exported_surfaces_.end());
exported_surface_it->exported_handle = handle;
for (auto& cb : exported_surface_it->callbacks)
std::move(cb).Run(exported_surface_it->exported_handle);
exported_surface_it->callbacks.clear();
}
} // namespace ui
// Copyright 2020 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_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
#include <string>
#include "base/callback.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
namespace ui {
class WaylandConnection;
// A wrapper for xdg foreign objects. Exports surfaces that have xdg_surface
// roles and asynchronously returns handles for them. Only xdg_surface surfaces
// may be exported. Currently supports only exporting surfaces.
//
// TODO(1126817): consider supporting xdg-foreign-v2.
class XdgForeignWrapper : public WaylandWindowObserver {
public:
using OnHandleExported = base::OnceCallback<void(const std::string&)>;
XdgForeignWrapper(WaylandConnection* connection,
wl::Object<zxdg_exporter_v1> exporter_v1);
XdgForeignWrapper(const XdgForeignWrapper&) = delete;
XdgForeignWrapper& operator=(const XdgForeignWrapper&) = delete;
~XdgForeignWrapper() override;
// Exports |window|'s wl_surface and asynchronously returns a handle for that
// via the |cb|. Please note that wl_surface that has xdg_surface role can be
// exported.
void ExportSurfaceToForeign(WaylandWindow* window, OnHandleExported cb);
private:
struct ExportedSurface;
ExportedSurface* GetExportedSurface(wl_surface* surface);
void ExportSurfaceInternal(wl_surface* surface, OnHandleExported cb);
// WaylandWindowObserver:
void OnWindowRemoved(WaylandWindow* window) override;
// zxdg_exported_v1_listener:
static void OnExported(void* data,
zxdg_exported_v1* exported,
const char* handle);
WaylandConnection* const connection_;
wl::Object<zxdg_exporter_v1> exporter_v1_;
std::vector<ExportedSurface> exported_surfaces_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment