diff --git a/application/application.cpp b/application/application.cpp index 709d80b8..d94c6a83 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -52,6 +52,10 @@ bool Application::init_platform(std::unique_ptr new_platform) #endif platform = std::move(new_platform); application_wsi.set_platform(platform.get()); + + if (auto *event = GRANITE_EVENT_MANAGER()) + event->enqueue_latched(*platform); + return true; } @@ -61,6 +65,7 @@ void Application::teardown_wsi() { event->dequeue_all_latched(DevicePipelineReadyEvent::get_type_id()); event->dequeue_all_latched(DeviceShaderModuleReadyEvent::get_type_id()); + event->dequeue_all_latched(ApplicationWSIPlatformEvent::get_type_id()); } application_wsi.teardown(); ready_modules = false; diff --git a/application/events/application_wsi_events.hpp b/application/events/application_wsi_events.hpp index cd8a248a..81070276 100644 --- a/application/events/application_wsi_events.hpp +++ b/application/events/application_wsi_events.hpp @@ -29,6 +29,7 @@ namespace Vulkan { class Device; class ShaderManager; +class WSIPlatform; class DeviceCreatedEvent : public Granite::Event { @@ -184,4 +185,56 @@ class SwapchainIndexEvent : public Granite::Event Device &device; unsigned index; }; + +class ApplicationWSIPlatformEvent : public Granite::Event +{ +public: + GRANITE_EVENT_TYPE_DECL(ApplicationWSIPlatformEvent) + + explicit ApplicationWSIPlatformEvent(WSIPlatform &platform_) + : platform(platform_) + {} + + WSIPlatform &get_platform() const + { + return platform; + } + +private: + WSIPlatform &platform; +}; + +class ApplicationWindowFileDropEvent : public Granite::Event +{ +public: + GRANITE_EVENT_TYPE_DECL(ApplicationWindowFileDropEvent) + explicit ApplicationWindowFileDropEvent(std::string path_) + : path(std::move(path_)) + {} + + const std::string &get_path() const + { + return path; + } + +private: + std::string path; +}; + +class ApplicationWindowTextDropEvent : public Granite::Event +{ +public: + GRANITE_EVENT_TYPE_DECL(ApplicationWindowTextDropEvent) + explicit ApplicationWindowTextDropEvent(std::string str_) + : str(std::move(str_)) + {} + + const std::string &get_text() const + { + return str; + } + +private: + std::string str; +}; } diff --git a/application/platforms/application_sdl3.cpp b/application/platforms/application_sdl3.cpp index 7a4e21fe..4419b2f7 100644 --- a/application/platforms/application_sdl3.cpp +++ b/application/platforms/application_sdl3.cpp @@ -157,6 +157,13 @@ struct WSIPlatformSDL : GraniteWSIPlatform return &application.info; } + void begin_drop_event() override + { + push_task_to_main_thread([]() { + SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, SDL_TRUE); + }); + } + void toggle_fullscreen() { bool is_fullscreen = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0; @@ -197,6 +204,7 @@ struct WSIPlatformSDL : GraniteWSIPlatform std::lock_guard holder{get_input_tracker().get_lock()}; flush_deferred_input_events(); process_events_async_thread(); + process_events_async_thread_non_pollable(); return !request_tear_down.load(); } @@ -405,6 +413,14 @@ struct WSIPlatformSDL : GraniteWSIPlatform { toggle_fullscreen(); } + else if (state == KeyState::Pressed && tolower(e.key.keysym.sym) == 'v' && + (e.key.keysym.mod & SDL_KMOD_LCTRL) != 0) + { + push_non_pollable_task_to_async_thread([c = clipboard]() mutable { + if (auto *manager = GRANITE_EVENT_MANAGER()) + manager->enqueue(std::move(c)); + }); + } else { Key key = sdl_key_to_granite_key(e.key.keysym.sym); @@ -415,6 +431,37 @@ struct WSIPlatformSDL : GraniteWSIPlatform } break; + case SDL_EVENT_DROP_FILE: + if (e.drop.windowID == SDL_GetWindowID(window)) + { + std::string str = e.drop.data; + push_non_pollable_task_to_async_thread([s = std::move(str)]() mutable { + if (auto *manager = GRANITE_EVENT_MANAGER()) + manager->enqueue(std::move(s)); + }); + } + break; + + case SDL_EVENT_DROP_COMPLETE: + SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, SDL_FALSE); + break; + + case SDL_EVENT_CLIPBOARD_UPDATE: + if (SDL_HasClipboardText()) + { + char *text = SDL_GetClipboardText(); + if (text) + { + clipboard = text; + SDL_free(text); + } + else + clipboard.clear(); + } + else + clipboard.clear(); + break; + default: break; } @@ -494,9 +541,6 @@ struct WSIPlatformSDL : GraniteWSIPlatform void notify_close() { request_tear_down.store(true); - SDL_Event quit_event = {}; - quit_event.type = SDL_EVENT_QUIT; - SDL_PushEvent(&quit_event); } #ifdef _WIN32 @@ -517,12 +561,19 @@ struct WSIPlatformSDL : GraniteWSIPlatform push_task_to_list(task_list_async, std::forward(op)); } + template + void push_non_pollable_task_to_async_thread(Op &&op) + { + push_non_pollable_task_to_list(task_list_async, std::forward(op)); + } + private: SDL_Window *window = nullptr; unsigned width = 0; unsigned height = 0; uint32_t wake_event_type = 0; Options options; + std::string clipboard; struct { @@ -536,6 +587,7 @@ struct WSIPlatformSDL : GraniteWSIPlatform std::mutex lock; std::condition_variable cond; std::vector> list; + std::vector> non_pollable_list; } task_list_main, task_list_async; static void process_events_for_list(TaskList &list, bool blocking) @@ -559,6 +611,14 @@ struct WSIPlatformSDL : GraniteWSIPlatform list.cond.notify_one(); } + template + void push_non_pollable_task_to_list(TaskList &list, Op &&op) + { + std::lock_guard holder{list.lock}; + list.non_pollable_list.emplace_back(std::forward(op)); + list.cond.notify_one(); + } + void process_events_main_thread() { process_events_for_list(task_list_main, false); @@ -574,6 +634,14 @@ struct WSIPlatformSDL : GraniteWSIPlatform process_events_for_list(task_list_async, false); } + void process_events_async_thread_non_pollable() + { + std::unique_lock holder{task_list_async.lock}; + for (auto &task : task_list_async.non_pollable_list) + task(); + task_list_async.non_pollable_list.clear(); + } + void process_events_async_thread_blocking() { process_events_for_list(task_list_async, true); diff --git a/vulkan/wsi.cpp b/vulkan/wsi.cpp index cb47d134..c488f7c4 100644 --- a/vulkan/wsi.cpp +++ b/vulkan/wsi.cpp @@ -1527,4 +1527,5 @@ void WSIPlatform::event_swapchain_created(Device *, VkSwapchainKHR, unsigned, un void WSIPlatform::event_swapchain_destroyed() {} void WSIPlatform::event_frame_tick(double, double) {} void WSIPlatform::event_swapchain_index(Device *, unsigned) {} +void WSIPlatform::begin_drop_event() {} } diff --git a/vulkan/wsi.hpp b/vulkan/wsi.hpp index 212abc84..a21210a6 100644 --- a/vulkan/wsi.hpp +++ b/vulkan/wsi.hpp @@ -124,6 +124,8 @@ class WSIPlatform virtual const VkApplicationInfo *get_application_info(); + virtual void begin_drop_event(); + protected: unsigned current_swapchain_width = 0; unsigned current_swapchain_height = 0;