b=750061 Put the hidden drag widget in the window group of the source node so that the gtk_grab_add during gtk_drag_begin is effective r=roc

--HG--
extra : rebase_source : 8ce17ca75be2b681f08489446bb8fdb2d651fe46
This commit is contained in:
Karl Tomlinson 2012-05-03 18:23:59 +12:00
parent a6b5afba17
commit cedf9acac4
3 changed files with 63 additions and 34 deletions

View File

@ -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)

View File

@ -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<nsIDocument> doc = do_QueryInterface(aDocument);
if (!doc)
return NULL;
nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
if (!presShell)
return NULL;
nsCOMPtr<nsIViewManager> vm = presShell->GetViewManager();
if (!vm)
return NULL;
nsCOMPtr<nsIWidget> widget;
vm->GetRootWidget(getter_AddRefs(widget));
if (!widget)
return NULL;
GtkWidget *gtkWidget =
static_cast<nsWindow*>(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

View File

@ -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;