Skip to content

Add drag and drop support#2265

Draft
justanobdy wants to merge 1 commit intoSFML:masterfrom
justanobdy:X11DnD
Draft

Add drag and drop support#2265
justanobdy wants to merge 1 commit intoSFML:masterfrom
justanobdy:X11DnD

Conversation

@justanobdy
Copy link

@justanobdy justanobdy commented Oct 30, 2022

Description

Edited to reflect new changes

This pull request adds file dropping support on Windows, X11, and MacOS. Unfortunately, this does not work on Wayland, even under xWayland.

Notes:

  • File drops are manually split into std::vectors on X11, which is less than ideal.
  • The file dropping API used on MacOS is the old, deprecated version, but because OpenGL is deprecated on MacOS, we are forced to use it.

Example

#include <SFML/Graphics.hpp>
#include <iostream>

int main() {
    sf::RenderWindow window(sf::VideoMode(sf::Vector2u{300, 300}), "dnd test", sf::State::Windowed);

    window.setFileDroppingEnabled(true);

    while(window.isOpen()) {
        while(const std::optional event = window.pollEvent()) {
            if(event->is<sf::Event::Closed>()) {
                window.close();
            }
            
            if(const auto dropped = event->getIf<sf::Event::FilesDropped>()) {
                for (const auto& item : dropped->filenames)
                {
                    std::cout << "This file was dropped: " << item.toAnsiString() << std::endl;
                }
            }
        }

        window.clear();

        window.display();
    }
}

@codecov
Copy link

codecov bot commented Oct 30, 2022

Codecov Report

Merging #2265 (a3555f1) into master (7faa550) will decrease coverage by 0.14%.
The diff coverage is 0.00%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2265      +/-   ##
==========================================
- Coverage   14.98%   14.83%   -0.15%     
==========================================
  Files         213      208       -5     
  Lines       15255    15317      +62     
  Branches     4072     4087      +15     
==========================================
- Hits         2286     2273      -13     
- Misses      12821    12914      +93     
+ Partials      148      130      -18     
Impacted Files Coverage Δ
include/SFML/Window/Window.hpp 0.00% <ø> (ø)
src/SFML/Window/Unix/WindowImplX11.cpp 0.18% <0.00%> (-0.01%) ⬇️
src/SFML/Window/Win32/WindowImplWin32.cpp 0.00% <0.00%> (ø)
src/SFML/Window/Win32/WindowImplWin32.hpp 0.00% <ø> (ø)
src/SFML/Window/Window.cpp 0.00% <0.00%> (ø)
src/SFML/Window/WindowImpl.cpp 0.00% <0.00%> (ø)
src/SFML/Window/WindowImpl.hpp 0.00% <ø> (ø)
include/SFML/System/String.hpp 0.00% <0.00%> (-100.00%) ⬇️
include/SFML/System/Clock.hpp 50.00% <0.00%> (-50.00%) ⬇️
include/SFML/Graphics/Shape.hpp 0.00% <0.00%> (-50.00%) ⬇️
... and 40 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7faa550...a3555f1. Read the comment docs.

@JonnyPtn
Copy link
Contributor

I think the main thing needed here (along with #1222) is a decision on whether to support multiple types or not. Otherwise it looks reasonable.

For what it's worth I would suggesting starting with support for files and text, then it can be expanded later if desired

@justanobdy
Copy link
Author

I agree, only supporting files and text is enough for most people right now. The only thing we still need to do is agree on an API which works on all platforms, and make sure file dropping works on all the platforms that support it.

Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

This seems like yet another PR which might suffer from having no modern sf::Event API (see comment). I would advocate we do not block it on that issue though, since that may take forever. Also, SFML 3 APIs are in flux and can be modified at any time.

But we should probably write a TODO and possibly a GitHub issue, so we don't forget this.

Comment on lines 2248 to 2296
// Get the dropped item by getting the XdndSelection property
m_droppedItem = getWindowStringProperty(m_display, m_window, windowEvent.xselection.property);

Event event;
event.type = Event::ItemDropped;
event.itemDropped.item = &m_droppedItem;
event.itemDropped.x = m_dropPosition.x;
event.itemDropped.y = m_dropPosition.y;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing the event string in the window is asking for trouble.

If another ItemDroppedEvent is processed while the first one is still alive, the string is suddenly wrong. In other words, it's possible that a const ItemDroppedEvent suddenly changes contents only by external means. You will also get UB through dangling pointer if e.g. the underlying sf::Window is moved while the event is still around.

Granted, these are edge cases, but ideally we'd have an API that's robust enough to not fall apart when a user wants to do more unconventional things.

I'm aware that the union approach we're using here is very limited, and this is actually a good example to show why. I don't know yet what a good API would look like. std::variant is unfortunately verbose as hell and really not fun to work with.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it is possible to get multiple drop events at once, because I don't think XdndDrop can be called multiple times per frame. (It might be possible if the user is deliberately trying, but I'm not really sure what could be done about that)

About the dangling pointer, I don't really know what could be done about that.

Comment on lines 2415 to 2416
// Signal the selection owner that we have successfully read the data.
XDeleteProperty(dpy, w, p);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have two XGetWindowProperty calls, but only one XDeleteProperty.

Is this correct? Do we not leak memory?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 2409 to 2413
XGetWindowProperty(dpy, w, p, 0, static_cast<long>(size), false, AnyPropertyType, &da, &di, &dul, &dul, &prop_ret);

String value = reinterpret_cast<char*>(prop_ret);

XFree(prop_ret);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These statements could be grouped (no empty lines) so we know they are closely related.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 2392 to 2395
Atom da, incr, type;
int di;
unsigned long size, dul;
unsigned char* prop_ret = NULL;
Copy link
Member

@Bromeon Bromeon Nov 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please declare variables as late as possible -- only once you need them. If possible, initialize them immediately during declaration.

Declaring everything at the beginning of the function is relatively outdated C practice, either mandated by old compilers or a way to measure stack memory usage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took this code from https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html, and i didn't test it very thoroughly, I just wanted to make a quick draft PR so we could figure out how to get it to work on multiple platforms, and then I would go and polish it up before merging it into master.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also like to see Bromeon's comments be addressed even if this is just a draft PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've completely changed how the selection is converted. I modded the conversion code from https://github.com/SFML/SFML/blob/master/src/SFML/Window/Unix/ClipboardImpl.cpp to work with mine.

@justanobdy justanobdy force-pushed the X11DnD branch 2 times, most recently from 0182953 to 66c75c1 Compare November 18, 2022 21:46
@ChrisThrasher
Copy link
Member

ChrisThrasher commented Nov 18, 2022

I see you're using clang-format-15. Sadly that version breaks lots of vertical alignment rules so it produces very different results from versions 12, 13, and 14 which we're using in CI. I don't have a great solution other than try to use one of those 3 versions if you can your hands on an installation of it.

@justanobdy
Copy link
Author

Ah, that's why it changed some random stuff. I upgraded from Leap 15.4 to Tumbleweed, so that's why it changed. I'll try to see if I can get 14 on my machine.

@justanobdy
Copy link
Author

Ok, I've used clang-format-13 and pushed the changes.

class WindowImplCocoa;
}
}
} // namespace sf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing these got added because you used clang-format-15 to format. You can remove these since we now disallow using clang-format-15.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visual Studio formatted everything for me, and I guess it used clang-format-15.

&remainingBytes,
&data);

sf::String value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this get used?

Copy link
Member

@ChrisThrasher ChrisThrasher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous CI run succeeded minus formatting failing. Please try to get a copy of clang-format 12, 13, or 14 and build the format target to fix this.

#include <SFML/Window/Mouse.hpp>
#include <SFML/Window/Sensor.hpp>

#include <memory>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove this header

@justanobdy
Copy link
Author

is there a way to get clang-format to reformat the whole codebase? because clang-format-13 isn't fixing everything, and I don't want to mess with visual studio's clang-format version

@justanobdy
Copy link
Author

justanobdy commented Dec 5, 2022

should I merge all the commits together and start a new pr on a new branch? (not named X11DnD)

@ChrisThrasher
Copy link
Member

ChrisThrasher commented Dec 5, 2022

is there a way to get clang-format to reformat the whole codebase?

Yes, that's what happens when you build the format target.

EDIT: The formatting CI jobs are passing now so I think you're good.

should I merge all the commits together and start a new pr on a new branch?

Please don't make a new branch or PR. If you want to clean up the commit history then go for it, but you can wait to do that later if you want. If you do that, you can just git push --force to update this PR with your new commits.

@justanobdy
Copy link
Author

justanobdy commented Dec 5, 2022

Please don't make a new branch or PR. If you want to clean up the commit history then go for it, but you can wait to do that later if you want. If you do that, you can just git push --force to update this PR with your new commits.

Ok, I wasn't sure if it was fine that a branch named "X11DnD" also had windows support.

@ChrisThrasher
Copy link
Member

You're good. Branches names aren't that important since they don't appear in the commit history after a merge.

@justanobdy justanobdy changed the title Add drag and drop on X11 Add drag and drop support Sep 2, 2024
@ChrisThrasher ChrisThrasher force-pushed the X11DnD branch 2 times, most recently from da762ae to 60b6dc3 Compare September 2, 2024 20:34
@coveralls
Copy link
Collaborator

coveralls commented Sep 3, 2024

Pull Request Test Coverage Report for Build 10754038072

Details

  • 7 of 160 (4.38%) changed or added relevant lines in 7 files are covered.
  • 5 unchanged lines in 2 files lost coverage.
  • Overall coverage decreased (-0.5%) to 56.171%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/SFML/Window/WindowBase.cpp 0 2 0.0%
src/SFML/Window/macOS/SFViewController.mm 0 6 0.0%
src/SFML/Window/macOS/SFWindowController.mm 0 6 0.0%
src/SFML/Window/macOS/WindowImplCocoa.mm 0 6 0.0%
src/SFML/Window/Win32/WindowImplWin32.cpp 0 16 0.0%
src/SFML/Window/macOS/SFOpenGLView.mm 0 25 0.0%
src/SFML/Window/Unix/WindowImplX11.cpp 7 99 7.07%
Files with Coverage Reduction New Missed Lines %
src/SFML/Window/WindowImpl.cpp 1 58.17%
src/SFML/Window/Unix/WindowImplX11.cpp 4 40.25%
Totals Coverage Status
Change from base Build 10732212885: -0.5%
Covered Lines: 11909
Relevant Lines: 20080

💛 - Coveralls

[self updateCursorGrabbed]; // update for fullscreen

// Register the drag types that this view can accept
//[self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you recall why this is commented out?

@eXpl0it3r eXpl0it3r removed this from the 3.1 milestone Jun 19, 2025
@eXpl0it3r eXpl0it3r removed this from SFML 3.1.0 Jun 19, 2025
@github-project-automation github-project-automation bot moved this to Planned in SFML 3.2.0 Jun 19, 2025
@eXpl0it3r eXpl0it3r added this to the 3.2 milestone Aug 28, 2025
@eXpl0it3r eXpl0it3r linked an issue Aug 28, 2025 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Planned

Development

Successfully merging this pull request may close these issues.

Add Support for Drag & Drop Events

6 participants