зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
932d9c2d5b
Коммит
632012d2ac
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче