I’m developing a clone of Yoink for Mac, a small utility that serves as a temporary space where the user could drop anything (a file, a text clip, etc.) that could eventually be re-dragged somewhere else. It’s useful in crowded desktops or to drag something onto a window or an app in another workspace.
As it stands now, it works pretty well with the so called “simple drag and drop” but when it comes to the negotiated drag and drop it can’t work, e.g. a Bitmap clip from ShowImage.
The point is that the receiver sends a reply to the originator that, in this case, is always my application.
DragMessage() handles this internally by using BMessage::Private and the method SetReplyTo(). Is there a practical way to change the originator by providing the BMessenger of the original sender?
You can try to add data to bmessage. See The Be Book - Classes And Methods - The Application Kit
status_t AddMessenger(const char* name, BMessenger messenger);
This adds a BMessenger as a data field, what I need is to set an arbitrary BMessenger as the responder, so that every reply to the message is forwarded to the recipient the BMessenger points to.
The responder can be retrieved by ReturnAddress() but can’t be set via any public method. Unless I’m shortsighted…
DragMessage() sets it using a private BMessagePrivate class and in any case overrides any previous responder (under the form of a pair of BHandler/BLooper).
Is there any code in this app that is useful?
https://depot.haiku-os.org/#!/pkg/filer/haikuports/haikuports_x86_64/1/3/0/-/2/x86_64?bcguid=bc221-UYJX
Filer deals with files only and has code just to handle entry_refs.
I think you would need to make your app act as a relay.
I believe be:sender or something like that is added to the BMessage, so you would need to hold onto the incoming messages, forward on drop, catch replies, then clone the data in the reply message into the original message, then reply to the original message.
For security reasons we wouldn’t want to really enable apps to spoof the sender.
This was the first solution I thought of and I’m implementing it right now but I hoped there was a less convoluted way without messing up with the inner workings of BView & C.
Or at least a way I could not spot at first sight.
I understand the concern, all in all this is a very special case that can’t justify such a change at the API level.
A “good” way could be sending a message to the original drag and drop initiating app that a new one is to be initiated to the target app.
But other than that just beeing a relay is probably the cleanest solution.
How do you deal with negotiated drag and drop when the origin app dies? I guess there must be a way this is done already currently.
I’m not at that point yet but each app will see DropIt! (This is the temporary name of this app) either as the recipient or the originator.
The only thing I can do is to return an error in case one of them terminates abruptly. Nevertheless, I think it’s up to the apps to properly handle such a case.
Just an example: if I drop a bitmap clip from ShowImage onto DropIt!! (without the “relay” capability) then I re-drag it onto the Tracker, the clip gets created anyway but empty. That means that the Tracker doesn’t care whether it receives a response or not and the operation is not rolled back in case of error or the response does not come through.
It turned out it does not work for some reason, and there is no need to clone the data into the original message.
In essence, I keep a copy of the drag message, the sender’s BMessenger via ReturnAddress() and add a correlation ID (NegotiationID) to it.
Whenever I receive a reply message where IsReply() is true, I check the Previous() message for the NegotiationID and check who sent it. if everything matches I simply forward it to the original sender:
fSender.SendMessage(replyMessage);
replyMessage retains the replyTo value (actualy a valid BMessenger) and the reply status, it is processed by the sender application (e.g. ShowImage) and the reply is sent back to the destination (e.g. the Tracker) directly without passing through “DropIt!”.
EDIT: here’s an example of how it works. It is quite embryonic but this proves it’s all feasible…
I think I’ll use this thread to discuss everything related to this app…
I have tried to drag a file onto DropIt! and redrag it onto Telegram but it fails. Dragging directly from the Tracker works and I’m sure the message being redragged is the same I receive.
Telegram prints a quite cryptic
TWidget(0x114f45934678) : No drag target set.
When dragging from the Tracker it does not log anything and goes ahead showing the typical popup.
Does anybody have a clue?
EDIT: I’ll try again in case it went unnoticed. Maybe @3dEyes may know why?
Ah very nice, I love drag’n drop.
How do you get the marque-tool selected at start?
Standard is: nothing is selected in the player.
To be able to drag’n drop a Text font would be great!
Is this possible at all?
Sorry, what is the marquee-tool?
Do you mean a styled text, actually?
The marque-tool is the one to select an area in the picture. Ant line…
Not the font type like: ARIAL, Comic Sans, Bodoni, or Garamond
It would be cool to grab a font and drop it on a text file to change the font.
Just an idea!
I have prepared the desktop for the recording by opening three images and have pre-selected a small area beforehand. In ShowImage there’s the fourth icon from the left in the toolbar that does that job. Hope this helps.
DropIt! is designed to temporary store a dropped item (technically it’s a BMessage) and redrag it somewhere else. Except the challenge of the negotiated vs simple drag and drop, it does not deal with the content itself.
Please remember that sender and the receiver need to agree on a common “language” by conforming to the protocol explained in the Be Book (be it simple or negotiated), so it’s really up to them to do whatever they want.
This would be a very specific use case, probably something to implement in StyledEdit?