From c51d0337a1561c75f253a2cfd70ce48585c5f86e Mon Sep 17 00:00:00 2001 From: Alexandre Deckner Date: Mon, 6 Apr 2009 19:15:00 +0000 Subject: [PATCH] * Rewrote BDragger's mouse tracking to be asynchronous using a message filter. Placed the filter in kits/shared since i plan to use it in other places like Tracker. Animated replicants like ActivityMonitor wont stall anymore when initiating the drag. (On the desktop, Tracker's mouse tracking still busy loops sometimes, that's next on my list). I had asynchronous long click detection (one button mouse support) in it but decided to get rid of it, it adds unneeded complexity in the code and is even getting in your way sometimes (ex: now you can take your time to drag the dragger, you wont be interrupted). If we want to reimplement that someday it should be done system wide anyway (only Tracker and replicants have that 'feature' AFAIK). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29972 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/interface/Dragger.h | 4 +- headers/private/shared/DragTrackingFilter.h | 34 +++++++ src/kits/interface/Dragger.cpp | 105 +++++++------------- src/kits/shared/DragTrackingFilter.cpp | 88 ++++++++++++++++ src/kits/shared/Jamfile | 1 + 5 files changed, 163 insertions(+), 69 deletions(-) create mode 100644 headers/private/shared/DragTrackingFilter.h create mode 100644 src/kits/shared/DragTrackingFilter.cpp diff --git a/headers/os/interface/Dragger.h b/headers/os/interface/Dragger.h index 55aa70c672..b1300b87a0 100644 --- a/headers/os/interface/Dragger.h +++ b/headers/os/interface/Dragger.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _DRAGGER_H @@ -115,7 +115,7 @@ class BDragger : public BView { bool fIsZombie; char fErrCount; bool fPopUpIsCustom; - BBitmap * fBitmap; + BBitmap* fBitmap; BPopUpMenu* fPopUp; uint32 _reserved[3]; }; diff --git a/headers/private/shared/DragTrackingFilter.h b/headers/private/shared/DragTrackingFilter.h new file mode 100644 index 0000000000..9d8eb0f0ce --- /dev/null +++ b/headers/private/shared/DragTrackingFilter.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Alexandre Deckner, alex@zappotek.com + * Distributed under the terms of the MIT License. + */ +#ifndef DRAG_TRACKING_FILTER_H +#define DRAG_TRACKING_FILTER_H + +#include +#include + +class BView; +class BHandler; + +namespace BPrivate { + +class DragTrackingFilter : public BMessageFilter { +public: + DragTrackingFilter(BView* targetView, uint32 messageWhat); + + filter_result Filter(BMessage* message, BHandler** _target); + +private: + BView* fTargetView; + uint32 fMessageWhat; + bool fIsTracking; + BPoint fClickPoint; + uint32 fClickButtons; +}; + +} // namespace BPrivate + +using BPrivate::DragTrackingFilter; + +#endif // DRAG_TRACKING_FILTER_H diff --git a/src/kits/interface/Dragger.cpp b/src/kits/interface/Dragger.cpp index 3182e962da..d3b0bd7c3b 100644 --- a/src/kits/interface/Dragger.cpp +++ b/src/kits/interface/Dragger.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2001-2008, Haiku. + * Copyright 2001-2009, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Marc Flerackers (mflerackers@androme.be) * Rene Gollent (rene@gollent.com) + * Alexandre Deckner (alex@zappotek.com) */ //! BDragger represents a replicant "handle". @@ -25,6 +26,7 @@ #include #include +#include #include #include #include @@ -37,6 +39,7 @@ bool BDragger::sVisibleInitialized; BLocker BDragger::sLock("BDragger static"); BList BDragger::sList; +const uint32 kMsgDragStarted = 'Drgs'; const unsigned char kHandBitmap[] = { @@ -153,6 +156,8 @@ BDragger::AttachedToWindow() _DetermineRelationship(); _AddToList(); + + AddFilter(new DragTrackingFilter(this, kMsgDragStarted)); } @@ -211,73 +216,8 @@ BDragger::MouseDown(BPoint where) uint32 buttons; Window()->CurrentMessage()->FindInt32("buttons", (int32 *)&buttons); - if (buttons & B_SECONDARY_MOUSE_BUTTON) { - if (!fShelf) - return; - + if (fShelf != NULL && (buttons & B_SECONDARY_MOUSE_BUTTON)) _ShowPopUp(fTarget, where); - } else { - bigtime_t time = system_time(); - bigtime_t clickSpeed = 0; - - get_click_speed(&clickSpeed); - - bool drag = false; - - while (true) { - BPoint mousePoint; - GetMouse(&mousePoint, &buttons, false); - - if (!buttons || system_time() > time + clickSpeed) - break; - - float squaredDistance = - (mousePoint.x - where.x) * (mousePoint.x - where.x) - + (mousePoint.y - where.y) * (mousePoint.y - where.y); - - if (squaredDistance >= 16) { - drag = true; - break; - } - - snooze(40000); - } - - if (drag) { - BMessage archive(B_ARCHIVED_OBJECT); - - if (fRelation == TARGET_IS_PARENT) - fTarget->Archive(&archive); - else if (fRelation == TARGET_IS_CHILD) - Archive(&archive); - else { - if (fTarget->Archive(&archive)) { - BMessage archivedSelf(B_ARCHIVED_OBJECT); - - if (Archive(&archivedSelf)) - archive.AddMessage("__widget", &archivedSelf); - } - } - - archive.AddInt32("be:actions", B_TRASH_TARGET); - - BPoint offset; - drawing_mode mode; - BBitmap *bitmap = DragBitmap(&offset, &mode); - if (bitmap != NULL) - DragMessage(&archive, bitmap, mode, offset, this); - else { - DragMessage(&archive, - ConvertFromScreen(fTarget->ConvertToScreen(fTarget->Bounds())), - this); - } - } else { - if (!fShelf) - return; - - _ShowPopUp(fTarget, where); - } - } } @@ -328,6 +268,37 @@ BDragger::MessageReceived(BMessage *msg) } break; + case kMsgDragStarted: + if (fTarget != NULL) { + BMessage archive(B_ARCHIVED_OBJECT); + + if (fRelation == TARGET_IS_PARENT) + fTarget->Archive(&archive); + else if (fRelation == TARGET_IS_CHILD) + Archive(&archive); + else { + if (fTarget->Archive(&archive)) { + BMessage archivedSelf(B_ARCHIVED_OBJECT); + + if (Archive(&archivedSelf)) + archive.AddMessage("__widget", &archivedSelf); + } + } + + archive.AddInt32("be:actions", B_TRASH_TARGET); + BPoint offset; + drawing_mode mode; + BBitmap *bitmap = DragBitmap(&offset, &mode); + if (bitmap != NULL) + DragMessage(&archive, bitmap, mode, offset, this); + else { + DragMessage(&archive, + ConvertFromScreen(fTarget->ConvertToScreen(fTarget->Bounds())), + this); + } + } + break; + default: BView::MessageReceived(msg); break; diff --git a/src/kits/shared/DragTrackingFilter.cpp b/src/kits/shared/DragTrackingFilter.cpp new file mode 100644 index 0000000000..9c4b0dd8ed --- /dev/null +++ b/src/kits/shared/DragTrackingFilter.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2009, Alexandre Deckner, alex@zappotek.com + * Distributed under the terms of the MIT License. + */ + +/*! + \class DragTrackingFilter + \brief A simple mouse drag detection filter + * + * A simple mouse filter that detects the start of a mouse drag over a + * threshold distance and sends a message with the 'what' field of your + * choice. Especially usefull for drag and drop. + * Allows you to free your code of encumbering mouse tracking details. + * + * It can detect fast drags spanning outside of a small view by temporarily + * setting the B_POINTER_EVENTS flag on the view. +*/ + +#include + +#include +#include +#include + +static const int kSquaredDragThreshold = 9; + +DragTrackingFilter::DragTrackingFilter(BView* targetView, uint32 messageWhat) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), + fTargetView(targetView), + fMessageWhat(messageWhat), + fIsTracking(false), + fClickButtons(0) +{ +} + + +filter_result +DragTrackingFilter::Filter(BMessage* message, BHandler** /*_target*/) +{ + if (fTargetView == NULL) + return B_DISPATCH_MESSAGE; + + switch (message->what) { + case B_MOUSE_DOWN: + message->FindPoint("where", &fClickPoint); + message->FindInt32("buttons", (int32*)&fClickButtons); + fIsTracking = true; + + fTargetView->SetMouseEventMask(B_POINTER_EVENTS); + + return B_DISPATCH_MESSAGE; + + case B_MOUSE_UP: + fIsTracking = false; + return B_DISPATCH_MESSAGE; + + case B_MOUSE_MOVED: + { + BPoint where; + message->FindPoint("be:view_where", &where); + + // TODO: be more flexible about buttons and pass their state + // in the message + if (fIsTracking && (fClickButtons & B_PRIMARY_MOUSE_BUTTON)) { + + BPoint delta(fClickPoint - where); + float squaredDelta = (delta.x * delta.x) + (delta.y * delta.y); + + if (squaredDelta >= kSquaredDragThreshold) { + BMessage dragClickMessage(fMessageWhat); + dragClickMessage.AddPoint("be:view_where", fClickPoint); + // name it "be:view_where" since BView::DragMessage + // positions the dragging frame/bitmap by retrieving the + // current message and reading that field + BMessenger messenger(fTargetView); + messenger.SendMessage(&dragClickMessage); + + fIsTracking = false; + } + } + return B_DISPATCH_MESSAGE; + } + default: + break; + } + + return B_DISPATCH_MESSAGE; +} diff --git a/src/kits/shared/Jamfile b/src/kits/shared/Jamfile index 5a010c3f9f..13adeb3666 100644 --- a/src/kits/shared/Jamfile +++ b/src/kits/shared/Jamfile @@ -17,6 +17,7 @@ StaticLibrary libshared.a : ColorQuantizer.cpp CommandPipe.cpp DateTime.cpp + DragTrackingFilter.cpp HashString.cpp RWLockManager.cpp ;