diff --git a/widget/gtk2/gtk2compat.h b/widget/gtk2/gtk2compat.h index dbbd1da0cbe..faf86f268dd 100644 --- a/widget/gtk2/gtk2compat.h +++ b/widget/gtk2/gtk2compat.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -103,6 +103,12 @@ gtk_widget_has_focus(GtkWidget *widget) return GTK_WIDGET_HAS_FOCUS(widget); } +static inline gboolean +gtk_widget_has_grab(GtkWidget *widget) +{ + return GTK_WIDGET_HAS_GRAB(widget); +} + static inline void gtk_widget_get_allocation(GtkWidget *widget, GtkAllocation *allocation) { @@ -181,6 +187,15 @@ gdk_drag_context_get_actions(GdkDragContext *context) { return context->actions; } + +static inline GtkWidget * +gtk_window_group_get_current_grab(GtkWindowGroup *window_group) +{ + if (!window_group->grabs) + return NULL; + + return GTK_WIDGET(window_group->grabs->data); +} #endif #if !GTK_CHECK_VERSION(2, 24, 0) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index f8648770284..06cf8f5f145 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -73,6 +73,7 @@ #include "nsPresContext.h" #include "nsIDocument.h" #include "nsISelection.h" +#include "nsIViewManager.h" #include "nsIFrame.h" // This sets how opaque the drag image is @@ -140,7 +141,7 @@ nsDragService::nsDragService() obsServ->AddObserver(this, "quit-application", false); // our hidden source widget - mHiddenWidget = gtk_invisible_new(); + mHiddenWidget = gtk_window_new(GTK_WINDOW_POPUP); // make sure that the widget is realized so that // we can use it as a drag source. gtk_widget_realize(mHiddenWidget); @@ -264,7 +265,7 @@ DispatchMotionEventCopy(gpointer aData) // If there is no longer a grab on the widget, then the drag is over and // there is no need to continue drag motion. - if (gtk_grab_get_current() == data->mWidget) { + if (gtk_widget_has_grab(data->mWidget)) { gtk_propagate_event(data->mWidget, data->mEvent); } @@ -286,7 +287,7 @@ OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data) // If there is no longer a grab on the widget, then the drag motion is // over (though the data may not be fetched yet). - if (gtk_grab_get_current() != widget) + if (!gtk_widget_has_grab(widget)) return; // Update the cursor position. The last of these recorded gets used for @@ -308,6 +309,39 @@ OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data) DispatchMotionEventCopy, data, DestroyMotionEventData); } +static GtkWindow* +GetGtkWindow(nsIDOMDocument *aDocument) +{ + nsCOMPtr doc = do_QueryInterface(aDocument); + if (!doc) + return NULL; + + nsCOMPtr presShell = doc->GetShell(); + if (!presShell) + return NULL; + + nsCOMPtr vm = presShell->GetViewManager(); + if (!vm) + return NULL; + + nsCOMPtr widget; + vm->GetRootWidget(getter_AddRefs(widget)); + if (!widget) + return NULL; + + GtkWidget *gtkWidget = + static_cast(widget.get())->GetMozContainerWidget(); + if (!gtkWidget) + return NULL; + + GtkWidget *toplevel = NULL; + toplevel = gtk_widget_get_toplevel(gtkWidget); + if (!GTK_IS_WINDOW(toplevel)) + return NULL; + + return GTK_WINDOW(toplevel); +} + // nsIDragService NS_IMETHODIMP @@ -366,6 +400,14 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode, event.button.window = mHiddenWidget->window; event.button.time = nsWindow::GetLastUserInputTime(); + // Put the drag widget in the window group of the source node so that the + // gtk_grab_add during gtk_drag_begin is effective. + // gtk_window_get_group(NULL) returns the default window group. + GtkWindowGroup *window_group = + gtk_window_get_group(GetGtkWindow(mSourceDocument)); + gtk_window_group_add_window(window_group, + GTK_WINDOW(mHiddenWidget)); + // start our drag. GdkDragContext *context = gtk_drag_begin(mHiddenWidget, sourceList, @@ -379,7 +421,7 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode, StartDragSession(); // GTK uses another hidden window for receiving mouse events. - mGrabWidget = gtk_grab_get_current(); + mGrabWidget = gtk_window_group_get_current_grab(window_group); if (mGrabWidget) { g_object_ref(mGrabWidget); // Only motion events are required but connect to diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index d467c2f2161..6f14cedd543 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -271,9 +271,6 @@ static void drag_data_received_event_cb(GtkWidget *aWidget, /* initialization static functions */ static nsresult initialize_prefs (void); -// Time of the last button release event. We use it to detect when the -// drag ended before we could properly setup drag and drop. -static guint32 sLastButtonReleaseTime = 0; static guint32 sLastUserInputTime = GDK_CURRENT_TIME; static guint32 sRetryGrabTime; @@ -2630,8 +2627,6 @@ nsWindow::DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent) synthEvent.button = buttonType; nsEventStatus status; DispatchEvent(&synthEvent, status); - - sLastButtonReleaseTime = aGdkEvent->time; } } } @@ -2712,9 +2707,6 @@ nsWindow::OnButtonPressEvent(GtkWidget *aWidget, GdkEventButton *aEvent) return; } - // We haven't received the corresponding release event yet. - sLastButtonReleaseTime = 0; - nsWindow *containerWindow = GetContainerWindow(); if (!gFocusWindow && containerWindow) { containerWindow->DispatchActivateEvent(); @@ -2798,8 +2790,6 @@ nsWindow::OnButtonReleaseEvent(GtkWidget *aWidget, GdkEventButton *aEvent) LOG(("Button %u release on %p\n", aEvent->button, (void *)this)); PRUint16 domButton; - sLastButtonReleaseTime = aEvent->time; - switch (aEvent->button) { case 1: domButton = nsMouseEvent::eLeftButton; @@ -5656,24 +5646,6 @@ drag_motion_event_cb(GtkWidget *aWidget, if (!window) return FALSE; - if (sLastButtonReleaseTime) { - // The drag ended before it was even setup to handle the end of the drag - // So, we fake the button getting released again to release the drag - GtkWidget *widget = gtk_grab_get_current(); - GdkEvent event; - gboolean retval; - memset(&event, 0, sizeof(event)); - event.type = GDK_BUTTON_RELEASE; - event.button.time = sLastButtonReleaseTime; - event.button.button = 1; - sLastButtonReleaseTime = 0; - if (widget) { - g_signal_emit_by_name(widget, "button_release_event", &event, &retval); - // FALSE means we won't reply with a status message. - return FALSE; - } - } - // figure out which internal widget this drag motion actually happened on nscoord retx = 0; nscoord rety = 0;