a real fix for #28216 instead of the previous work around. also fixes the unix part of bug #27791.

This commit is contained in:
blizzard%redhat.com 2000-02-28 06:13:27 +00:00
Родитель f5f0344430
Коммит c616ebd613
7 изменённых файлов: 142 добавлений и 88 удалений

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

@ -27,6 +27,8 @@
#include <gtk/gtk.h>
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;
};

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

@ -29,6 +29,7 @@
#include "nsPrimitiveHelpers.h"
#include "nsString.h"
#include <gtk/gtkinvisible.h>
#include <gdk/gdkx.h>
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<nsIDragService> dragService;
gdk_pointer_ungrab(GDK_CURRENT_TIME);
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
nsresult rv = nsServiceManager::GetService(kCDragServiceCID,
NS_GET_IID(nsIDragService),
(nsISupports **)&dragService);

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

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

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

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

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

@ -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<nsIRollupListener> nsWidget::gRollupListener;
nsCOMPtr<nsIWidget> 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<nsIDragService> 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<nsIDragSessionGTK> 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<nsIDragService> 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<nsIDragSessionGTK> dragServiceGTK;
dragServiceGTK = do_QueryInterface(dragService);
if (!dragServiceGTK) {
return;
}
dragServiceGTK->UpdateDragStatus(aWidget, aGdkDragContext, aTime);
}
#ifdef NS_DEBUG

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

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

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

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