Skip to content

Commit

Permalink
Bug 1795849 [Linux] Chancel D&D operation on Wayland and XWayland whe…
Browse files Browse the repository at this point in the history
…n D&D source window is closing r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D159588
  • Loading branch information
stransky committed Oct 19, 2022
1 parent 4cc3078 commit 599b985
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 10 deletions.
3 changes: 1 addition & 2 deletions widget/gtk/GfxInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions widget/gtk/WidgetUtilsGtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 2 additions & 0 deletions widget/gtk/WidgetUtilsGtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 18 additions & 3 deletions widget/gtk/nsDragService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions widget/gtk/nsDragService.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
29 changes: 24 additions & 5 deletions widget/gtk/nsWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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()");

Expand Down Expand Up @@ -9813,3 +9828,7 @@ void nsWindow::NotifyOcclusionState(mozilla::widget::OcclusionState aState) {
mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
}
}

void nsWindow::SetDragSource(GdkDragContext* aSourceDragContext) {
mSourceDragContext = aSourceDragContext;
}
4 changes: 4 additions & 0 deletions widget/gtk/nsWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -461,6 +462,8 @@ class nsWindow final : public nsBaseWidget {

void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;

static nsWindow* GetWindow(GdkWindow* window);

protected:
virtual ~nsWindow();

Expand Down Expand Up @@ -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__ */

0 comments on commit 599b985

Please sign in to comment.