mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-14 14:24:10 +02:00
Merge pull request #2027 from zerkawei/linux-file-dialogs
Implement xdg-desktop-portal for Linux dialogs
This commit is contained in:
commit
4f073ef60a
5 changed files with 490 additions and 2 deletions
|
@ -577,4 +577,306 @@ namespace System.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif BF_PLATFORM_LINUX
|
||||||
|
namespace System.IO;
|
||||||
|
|
||||||
|
enum DialogResult
|
||||||
|
{
|
||||||
|
None = 2,
|
||||||
|
OK = 0,
|
||||||
|
Cancel = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CommonDialog
|
||||||
|
{
|
||||||
|
protected Linux.DBus* mBus ~ Linux.SdBusUnref(_);
|
||||||
|
protected Linux.DBusMsg* mRequest ~ Linux.SdBusMessageUnref(_);
|
||||||
|
protected Linux.DBusErr mError ~ Linux.SdBusErrorFree(&_);
|
||||||
|
protected String mTitle ~ delete _;
|
||||||
|
protected String mInitialDir ~ delete _;
|
||||||
|
protected String[] mFileNames ~ DeleteContainerAndItems!(_);
|
||||||
|
protected bool mDone;
|
||||||
|
|
||||||
|
private uint32 mResult;
|
||||||
|
|
||||||
|
|
||||||
|
public virtual void Reset()
|
||||||
|
{
|
||||||
|
DeleteAndNullify!(mTitle);
|
||||||
|
DeleteAndNullify!(mInitialDir);
|
||||||
|
DeleteContainerAndItems!(mFileNames);
|
||||||
|
mFileNames = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView Title
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
String.NewOrSet!(mTitle, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<DialogResult> ShowDialog(INativeWindow owner = null)
|
||||||
|
{
|
||||||
|
TryC!(Linux.SdBusOpenUser(&mBus)); // Maybe keep the bus open while the program is running ?
|
||||||
|
|
||||||
|
Linux.DBusMsg* call = ?;
|
||||||
|
TryC!(Linux.SdBusNewMethodCall(
|
||||||
|
mBus,
|
||||||
|
&call,
|
||||||
|
"org.freedesktop.portal.Desktop",
|
||||||
|
"/org/freedesktop/portal/desktop",
|
||||||
|
"org.freedesktop.portal.FileChooser",
|
||||||
|
Method));
|
||||||
|
|
||||||
|
Linux.SdBusMessageAppend(call, "ss", "", Title.ToScopeCStr!()); //TODO : set parent_window to X11/Wayland handle
|
||||||
|
Linux.SdBusMessageOpenContainer(call, .Array, "{sv}");
|
||||||
|
if(mInitialDir != null)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(call, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageAppendBasic(call, .String, "current_folder");
|
||||||
|
Linux.SdBusMessageOpenContainer(call, .Variant, "ay");
|
||||||
|
Linux.SdBusMessageAppendArray(call, .Byte, mInitialDir.CStr(), (.)mInitialDir.Length);
|
||||||
|
Linux.SdBusMessageCloseContainer(call);
|
||||||
|
Linux.SdBusMessageCloseContainer(call);
|
||||||
|
}
|
||||||
|
AddOptions(call);
|
||||||
|
Linux.SdBusMessageCloseContainer(call);
|
||||||
|
TryC!(Linux.SdBusCall(mBus, call, uint32.MaxValue, &mError, &mRequest)); // TODO : change timeout
|
||||||
|
|
||||||
|
Linux.SdBusMessageUnref(call);
|
||||||
|
|
||||||
|
char8* path = ?;
|
||||||
|
TryC!(Linux.SdBusMessageRead(mRequest, "o", &path));
|
||||||
|
TryC!(Linux.SdBusMatchSignal(mBus,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
path,
|
||||||
|
"org.freedesktop.portal.Request",
|
||||||
|
"Response",
|
||||||
|
=> ParseResponse,
|
||||||
|
Internal.UnsafeCastToPtr(this)
|
||||||
|
));
|
||||||
|
|
||||||
|
while(!mDone)
|
||||||
|
{
|
||||||
|
Linux.DBusMsg* m = ?;
|
||||||
|
TryC!(Linux.SdBusWait(mBus, uint64.MaxValue));
|
||||||
|
TryC!(Linux.SdBusProcess(mBus, &m));
|
||||||
|
Linux.SdBusMessageUnref(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (DialogResult)mResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int32 ParseResponse(Linux.DBusMsg* response, void* ptr, Linux.DBusErr* error)
|
||||||
|
{
|
||||||
|
Self dia = (.)Internal.UnsafeCastToObject(ptr);
|
||||||
|
|
||||||
|
char8* key = ?;
|
||||||
|
|
||||||
|
Linux.SdBusMessageReadBasic(response, .UInt32, &dia.mResult);
|
||||||
|
Linux.SdBusMessageEnterContainer(response, .Array, "{sv}");
|
||||||
|
while(Linux.SdBusMessagePeekType(response, null, null) != 0)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageEnterContainer(response, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageReadBasic(response, .String, &key);
|
||||||
|
switch(StringView(key))
|
||||||
|
{
|
||||||
|
case "uris":
|
||||||
|
List<String> uris = scope .();
|
||||||
|
|
||||||
|
Linux.SdBusMessageEnterContainer(response, .Variant, "as");
|
||||||
|
Linux.SdBusMessageEnterContainer(response, .Array, "s");
|
||||||
|
while(Linux.SdBusMessagePeekType(response, null, null) != 0)
|
||||||
|
{
|
||||||
|
char8* uri = ?;
|
||||||
|
Linux.SdBusMessageReadBasic(response, .String, &uri);
|
||||||
|
uris.Add(new .(StringView(uri+7))); // Removing the "file://" prefix
|
||||||
|
}
|
||||||
|
Linux.SdBusMessageExitContainer(response);
|
||||||
|
Linux.SdBusMessageExitContainer(response);
|
||||||
|
|
||||||
|
dia.mFileNames = new .[uris.Count];
|
||||||
|
uris.CopyTo(dia.mFileNames);
|
||||||
|
default:
|
||||||
|
Linux.SdBusMessageSkip(response, "v");
|
||||||
|
}
|
||||||
|
Linux.SdBusMessageExitContainer(response);
|
||||||
|
}
|
||||||
|
Linux.SdBusMessageExitContainer(response);
|
||||||
|
|
||||||
|
dia.mDone = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract char8* Method { get; }
|
||||||
|
protected abstract void AddOptions(Linux.DBusMsg* m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class FileDialog : CommonDialog
|
||||||
|
{
|
||||||
|
protected int32 mOptions;
|
||||||
|
private String mFilter ~ delete _;
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
base.Reset();
|
||||||
|
DeleteAndNullify!(mFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView InitialDirectory
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
String.NewOrSet!(mInitialDir, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mInitialDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] FileNames
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mFileNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView FileName
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (mFileNames == null)
|
||||||
|
{
|
||||||
|
mFileNames = new String[](new String(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Multiselect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetOption(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetOption(512, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValidateNames // Unused kept for compatibility
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !GetOption(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetOption(256, !value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView DefaultExt { get; set; } // Unused kept for compatibility
|
||||||
|
|
||||||
|
public void GetFilter(String outFilter)
|
||||||
|
{
|
||||||
|
if (mFilter != null)
|
||||||
|
outFilter.Append(mFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<void> SetFilter(StringView value)
|
||||||
|
{
|
||||||
|
String useValue = scope String(value);
|
||||||
|
if (useValue != null && useValue.Length > 0)
|
||||||
|
{
|
||||||
|
var formats = String.StackSplit!(useValue, '|');
|
||||||
|
if (formats == null || formats.Count % 2 != 0)
|
||||||
|
{
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/*String[] formats = value.Split('|');
|
||||||
|
if (formats == null || formats.Length % 2 != 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(SR.GetString(SR.FileDialogInvalidFilter));
|
||||||
|
}*/
|
||||||
|
String.NewOrSet!(mFilter, useValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
useValue = null;
|
||||||
|
DeleteAndNullify!(mFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool GetOption(int32 option)
|
||||||
|
{
|
||||||
|
return (mOptions & option) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetOption(int32 option, bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
mOptions |= option;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mOptions &= ~option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddOptions(Linux.DBusMsg* m)
|
||||||
|
{
|
||||||
|
if(Multiselect)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageAppend(m, "sv", "multiple", "b", 1);
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mFilter != null)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageAppendBasic(m, .String, "filters");
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .Variant, "a(sa(us))");
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .Array, "(sa(us))");
|
||||||
|
for(let filter in mFilter.Split('|'))
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .Struct, "sa(us)");
|
||||||
|
Linux.SdBusMessageAppendBasic(m, .String, filter.ToScopeCStr!());
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .Array, "(us)");
|
||||||
|
@filter.MoveNext();
|
||||||
|
for(let ext in @filter.Current.Split(';'))
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageAppend(m, "(us)", 0, ext.ToScopeCStr!());
|
||||||
|
}
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
}
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
|
@ -221,4 +221,41 @@ namespace System.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif BF_PLATFORM_LINUX
|
||||||
|
namespace System.IO;
|
||||||
|
|
||||||
|
public class FolderBrowserDialog : CommonDialog
|
||||||
|
{
|
||||||
|
public enum FolderKind
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Save
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(FolderKind kind = .Open)
|
||||||
|
{
|
||||||
|
// Only OpenFile allows directory selection so FolderKind isn't stored
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView SelectedPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mDone ? (mFileNames == null) ? "" : mFileNames[0] : mInitialDir; //Response gets stored in mFileNames
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
mInitialDir.Set(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override char8* Method => "OpenFile";
|
||||||
|
protected override void AddOptions(Linux.DBusMsg* m)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageAppend(m, "sv", "directory", "b", 1);
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
|
@ -173,4 +173,23 @@ namespace System.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif BF_PLATFORM_LINUX
|
||||||
|
namespace System.IO;
|
||||||
|
|
||||||
|
public class OpenFileDialog : FileDialog
|
||||||
|
{
|
||||||
|
public bool ShowReadOnly // Unused kept for compatibility
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !GetOption(4);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetOption(4, !value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override char8* Method => "OpenFile";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
|
@ -139,8 +139,36 @@ namespace System.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#elif BF_PLATFORM_LINUX
|
||||||
|
namespace System.IO;
|
||||||
|
|
||||||
|
public class SaveFileDialog : FileDialog
|
||||||
|
{
|
||||||
|
public virtual bool OverwritePrompt // Unused kept for compatibility
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetOption(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetOption(2, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override char8* Method => "SaveFile";
|
||||||
|
protected override void AddOptions(Linux.DBusMsg* m)
|
||||||
|
{
|
||||||
|
if(mFileNames != null)
|
||||||
|
{
|
||||||
|
Linux.SdBusMessageOpenContainer(m, .DictEntry, "sv");
|
||||||
|
Linux.SdBusMessageAppend(m, "sv", "current_name", "s", mFileNames[0].CStr());
|
||||||
|
Linux.SdBusMessageCloseContainer(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
namespace System.IO
|
namespace System.IO
|
||||||
{
|
{
|
||||||
[Error("This class is only available on Windows")]
|
[Error("This class is only available on Windows")]
|
||||||
|
@ -149,5 +177,4 @@ namespace System.IO
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
103
BeefLibs/corlib/src/Linux.bf
Normal file
103
BeefLibs/corlib/src/Linux.bf
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
#if BF_PLATFORM_LINUX
|
||||||
|
using System.Interop;
|
||||||
|
namespace System;
|
||||||
|
|
||||||
|
class Linux
|
||||||
|
{
|
||||||
|
public struct DBus;
|
||||||
|
public struct DBusMsg;
|
||||||
|
public struct DBusSlot;
|
||||||
|
|
||||||
|
public enum DBusType : char8
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
Byte = 'y',
|
||||||
|
Bool = 'b',
|
||||||
|
Int16 = 'n',
|
||||||
|
UInt16 = 'q',
|
||||||
|
Int32 = 'i',
|
||||||
|
UInt32 = 'u',
|
||||||
|
Int64 = 'x',
|
||||||
|
UInt64 = 't',
|
||||||
|
Double = 'd',
|
||||||
|
String = 's',
|
||||||
|
ObjectPath = 'o',
|
||||||
|
Signature = 'g',
|
||||||
|
UnixFD = 'h',
|
||||||
|
Array = 'a',
|
||||||
|
Variant = 'v',
|
||||||
|
Struct = 'r', /* not actually used in signatures */
|
||||||
|
StructBegin = '(',
|
||||||
|
StructEnd = ')',
|
||||||
|
DictEntry = 'e', /* not actually used in signatures */
|
||||||
|
DictEntryBegin = '{',
|
||||||
|
DictEntryEnd = '}'
|
||||||
|
}
|
||||||
|
|
||||||
|
[CRepr]
|
||||||
|
public struct DBusErr
|
||||||
|
{
|
||||||
|
public char8* name;
|
||||||
|
public char8* message;
|
||||||
|
public c_int _need_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
public typealias DBusMsgHandler = function int32(DBusMsg *m, void *userdata, DBusErr *ret_error);
|
||||||
|
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_open_user")]
|
||||||
|
public static extern c_int SdBusOpenUser(DBus **ret);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_open_system")]
|
||||||
|
public static extern c_int SdBusOpenSystem(DBus **ret);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_unref")]
|
||||||
|
public static extern DBus* SdBusUnref(DBus *bus);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_call")]
|
||||||
|
public static extern c_int SdBusCall(DBus *bus, DBusMsg *m, uint64 usec, DBusErr *ret_error, DBusMsg **reply);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_process")]
|
||||||
|
public static extern c_int SdBusProcess(DBus *bus, DBusMsg **r);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_wait")]
|
||||||
|
public static extern c_int SdBusWait(DBus *bus, uint64 timeout_usec);
|
||||||
|
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_new_method_call")]
|
||||||
|
public static extern c_int SdBusNewMethodCall(DBus *bus, DBusMsg **m, char8 *destination, char8 *path, char8 *iface, char8 *member);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_unref")]
|
||||||
|
public static extern DBusMsg* SdBusMessageUnref(DBusMsg *m);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_append")]
|
||||||
|
public static extern c_int SdBusMessageAppend(DBusMsg *m, char8 *types, ...);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_append_basic")]
|
||||||
|
public static extern c_int SdBusMessageAppendBasic(DBusMsg *m, DBusType type, void *p);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_append_array")]
|
||||||
|
public static extern c_int SdBusMessageAppendArray(DBusMsg *m, DBusType type, void *ptr, c_size size);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_open_container")]
|
||||||
|
public static extern c_int SdBusMessageOpenContainer(DBusMsg *m, DBusType type, char8 *contents);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_close_container")]
|
||||||
|
public static extern c_int SdBusMessageCloseContainer(DBusMsg *m);
|
||||||
|
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_read")]
|
||||||
|
public static extern c_int SdBusMessageRead(DBusMsg *m, char8 *types, ...);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_read_basic")]
|
||||||
|
public static extern c_int SdBusMessageReadBasic(DBusMsg *m, DBusType type, void *p);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_read_array")]
|
||||||
|
public static extern c_int SdBusMessageReadArray(DBusMsg *m, DBusType type, void **ptr, c_size *size);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_skip")]
|
||||||
|
public static extern c_int SdBusMessageSkip(DBusMsg *m, char8 *types);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_enter_container")]
|
||||||
|
public static extern c_int SdBusMessageEnterContainer(DBusMsg *m, DBusType type, char8 *contents);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_exit_container")]
|
||||||
|
public static extern c_int SdBusMessageExitContainer(DBusMsg *m);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_message_peek_type")]
|
||||||
|
public static extern c_int SdBusMessagePeekType(DBusMsg *m, char8 *type, char8 **contents);
|
||||||
|
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_call_method")]
|
||||||
|
public static extern c_int SdBusCallMethod(DBus *bus, char8 *destination, char8 *path, char8 *iface, char8 *member, DBusErr *ret_error, DBusMsg **reply, char8 *types, ...);
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_match_signal")]
|
||||||
|
public static extern c_int SdBusMatchSignal(DBus *bus, DBusSlot **ret, char8 *sender, char8 *path, char8 *iface, char8 *member, DBusMsgHandler callback, void *userdata);
|
||||||
|
|
||||||
|
[Import("libsystemd.so"), LinkName("sd_bus_error_free")]
|
||||||
|
public static extern void SdBusErrorFree(DBusErr *e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
public static mixin TryC(int result) { if(result < 0) return .Err; }
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue