Search code examples
.netlinuxexplorerfinder

From dotnet how to open file in containing folder in the Linux file manager?


I'm developing a cross-platform application on dotnet with Avalonia UI and ReactiveUI.

I need to implement a command that open the file browser on the folder containing the file with the focus/highlight on the file.

Here is the command that works for Windows and OSX, but I don't know how to implement the case for Linux

    RevealInFolderCommand = ReactiveCommand.CreateFromTask<string>(async path =>
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                using Process fileOpener = new Process();
                fileOpener.StartInfo.FileName = "explorer";
                fileOpener.StartInfo.Arguments = "/select," + path + "\"";
                fileOpener.Start();
                await fileOpener.WaitForExitAsync();
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                using Process fileOpener = new Process();
                fileOpener.StartInfo.FileName = "explorer";
                fileOpener.StartInfo.Arguments = "-R " + path;
                fileOpener.Start();
                await fileOpener.WaitForExitAsync();
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                throw new NotImplementedException();
            }
            else
            { 
                using Process fileOpener = new Process();
                fileOpener.StartInfo.FileName = Path.GetDirectoryName(path);
                fileOpener.StartInfo.UseShellExecute = true;
                fileOpener.Start();
                await fileOpener.WaitForExitAsync();
            }
        });

Solution

  • When supported, dbus can provide that feature with this command line:

    dbus-send --print-reply --dest=org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1.ShowItems array:string:"file:///some path/some file" string:""
    

    Here is the code that handle the dbus case with a fallback to opening the folder:

            RevealInFolderCommand = ReactiveCommand.CreateFromTask<string>(async path =>
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    using Process fileOpener = new Process();
                    fileOpener.StartInfo.FileName = "explorer";
                    fileOpener.StartInfo.Arguments = "/select," + path + "\"";
                    fileOpener.Start();
                    await fileOpener.WaitForExitAsync();
                    return;
                }
                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    using Process fileOpener = new Process();
                    fileOpener.StartInfo.FileName = "explorer";
                    fileOpener.StartInfo.Arguments = "-R " + path;
                    fileOpener.Start();
                    await fileOpener.WaitForExitAsync();
                    return;
                }
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    using Process dbusShowItemsProcess = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = "dbus-send",
                            Arguments = "--print-reply --dest=org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1.ShowItems array:string:\"file://"+ path +"\" string:\"\"",
                            UseShellExecute = true
                        }
                    };
                    dbusShowItemsProcess.Start();
                    await dbusShowItemsProcess.WaitForExitAsync();
        
                    if (dbusShowItemsProcess.ExitCode == 0)
                    {            
                        // The dbus invocation can fail for a variety of reasons:
                        // - dbus is not available
                        // - no programs implement the service,
                        // - ...
                        return;
                    }
                }
                
                using Process folderOpener = new Process();
                folderOpener.StartInfo.FileName = Path.GetDirectoryName(path);
                folderOpener.StartInfo.UseShellExecute = true;
                folderOpener.Start();
                await folderOpener.WaitForExitAsync();
            });