Bug 1795849 [Linux] Chancel D&D operation on Wayland and XWayland when D&D source window is closing r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D159588
This commit is contained in:
stransky 2022-10-19 06:39:11 +00:00
Родитель 4cc3078461
Коммит 599b985afe
7 изменённых файлов: 61 добавлений и 10 удалений

Просмотреть файл

@ -462,8 +462,7 @@ void GfxInfo::GetData() {
// layer. For all intents and purposes, we should otherwise believe we are
// using X11.
mIsWayland = GdkIsWaylandDisplay();
const char* waylandDisplay = getenv("WAYLAND_DISPLAY");
mIsXWayland = !mIsWayland && waylandDisplay;
mIsXWayland = IsXWaylandProtocol();
// Make a best effort guess at the desktop environment in use. Sadly there
// does not appear to be a standard way to do this, so we check a few

Просмотреть файл

@ -9,6 +9,8 @@
#include "mozilla/UniquePtr.h"
#include "nsReadableUtils.h"
#include "nsWindow.h"
#include "nsIGfxInfo.h"
#include "mozilla/Components.h"
#include <gtk/gtk.h>
#include <dlfcn.h>
@ -71,6 +73,13 @@ bool GdkIsX11Display(GdkDisplay* display) {
G_TYPE_CHECK_INSTANCE_TYPE(display, sGdkX11DisplayGetType());
}
bool IsXWaylandProtocol() {
static bool isXwayland = [] {
return !GdkIsWaylandDisplay() && !!getenv("WAYLAND_DISPLAY");
}();
return isXwayland;
}
bool GdkIsWaylandDisplay() {
static bool isWaylandDisplay = gdk_display_get_default() &&
GdkIsWaylandDisplay(gdk_display_get_default());

Просмотреть файл

@ -31,6 +31,8 @@ bool GdkIsX11Display(GdkDisplay* display);
bool GdkIsWaylandDisplay();
bool GdkIsX11Display();
bool IsXWaylandProtocol();
GdkDevice* GdkGetPointer();
// Sets / returns the last mouse press event we processed.

Просмотреть файл

@ -168,13 +168,13 @@ nsDragService::nsDragService()
}
// set up our logging module
LOGDRAGSERVICE("nsDragService::nsDragService");
mCanDrop = false;
mTargetDragDataReceived = false;
mTargetDragData = 0;
mTargetDragDataLen = 0;
mTempFileTimerID = 0;
mEventLoopDepth = 0;
LOGDRAGSERVICE("nsDragService::nsDragService");
}
nsDragService::~nsDragService() {
@ -388,8 +388,19 @@ nsresult nsDragService::InvokeDragSessionImpl(
mHiddenWidget, sourceList, action, 1,
existingEvent ? existingEvent : &fakeEvent, -1, -1);
LOGDRAGSERVICE("nsDragService::InvokeDragSessionImpl GdkDragContext %p",
context);
if (widget::GdkIsWaylandDisplay() || widget::IsXWaylandProtocol()) {
GdkDevice* device = gdk_drag_context_get_device(context);
GdkWindow* gdkWindow =
gdk_device_get_window_at_position(device, nullptr, nullptr);
mSourceWindow = nsWindow::GetWindow(gdkWindow);
if (mSourceWindow) {
mSourceWindow->SetDragSource(context);
}
}
LOGDRAGSERVICE(
"nsDragService::InvokeDragSessionImpl GdkDragContext [%p] nsWindow [%p]",
context, mSourceWindow.get());
nsresult rv;
if (context) {
@ -531,6 +542,10 @@ nsDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
}
// We're done with the drag context.
if (mSourceWindow) {
mSourceWindow->SetDragSource(nullptr);
mSourceWindow = nullptr;
}
mTargetDragContextForRemote = nullptr;
mTargetWindow = nullptr;
mPendingWindow = nullptr;

Просмотреть файл

@ -132,6 +132,9 @@ class nsDragService final : public nsBaseDragService, public nsIObserver {
guint mTaskSource;
bool mScheduledTaskIsRunning;
// Where the drag begins. We need to keep it open on Wayland.
RefPtr<nsWindow> mSourceWindow;
// target/destination side vars
// These variables keep track of the state of the current drag.

Просмотреть файл

@ -1416,8 +1416,10 @@ void nsWindow::WaylandPopupHierarchyHideByLayout(
// Hide all popups which are not in layout popup chain
nsWindow* popup = mWaylandPopupNext;
while (popup) {
// Tooltips are not tracked in layout chain
if (!popup->mPopupClosed && popup->mPopupType != ePopupTypeTooltip) {
MOZ_ASSERT(popup->mPopupType != ePopupTypeTooltip,
"Tooltips should be closed!");
// Don't check closed popups and drag source popups
if (!popup->mPopupClosed && !popup->mSourceDragContext) {
if (!popup->IsPopupInLayoutPopupChain(aLayoutWidgetHierarchy,
/* aMustMatchParent */ false)) {
LOG(" hidding popup [%p]", popup);
@ -4084,6 +4086,15 @@ void nsWindow::OnUnmap() {
// untill OnUnrealize is called.
mIsMapped = false;
if (mSourceDragContext) {
static auto sGtkDragCancel =
(void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
if (sGtkDragCancel) {
sGtkDragCancel(mSourceDragContext);
mSourceDragContext = nullptr;
}
}
#ifdef MOZ_WAYLAND
// wl_surface owned by mContainer is going to be deleted.
// Make sure we don't paint to it on Wayland.
@ -5249,6 +5260,7 @@ void nsWindow::OnScaleChanged() {
void nsWindow::DispatchDragEvent(EventMessage aMsg,
const LayoutDeviceIntPoint& aRefPoint,
guint aTime) {
LOGDRAG("nsWindow::DispatchDragEvent");
WidgetDragEvent event(true, aMsg, this);
InitDragEvent(event);
@ -5265,7 +5277,7 @@ void nsWindow::OnDragDataReceivedEvent(GtkWidget* aWidget,
GtkSelectionData* aSelectionData,
guint aInfo, guint aTime,
gpointer aData) {
LOGDRAG("nsWindow::OnDragDataReceived(%p)\n", (void*)this);
LOGDRAG("nsWindow::OnDragDataReceived");
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsDragService::AutoEventLoop loop(dragService);
@ -7437,6 +7449,7 @@ void nsWindow::HideWindowChrome(bool aShouldHide) {
bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
bool aAlwaysRollup) {
LOG("nsWindow::CheckForRollup() aAlwaysRollup %d", aAlwaysRollup);
nsIRollupListener* rollupListener = GetActiveRollupListener();
nsCOMPtr<nsIWidget> rollupWidget;
if (rollupListener) {
@ -7550,13 +7563,11 @@ MOZ_CAN_RUN_SCRIPT static void WaylandDragWorkaround(GdkEventButton* aEvent) {
static nsWindow* get_window_for_gtk_widget(GtkWidget* widget) {
gpointer user_data = g_object_get_data(G_OBJECT(widget), "nsWindow");
return static_cast<nsWindow*>(user_data);
}
static nsWindow* get_window_for_gdk_window(GdkWindow* window) {
gpointer user_data = g_object_get_data(G_OBJECT(window), "nsWindow");
return static_cast<nsWindow*>(user_data);
}
@ -9749,6 +9760,10 @@ LayoutDeviceIntSize nsWindow::GetMozContainerSize() {
return size;
}
nsWindow* nsWindow::GetWindow(GdkWindow* window) {
return get_window_for_gdk_window(window);
}
void nsWindow::ClearRenderingQueue() {
LOG("nsWindow::ClearRenderingQueue()");
@ -9813,3 +9828,7 @@ void nsWindow::NotifyOcclusionState(mozilla::widget::OcclusionState aState) {
mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
}
}
void nsWindow::SetDragSource(GdkDragContext* aSourceDragContext) {
mSourceDragContext = aSourceDragContext;
}

Просмотреть файл

@ -295,6 +295,7 @@ class nsWindow final : public nsBaseWidget {
const LayoutDeviceIntPoint& aRefPoint, guint aTime);
static void UpdateDragStatus(GdkDragContext* aDragContext,
nsIDragService* aDragService);
void SetDragSource(GdkDragContext* aSourceDragContext);
WidgetEventTime GetWidgetEventTime(guint32 aEventTime);
mozilla::TimeStamp GetEventTimeStamp(guint32 aEventTime);
@ -461,6 +462,8 @@ class nsWindow final : public nsBaseWidget {
void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;
static nsWindow* GetWindow(GdkWindow* window);
protected:
virtual ~nsWindow();
@ -980,6 +983,7 @@ class nsWindow final : public nsBaseWidget {
xdg_activation_token_v1* mXdgToken = nullptr;
#endif
mozilla::widget::WindowSurfaceProvider mSurfaceProvider;
GdkDragContext* mSourceDragContext = nullptr;
};
#endif /* __nsWindow_h__ */