diff --git a/mozilla/widget/public/nsIDragSessionGTK.h b/mozilla/widget/public/nsIDragSessionGTK.h index c86674ff268..7be593974c8 100644 --- a/mozilla/widget/public/nsIDragSessionGTK.h +++ b/mozilla/widget/public/nsIDragSessionGTK.h @@ -27,6 +27,8 @@ #include +typedef void (*nsIDragSessionGTKTimeCB)(guint32 *aTime); + #define NS_IDRAGSESSIONGTK_IID \ { 0xa6b49c42, 0x1dd1, 0x11b2, { 0xb2, 0xdf, 0xc1, 0xd6, 0x1d, 0x67, 0x45, 0xcf } }; @@ -37,19 +39,23 @@ class nsIDragSessionGTK : public nsISupports { NS_IMETHOD SetLastContext (GtkWidget *aWidget, GdkDragContext *aContext, guint aTime) = 0; + NS_IMETHOD UpdateDragStatus(GtkWidget *aWidget, + GdkDragContext *aContext, + guint aTime) = 0; NS_IMETHOD SetDataReceived (GtkWidget *aWidget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, - guint32 time) = 0; + guint32 aTime) = 0; NS_IMETHOD DataGetSignal (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, - guint32 time, + guint32 aTime, gpointer data) = 0; + NS_IMETHOD SetTimeCallback (nsIDragSessionGTKTimeCB aCallback) = 0; }; diff --git a/mozilla/widget/src/gtk/nsDragService.cpp b/mozilla/widget/src/gtk/nsDragService.cpp index 4b08a392aec..47f456c8103 100644 --- a/mozilla/widget/src/gtk/nsDragService.cpp +++ b/mozilla/widget/src/gtk/nsDragService.cpp @@ -29,6 +29,7 @@ #include "nsPrimitiveHelpers.h" #include "nsString.h" #include +#include static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID); @@ -71,6 +72,7 @@ nsDragService::nsDragService() mDoingDrag = PR_FALSE; // reset everything ResetDragState(); + mTimeCB = nsnull; } nsDragService::~nsDragService() @@ -84,6 +86,9 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsISupportsArray * anArrayTransf nsIScriptableRegion * aRegion, PRUint32 aActionType) { +#ifdef DEBUG_DD + g_print("InvokeDragSession\n"); +#endif // make sure that we have an array of transferables to use if (!anArrayTransferables) return NS_ERROR_INVALID_ARG; @@ -96,12 +101,34 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsISupportsArray * anArrayTransf // create a target list from the list of transferables GtkTargetList *targetList = targetListFromTransArr(anArrayTransferables); if (targetList) { + // get the last time event. we do this because if we don't then + // gdk_drag_begin() will use the current time as the arg for the + // grab. if you happen to do a drag really quickly and release + // the mouse button before the drag begins ( really easy to do, by + // the way ) then the server ungrab from the mouse button release + // will actually have a time that is _before_ the server grab that + // we are about to cause and it will leave the server in a grabbed + // state after the drag has ended. + guint32 last_event_time = 0; + mTimeCB(&last_event_time); // synth an event so that that fun bug in the gtk dnd code doesn't // rear its ugly head GdkEvent gdk_event; - gdk_event.type = GDK_NOTHING; - gdk_event.any.window = 0; - gdk_event.any.send_event = 0; + gdk_event.type = GDK_BUTTON_PRESS; + gdk_event.button.window = mHiddenWidget->window; + gdk_event.button.send_event = 0; + gdk_event.button.time = last_event_time; + gdk_event.button.x = 0; + gdk_event.button.y = 0; + gdk_event.button.pressure = 0; + gdk_event.button.xtilt = 0; + gdk_event.button.ytilt = 0; + gdk_event.button.state = 0; + gdk_event.button.button = 0; + gdk_event.button.source = (GdkInputSource)0; + gdk_event.button.deviceid = 0; + gdk_event.button.x_root = 0; + gdk_event.button.y_root = 0; // start our drag. GdkDragContext *context = gtk_drag_begin(mHiddenWidget, @@ -112,6 +139,8 @@ NS_IMETHODIMP nsDragService::InvokeDragSession (nsISupportsArray * anArrayTransf // make sure to set our default icon gtk_drag_set_icon_default (context); gtk_target_list_unref(targetList); + // set our last context as this context + SetLastContext(mHiddenWidget, context, gdk_time_get()); } return NS_OK; @@ -129,7 +158,6 @@ NS_IMETHODIMP nsDragService::EndDragSession() { // a drag just ended. reset everything. ResetDragState(); - mDoingDrag = PR_FALSE; return NS_OK; } @@ -139,12 +167,6 @@ NS_IMETHODIMP nsDragService::SetCanDrop (PRBool aCanDrop) #ifdef DEBUG_DD g_print("can drop: %d\n", aCanDrop); #endif - if (aCanDrop) { - gdk_drag_status(mLastContext, GDK_ACTION_COPY, mLastTime); - } - else { - gdk_drag_status(mLastContext, (GdkDragAction)0, mLastTime); - } mCanDrop = aCanDrop; return NS_OK; } @@ -319,6 +341,20 @@ NS_IMETHODIMP nsDragService::SetLastContext (GtkWidget *aWidget, return NS_OK; } +NS_IMETHODIMP nsDragService::UpdateDragStatus(GtkWidget *aWidget, + GdkDragContext *aContext, + guint aTime) +{ +#ifdef DEBUG_DD + g_print("UpdateDragStatus: %d\n", mCanDrop); +#endif + if (mCanDrop) + gdk_drag_status(aContext, GDK_ACTION_COPY, aTime); + else + gdk_drag_status(aContext, (GdkDragAction)0, mLastTime); + return NS_OK; +} + NS_IMETHODIMP nsDragService::SetDataReceived (GtkWidget *aWidget, GdkDragContext *context, gint x, @@ -424,6 +460,15 @@ NS_IMETHODIMP nsDragService::DataGetSignal (GtkWidget *widget, return NS_OK; } +NS_IMETHODIMP nsDragService::SetTimeCallback (nsIDragSessionGTKTimeCB aCallback) +{ +#ifdef DEBUG_DD + g_print("SetTimeCallback %p\n", aCallback); +#endif + mTimeCB = aCallback; + return NS_OK; +} + void nsDragService::ResetDragState(void) { // make sure that all of our last state is set @@ -440,6 +485,8 @@ void nsDragService::ResetDragState(void) mDragData = NULL; } mDragDataLen = 0; + mCanDrop = PR_FALSE; + mDoingDrag = PR_FALSE; } void nsDragService::SetDataItems(nsISupportsArray *anArray) @@ -475,10 +522,6 @@ static void invisibleDragEnd (GtkWidget *widget, // apparently, the drag is over. make sure to tell the drag service // about it. nsCOMPtr dragService; - - gdk_pointer_ungrab(GDK_CURRENT_TIME); - gdk_keyboard_ungrab(GDK_CURRENT_TIME); - nsresult rv = nsServiceManager::GetService(kCDragServiceCID, NS_GET_IID(nsIDragService), (nsISupports **)&dragService); diff --git a/mozilla/widget/src/gtk/nsDragService.h b/mozilla/widget/src/gtk/nsDragService.h index fd97208cd14..79017e87c95 100644 --- a/mozilla/widget/src/gtk/nsDragService.h +++ b/mozilla/widget/src/gtk/nsDragService.h @@ -59,6 +59,9 @@ public: NS_IMETHOD SetLastContext (GtkWidget *aWidget, GdkDragContext *aContext, guint aTime); + NS_IMETHOD UpdateDragStatus(GtkWidget *aWidget, + GdkDragContext *aContext, + guint aTime); NS_IMETHOD SetDataReceived (GtkWidget *aWidget, GdkDragContext *context, gint x, @@ -72,6 +75,7 @@ public: guint info, guint32 time, gpointer data); + NS_IMETHOD SetTimeCallback (nsIDragSessionGTKTimeCB aCallback); // END PUBLIC API @@ -103,6 +107,9 @@ private: void SetDataItems(nsISupportsArray *anArray); // get the data for a particular flavor NS_METHOD GetNativeDragData(GdkAtom aFlavor); + // this is a callback to get the time for the last event that + // happened + nsIDragSessionGTKTimeCB mTimeCB; }; #endif // nsDragService_h__ diff --git a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp index 752304e4b81..3fc736fe21c 100644 --- a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp +++ b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp @@ -852,6 +852,10 @@ handle_gdk_event (GdkEvent *event, gpointer data) { GtkObject *object = nsnull; + guint32 event_time = gdk_event_get_time(event); + if (event_time) + nsWidget::SetLastEventTime(event_time); + if (event->any.window) gdk_window_get_user_data (event->any.window, (void **)&object); diff --git a/mozilla/widget/src/gtk/nsWidget.cpp b/mozilla/widget/src/gtk/nsWidget.cpp index 7d40a953f1f..cb396efe0cb 100644 --- a/mozilla/widget/src/gtk/nsWidget.cpp +++ b/mozilla/widget/src/gtk/nsWidget.cpp @@ -76,6 +76,9 @@ PRUint32 nsWidget::sWidgetCount = 0; // this is the nsWindow with the focus nsWidget *nsWidget::focusWindow = NULL; +// this is the last time that an event happened. we keep this +// around so that we can synth drag events properly +guint32 nsWidget::sLastEventTime = 0; PRBool nsWidget::OnInput(nsInputEvent &aEvent) { @@ -101,6 +104,18 @@ PRBool nsWidget::OnInput(nsInputEvent &aEvent) return ret; } + +void nsWidget::SetLastEventTime(guint32 aTime) +{ + sLastEventTime = aTime; +} + +void nsWidget::GetLastEventTime(guint32 *aTime) +{ + if (aTime) + *aTime = sLastEventTime; +} + nsresult nsWidget::KillICSpotTimer () { if(mICSpotTimer) @@ -169,6 +184,7 @@ nsCOMPtr nsWidget::gRollupListener; nsCOMPtr nsWidget::gRollupWidget; PRBool nsWidget::gRollupConsumeRollupEvent = PR_FALSE; PRBool nsWidget::mGDKHandlerInstalled = PR_FALSE; +PRBool nsWidget::mTimeCBSet = PR_FALSE; #ifdef NS_DEBUG // debugging window @@ -263,6 +279,24 @@ nsWidget::nsWidget() // they have been converted to GDK, but before GTK+ gets them gdk_event_handler_set (handle_gdk_event, NULL, NULL); } + if (mTimeCBSet == PR_FALSE) { + mTimeCBSet = PR_TRUE; + nsCOMPtr dragService; + nsresult rv = nsServiceManager::GetService(kCDragServiceCID, + nsIDragService::GetIID(), + (nsISupports **)&dragService); + if (NS_FAILED(rv)) { + g_print("*** warning: failed to get the drag service. this is a _bad_ thing.\n"); + mTimeCBSet = PR_FALSE; + } + nsCOMPtr dragServiceGTK; + dragServiceGTK = do_QueryInterface(dragService); + if (!dragServiceGTK) { + mTimeCBSet = PR_FALSE; + return; + } + dragServiceGTK->SetTimeCallback(nsWidget::GetLastEventTime); + } #ifdef NS_DEBUG // see if we need to set up the debugging window if (!debugCheckedDebugWindow) { @@ -3150,6 +3184,25 @@ void nsWidget::UpdateDragContext(GtkWidget *aWidget, GdkDragContext *aGdkDragCon } +/* virtual */ +void nsWidget::UpdateDragStatus(GtkWidget *aWidget, GdkDragContext *aGdkDragContext, guint aTime) +{ + // make sure that we tell the drag manager what the hell is going on. + nsCOMPtr dragService; + nsresult rv = nsServiceManager::GetService(kCDragServiceCID, + nsIDragService::GetIID(), + (nsISupports **)&dragService); + if (NS_FAILED(rv)) { + g_print("*** warning: failed to get the drag service. this is a _bad_ thing.\n"); + return; + } + nsCOMPtr dragServiceGTK; + dragServiceGTK = do_QueryInterface(dragService); + if (!dragServiceGTK) { + return; + } + dragServiceGTK->UpdateDragStatus(aWidget, aGdkDragContext, aTime); +} #ifdef NS_DEBUG diff --git a/mozilla/widget/src/gtk/nsWidget.h b/mozilla/widget/src/gtk/nsWidget.h index ed1f933a1ea..2aa6e3097e7 100644 --- a/mozilla/widget/src/gtk/nsWidget.h +++ b/mozilla/widget/src/gtk/nsWidget.h @@ -191,9 +191,14 @@ public: PRBool OnText(nsTextEvent &aEvent) { return OnInput(aEvent); }; PRBool OnComposition(nsCompositionEvent &aEvent) { return OnInput(aEvent); }; PRBool OnInput(nsInputEvent &aEvent); + + // the event handling code needs to let us know the time of the last event + static void SetLastEventTime(guint32 aTime); + static void GetLastEventTime(guint32 *aTime); protected: virtual void UpdateDragContext(GtkWidget *aWidget, GdkDragContext *aGdkDragContext, guint aTime); + virtual void UpdateDragStatus(GtkWidget *aWidget, GdkDragContext *aGdkDragContext, guint aTime); virtual void InitCallbacks(char * aName = nsnull); @@ -453,6 +458,9 @@ protected: nsITimer* mICSpotTimer; static void ICSpotCallback(nsITimer* aTimer, void* aClosure); + // this is the last time that an event happened. we keep this + // around so that we can synth drag events properly + static guint32 sLastEventTime; public: nsresult KillICSpotTimer(); nsresult PrimeICSpotTimer(); @@ -467,6 +475,9 @@ private: // this will keep track of whether or not the gdk handler // is installed yet static PRBool mGDKHandlerInstalled; + // this will keep track of whether or not we've told the drag + // service how to call back into us to get the last event time + static PRBool mTimeCBSet; // // Keep track of the last widget being "dragged" diff --git a/mozilla/widget/src/gtk/nsWindow.cpp b/mozilla/widget/src/gtk/nsWindow.cpp index b6276553f04..64ddbcd9a09 100644 --- a/mozilla/widget/src/gtk/nsWindow.cpp +++ b/mozilla/widget/src/gtk/nsWindow.cpp @@ -1158,74 +1158,6 @@ nsWindow::HandleGDKEvent(GdkEvent *event) default: break; } - - -#if 0 - // this code does it the ugly way. - XEvent xevent; - - switch (event->any.type) - { - case GDK_MOTION_NOTIFY: - OnMotionNotifySignal (&event->motion); - break; - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - { - GdkEventMask mask = (GdkEventMask)(GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_EXPOSURE_MASK | - GDK_FOCUS_CHANGE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK); - - gdk_window_set_events(((GdkEventButton*)event)->window, - mask); - OnButtonPressSignal (&event->button); - - - while (!XCheckTypedEvent(GDK_DISPLAY(), ButtonRelease, &xevent)) { - int x,y; - gdk_window_get_pointer(((GdkEventButton*)event)->window, &x, &y, nsnull); - XMotionEvent bevent; - bevent.x = x; - bevent.y = y; - HandleXlibMotionNotifyEvent(&bevent); - } - XPutBackEvent(GDK_DISPLAY(), &xevent); - - printf("button press finished\n"); - } - break; - - case GDK_BUTTON_RELEASE: - { - GdkEventMask mask = (GdkEventMask)(GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_EXPOSURE_MASK | - GDK_FOCUS_CHANGE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_POINTER_MOTION_MASK); - - gdk_window_set_events(((GdkEventButton*)event)->window, - mask); - - HandleXlibButtonEvent((XButtonEvent *)event); - } - - OnButtonReleaseSignal (&event->button); - break; - default: - break; - } - -#endif } void @@ -1499,10 +1431,8 @@ nsWindow::OnToplevelDragMotion (GtkWidget *aWidget, innerMostWidget->Release(); - // make sure that we set our drag context - GdkDragAction action = GDK_ACTION_COPY; - gdk_drag_status(aDragContext, action, aTime); - + // now that we've dispatched the signal, update the drag context + UpdateDragStatus(aWidget, aDragContext, aTime); } void