2626#define  getrandom (buf, sz, flags ) syscall(SYS_getrandom, buf, sz, flags)
2727#endif 
2828
29+ #ifdef  NFD_WAYLAND
30+ #include  < wayland-client.h> 
31+ #include  " xdg-foreign-unstable-v1.h" 
32+ struct  wl_display * wayland_display;
33+ struct  wl_registry * wayland_registry;
34+ uint32_t  wayland_xdg_exporter_v1_name;
35+ struct  zxdg_exporter_v1 * wayland_xdg_exporter_v1;
36+ #endif 
37+ 
2938#include  " nfd.h" 
3039
3140/* 
@@ -68,6 +77,17 @@ struct FreeCheck_Guard {
6877    }
6978};
7079
80+ void  EmptyFn (void *) {}
81+ 
82+ struct  DestroyFunc  {
83+     DestroyFunc () : fn(&EmptyFn), context(nullptr ) {}
84+     ~DestroyFunc () {
85+         (*fn)(context);
86+     }
87+     void (*fn)(void *);
88+     void * context;
89+ };
90+ 
7191struct  DBusMessage_Guard  {
7292    DBusMessage* data;
7393    DBusMessage_Guard (DBusMessage* freeable) noexcept  : data(freeable) {}
@@ -172,9 +192,43 @@ constexpr const char* DBUS_PATH = "/org/freedesktop/portal/desktop";
172192constexpr  const  char * DBUS_FILECHOOSER_IFACE = " org.freedesktop.portal.FileChooser" 
173193constexpr  const  char * DBUS_REQUEST_IFACE = " org.freedesktop.portal.Request" 
174194
175- void  AppendOpenFileQueryParentWindow (DBusMessageIter& iter, const  nfdwindowhandle_t & parentWindow) {
195+ #ifdef  NFD_WAYLAND
196+ constexpr  const  char * XDG_EXPORTER_V1 = " zxdg_exporter_v1" 
197+ constexpr  const  char * WAYLAND_PREFIX = " wayland:" 
198+ 
199+ void  DestroyXdgExported (void * context) {
200+     zxdg_exported_v1_destroy (static_cast <struct  zxdg_exported_v1 *>(context));
201+ }
202+ 
203+ void  zxdg_exported_v1_handle (void * context,
204+ 		       struct  zxdg_exported_v1 * zxdg_exported_v1,
205+ 		       const  char * handle) {
206+     if  (!context) return ;
207+     DBusMessageIter& iter = *static_cast <DBusMessageIter*>(context);
208+     const  size_t  handle_len = strlen (handle);
209+     const  size_t  prefix_len = strlen (WAYLAND_PREFIX);
210+     char * const  buf = NFDi_Malloc<char >(prefix_len + handle_len + 1 );
211+     char * buf_end = copy (WAYLAND_PREFIX, WAYLAND_PREFIX + prefix_len, buf);
212+     buf_end = copy (handle, handle+handle_len, buf_end);
213+     *buf_end = ' \0 ' 
214+     dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &buf);
215+     NFDi_Free (buf);
216+ }
217+ 
218+ constexpr  struct  zxdg_exported_v1_listener  wayland_xdg_exported_v1_listener {
219+     &zxdg_exported_v1_handle
220+ };
221+ #endif 
222+ 
223+ void  AppendOpenFileQueryParentWindow (DBusMessageIter& iter, const  nfdwindowhandle_t & parentWindow, void (*&destroyFn)(void *), void*& destroyFnContext) {
224+     (void ) iter;
225+     (void ) parentWindow;
226+     (void ) destroyFn;
227+     (void ) destroyFnContext;
176228    switch  (parentWindow.type ) {
229+ #ifdef  NFD_X11
177230        case  NFD_WINDOW_HANDLE_TYPE_X11: {
231+             fprintf (stderr, " X11\n " 
178232            constexpr  size_t  maxX11WindowStrLen =
179233                4  + sizeof (uintptr_t ) * 2  + 1 ;  //  "x11:" + "<hex>" + "\0"
180234            char  serializedWindowBuf[maxX11WindowStrLen];
@@ -190,6 +244,26 @@ void AppendOpenFileQueryParentWindow(DBusMessageIter& iter, const nfdwindowhandl
190244            dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &serializedWindow);
191245            return ;
192246        }
247+ #endif 
248+ #ifdef  NFD_WAYLAND
249+         case  NFD_WINDOW_HANDLE_TYPE_WAYLAND: {
250+             fprintf (stderr, " Wayland\n " 
251+             if  (wayland_xdg_exporter_v1) {
252+                 struct  zxdg_exported_v1 * exported = zxdg_exporter_v1_export (wayland_xdg_exporter_v1, static_cast <struct  wl_surface *>(parentWindow.handle ));
253+                 if  (!exported) {
254+                     //  if we fail to export the wl_surface, act as if the window has no parent
255+                     dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &STR_EMPTY);
256+                     return ;
257+                 }
258+                 zxdg_exported_v1_add_listener (exported, &wayland_xdg_exported_v1_listener, static_cast <void *>(&iter));
259+                 wl_display_roundtrip (wayland_display);
260+                 zxdg_exported_v1_set_user_data (exported, nullptr );
261+                 destroyFn = &DestroyXdgExported;
262+                 destroyFnContext = static_cast <void *>(exported);
263+             }
264+             return ;
265+         }
266+ #endif 
193267        default : {
194268            dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &STR_EMPTY);
195269            return ;
@@ -619,11 +693,11 @@ void AppendOpenFileQueryParams(DBusMessage* query,
619693                               const  nfdnfilteritem_t * filterList,
620694                               nfdfiltersize_t  filterCount,
621695                               const  nfdnchar_t * defaultPath,
622-                                const  nfdwindowhandle_t & parentWindow) {
696+                                const  nfdwindowhandle_t & parentWindow,  void (*&destroyFn)( void *), void*& destroyFnContext ) {
623697    DBusMessageIter iter;
624698    dbus_message_iter_init_append (query, &iter);
625699
626-     AppendOpenFileQueryParentWindow (iter, parentWindow);
700+     AppendOpenFileQueryParentWindow (iter, parentWindow, destroyFn, destroyFnContext );
627701    AppendOpenFileQueryTitle<Multiple, Directory>(iter);
628702
629703    DBusMessageIter sub_iter;
@@ -643,11 +717,11 @@ void AppendSaveFileQueryParams(DBusMessage* query,
643717                               nfdfiltersize_t  filterCount,
644718                               const  nfdnchar_t * defaultPath,
645719                               const  nfdnchar_t * defaultName,
646-                                const  nfdwindowhandle_t & parentWindow) {
720+                                const  nfdwindowhandle_t & parentWindow,  void (*&destroyFn)( void *), void*& destroyFnContext ) {
647721    DBusMessageIter iter;
648722    dbus_message_iter_init_append (query, &iter);
649723
650-     AppendOpenFileQueryParentWindow (iter, parentWindow);
724+     AppendOpenFileQueryParentWindow (iter, parentWindow, destroyFn, destroyFnContext );
651725    AppendSaveFileQueryTitle (iter);
652726
653727    DBusMessageIter sub_iter;
@@ -1195,8 +1269,10 @@ nfdresult_t NFD_DBus_OpenFile(DBusMessage*& outMsg,
11951269    DBusMessage* query = dbus_message_new_method_call (
11961270        DBUS_DESTINATION, DBUS_PATH, DBUS_FILECHOOSER_IFACE, " OpenFile" 
11971271    DBusMessage_Guard query_guard (query);
1272+ 
1273+     DestroyFunc destroy;
11981274    AppendOpenFileQueryParams<Multiple, Directory>(
1199-         query, handle_token_ptr, filterList, filterCount, defaultPath, parentWindow);
1275+         query, handle_token_ptr, filterList, filterCount, defaultPath, parentWindow, destroy. fn , destroy. context );
12001276
12011277    DBusMessage* reply =
12021278        dbus_connection_send_with_reply_and_block (dbus_conn, query, DBUS_TIMEOUT_INFINITE, &err);
@@ -1278,8 +1354,10 @@ nfdresult_t NFD_DBus_SaveFile(DBusMessage*& outMsg,
12781354    DBusMessage* query = dbus_message_new_method_call (
12791355        DBUS_DESTINATION, DBUS_PATH, DBUS_FILECHOOSER_IFACE, " SaveFile" 
12801356    DBusMessage_Guard query_guard (query);
1357+ 
1358+     DestroyFunc destroy;
12811359    AppendSaveFileQueryParams (
1282-         query, handle_token_ptr, filterList, filterCount, defaultPath, defaultName, parentWindow);
1360+         query, handle_token_ptr, filterList, filterCount, defaultPath, defaultName, parentWindow, destroy. fn , destroy. context );
12831361
12841362    DBusMessage* reply =
12851363        dbus_connection_send_with_reply_and_block (dbus_conn, query, DBUS_TIMEOUT_INFINITE, &err);
@@ -1383,6 +1461,27 @@ nfdresult_t NFD_DBus_GetVersion(dbus_uint32_t& outVersion) {
13831461    return  NFD_OKAY;
13841462}
13851463
1464+ #ifdef  NFD_WAYLAND
1465+ void  registry_handle_global (void * context, struct  wl_registry * registry, uint32_t  name, const  char * interface, uint32_t  version) {
1466+     if  (strcmp (interface, XDG_EXPORTER_V1) == 0 ) {
1467+         wayland_xdg_exporter_v1_name = name;
1468+         wayland_xdg_exporter_v1 = static_cast <struct  zxdg_exporter_v1 *>(wl_registry_bind (registry, name, &zxdg_exporter_v1_interface, zxdg_exporter_v1_interface.version ));
1469+     }
1470+ }
1471+ 
1472+ void  registry_handle_global_remove (void * context, struct  wl_registry * registry, uint32_t  name) {
1473+     if  (wayland_xdg_exporter_v1 && name == wayland_xdg_exporter_v1_name) {
1474+         zxdg_exporter_v1_destroy (wayland_xdg_exporter_v1);
1475+         wayland_xdg_exporter_v1 = nullptr ;
1476+     }
1477+ }
1478+ 
1479+ constexpr  struct  wl_registry_listener  wayland_registry_listener = {
1480+     ®istry_handle_global,
1481+     ®istry_handle_global_remove
1482+ };
1483+ #endif 
1484+ 
13861485}  //  namespace
13871486
13881487/*  public */ 
@@ -1408,11 +1507,30 @@ nfdresult_t NFD_Init(void) {
14081507    dbus_unique_name = dbus_bus_get_unique_name (dbus_conn);
14091508    if  (!dbus_unique_name) {
14101509        NFDi_SetError (" Unable to get the unique name of our D-Bus connection." 
1510+         dbus_connection_unref (dbus_conn);
14111511        return  NFD_ERROR;
14121512    }
1513+ #ifdef  NFD_WAYLAND
1514+     //  This might fail, but it is fine because the system might not actually have Wayland installed
1515+     wayland_display = wl_display_connect (nullptr );
1516+     if  (wayland_display) {
1517+         wayland_registry = wl_display_get_registry (wayland_display);
1518+         wayland_xdg_exporter_v1 = nullptr ;
1519+         //  seems like registry can't be null
1520+         wl_registry_add_listener (wayland_registry, &wayland_registry_listener, nullptr );
1521+         wl_display_roundtrip (wayland_display);
1522+     }
1523+ #endif 
14131524    return  NFD_OKAY;
14141525}
14151526void  NFD_Quit (void ) {
1527+ #ifdef  NFD_WAYLAND
1528+     if  (wayland_display) {
1529+         if  (wayland_xdg_exporter_v1) zxdg_exporter_v1_destroy (wayland_xdg_exporter_v1);
1530+         wl_registry_destroy (wayland_registry);
1531+         wl_display_disconnect (wayland_display);
1532+     }
1533+ #endif 
14161534    dbus_connection_unref (dbus_conn);
14171535    //  Note: We do not free dbus_error since NFD_Init might set it.
14181536    //  To avoid leaking memory, the caller should explicitly call NFD_ClearError after reading the
0 commit comments