b=751429 handle modifier changes in periodic synthetic mouse events for drag sources r=roc

--HG--
extra : rebase_source : 08c12b5e4e2acb7e65ff29168356312eb9185d97
This commit is contained in:
Karl Tomlinson 2012-05-03 18:24:20 +12:00
Родитель 932d9c2d5b
Коммит 632012d2ac
2 изменённых файлов: 50 добавлений и 57 удалений

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

@ -100,7 +100,12 @@ FuncToGpointer(T aFunction)
}
static PRLogModuleInfo *sDragLm = NULL;
// data used for synthetic periodic motion events sent to the source widget
// grabbing real events for the drag.
static guint sMotionEventTimerID;
static GdkEvent *sMotionEvent;
static GtkWidget *sGrabWidget;
static const char gMimeListType[] = "application/x-moz-internal-item-list";
static const char gMozUrlType[] = "_NETSCAPE_URL";
@ -167,7 +172,6 @@ nsDragService::nsDragService()
if (!sDragLm)
sDragLm = PR_NewLogModule("nsDragService");
PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::nsDragService"));
mGrabWidget = 0;
mCanDrop = false;
mTargetDragDataReceived = false;
mTargetDragData = 0;
@ -232,42 +236,21 @@ nsDragService::Observe(nsISupports *aSubject, const char *aTopic,
// change its feedback re whether it could accept the drop, and so the
// source's behavior on drop will not be consistent.)
struct MotionEventData {
MotionEventData(GtkWidget *aWidget, GdkEvent *aEvent)
: mWidget(aWidget), mEvent(gdk_event_copy(aEvent))
{
MOZ_COUNT_CTOR(MotionEventData);
g_object_ref(mWidget);
}
~MotionEventData()
{
MOZ_COUNT_DTOR(MotionEventData);
g_object_unref(mWidget);
gdk_event_free(mEvent);
}
GtkWidget *mWidget;
GdkEvent *mEvent;
};
static void
DestroyMotionEventData(gpointer data)
{
delete static_cast<MotionEventData*>(data);
}
static gboolean
DispatchMotionEventCopy(gpointer aData)
{
MotionEventData *data = static_cast<MotionEventData*>(aData);
// Clear the timer id before OnSourceGrabEventAfter is called during event dispatch.
// Clear the timer id before OnSourceGrabEventAfter is called during event
// dispatch.
sMotionEventTimerID = 0;
GdkEvent *event = sMotionEvent;
sMotionEvent = NULL;
// 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_widget_has_grab(data->mWidget)) {
gtk_propagate_event(data->mWidget, data->mEvent);
if (gtk_widget_has_grab(sGrabWidget)) {
gtk_propagate_event(sGrabWidget, event);
}
gdk_event_free(event);
// Cancel this timer;
// We've already started another if the motion event was dispatched.
@ -277,27 +260,35 @@ DispatchMotionEventCopy(gpointer aData)
static void
OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
if (event->type != GDK_MOTION_NOTIFY)
// 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_widget_has_grab(sGrabWidget))
return;
GdkModifierType state;
if (event->type == GDK_MOTION_NOTIFY) {
if (sMotionEvent) {
gdk_event_free(sMotionEvent);
}
sMotionEvent = gdk_event_copy(event);
// Update the cursor position. The last of these recorded gets used for
// the NS_DRAGDROP_END event.
nsDragService *dragService = static_cast<nsDragService*>(user_data);
dragService->SetDragEndPoint(nsIntPoint(event->motion.x_root,
event->motion.y_root));
} else if (sMotionEvent && (event->type != GDK_KEY_PRESS ||
event->type != GDK_KEY_RELEASE)) {
// Update modifier state from keypress events.
sMotionEvent->motion.state = event->key.state;
} else {
return;
}
if (sMotionEventTimerID) {
g_source_remove(sMotionEventTimerID);
sMotionEventTimerID = 0;
}
// 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_widget_has_grab(widget))
return;
// Update the cursor position. The last of these recorded gets used for
// the NS_DRAGDROP_END event.
nsDragService *dragService = static_cast<nsDragService*>(user_data);
dragService->
SetDragEndPoint(nsIntPoint(event->motion.x_root, event->motion.y_root));
MotionEventData *data = new MotionEventData(widget, event);
// G_PRIORITY_DEFAULT_IDLE is lower priority than GDK's redraw idle source
// and lower than GTK's idle source that sends drag position messages after
// motion-notify signals.
@ -306,7 +297,7 @@ OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data)
// recommends an interval of 350ms +/- 200ms.
sMotionEventTimerID =
g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 350,
DispatchMotionEventCopy, data, DestroyMotionEventData);
DispatchMotionEventCopy, NULL, NULL);
}
static GtkWindow*
@ -353,7 +344,7 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::InvokeDragSession"));
// If the previous source drag has not yet completed, signal handlers need
// to be removed from mGrabWidget and dragend needs to be dispatched to
// to be removed from sGrabWidget and dragend needs to be dispatched to
// the source node, but we can't call EndDragSession yet because we don't
// know whether or not the drag succeeded.
if (mSourceNode)
@ -421,12 +412,12 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
StartDragSession();
// GTK uses another hidden window for receiving mouse events.
mGrabWidget = gtk_window_group_get_current_grab(window_group);
if (mGrabWidget) {
g_object_ref(mGrabWidget);
// Only motion events are required but connect to
sGrabWidget = gtk_window_group_get_current_grab(window_group);
if (sGrabWidget) {
g_object_ref(sGrabWidget);
// Only motion and key events are required but connect to
// "event-after" as this is never blocked by other handlers.
g_signal_connect(mGrabWidget, "event-after",
g_signal_connect(sGrabWidget, "event-after",
G_CALLBACK(OnSourceGrabEventAfter), this);
}
// We don't have a drag end point yet.
@ -504,16 +495,20 @@ nsDragService::EndDragSession(bool aDoneDrag)
PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::EndDragSession %d",
aDoneDrag));
if (mGrabWidget) {
g_signal_handlers_disconnect_by_func(mGrabWidget,
if (sGrabWidget) {
g_signal_handlers_disconnect_by_func(sGrabWidget,
FuncToGpointer(OnSourceGrabEventAfter), this);
g_object_unref(mGrabWidget);
mGrabWidget = NULL;
g_object_unref(sGrabWidget);
sGrabWidget = NULL;
if (sMotionEventTimerID) {
g_source_remove(sMotionEventTimerID);
sMotionEventTimerID = 0;
}
if (sMotionEvent) {
gdk_event_free(sMotionEvent);
sMotionEvent = NULL;
}
}
// unset our drag action

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

@ -207,8 +207,6 @@ private:
// the source of our drags
GtkWidget *mHiddenWidget;
// the widget receiving mouse events
GtkWidget *mGrabWidget;
// our source data items
nsCOMPtr<nsISupportsArray> mSourceDataItems;