5 changed files with 1616 additions and 0 deletions
@ -0,0 +1,35 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System.Collections.ObjectModel; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Controls.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a platform-specific drive mount information provider implementation.
|
|||
/// </summary>
|
|||
public interface IMountedDriveInfoProvider |
|||
{ |
|||
/// <summary>
|
|||
/// Observable list of currently-mounted drives.
|
|||
/// </summary>
|
|||
ObservableCollection<MountedDriveInfo> CurrentDrives { get; } |
|||
|
|||
/// <summary>
|
|||
/// Determines if the service is currently monitoring.
|
|||
/// </summary>
|
|||
bool IsMonitoring { get; } |
|||
|
|||
/// <summary>
|
|||
/// Start the service polling routine.
|
|||
/// </summary>
|
|||
void Start(); |
|||
|
|||
/// <summary>
|
|||
/// Stop the service polling routine.
|
|||
/// </summary>
|
|||
void Stop(); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
|
|||
namespace Avalonia.Controls.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Describes a Drive's properties.
|
|||
/// </summary>
|
|||
public class MountedDriveInfo : IEquatable<MountedDriveInfo> |
|||
{ |
|||
public string DriveLabel { get; set; } |
|||
public string DriveName { get; set; } |
|||
public ulong DriveSizeBytes { get; set; } |
|||
public string DevicePath { get; set; } |
|||
public string MountPath { get; set; } |
|||
|
|||
public bool Equals(MountedDriveInfo other) |
|||
{ |
|||
return this.DriveLabel.Equals(other.DriveLabel) && |
|||
this.DriveName.Equals(other.DriveName) && |
|||
this.DriveSizeBytes.Equals(other.DriveSizeBytes) && |
|||
this.DevicePath.Equals(other.DevicePath) && |
|||
this.MountPath.Equals(other.MountPath); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Collections.Generic; |
|||
using System.Collections.ObjectModel; |
|||
|
|||
using Avalonia.Controls.Platform; |
|||
using Tmds.DBus; |
|||
|
|||
namespace Avalonia.X11.Dbus |
|||
{ |
|||
public class LinuxMountedDriveInfoProvider : IMountedDriveInfoProvider |
|||
{ |
|||
private IDisposable[] Disposables; |
|||
private readonly Connection _sysDbus; |
|||
private readonly IObjectManager udisk2Manager; |
|||
|
|||
public LinuxMountedDriveInfoProvider() |
|||
{ |
|||
this._sysDbus = Connection.System; |
|||
this.udisk2Manager = _sysDbus.CreateProxy<IObjectManager>("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2"); |
|||
} |
|||
|
|||
public ObservableCollection<MountedDriveInfo> CurrentDrives { get; } = new ObservableCollection<MountedDriveInfo>(); |
|||
|
|||
private bool _isMonitoring; |
|||
public bool IsMonitoring => _isMonitoring; |
|||
|
|||
private async void Poll() |
|||
{ |
|||
var newDriveList = new List<MountedDriveInfo>(); |
|||
|
|||
var fProcMounts = File.ReadAllLines("/proc/mounts"); |
|||
|
|||
var managedObj = await udisk2Manager.GetManagedObjectsAsync(); |
|||
|
|||
var res_drives = managedObj.Where(x => x.Key.ToString().Contains("/org/freedesktop/UDisks2/drives/")) |
|||
.Select(x => x.Key); |
|||
|
|||
var res_blockdev = managedObj.Where(x => x.Key.ToString().Contains("/org/freedesktop/UDisks2/block_devices/")) |
|||
.Select(x => x); |
|||
|
|||
var res_fs = managedObj.Where(x => x.Key.ToString().Contains("system")) |
|||
.Select(x => x.Key) |
|||
.ToList(); |
|||
|
|||
foreach (var block in res_blockdev) |
|||
{ |
|||
|
|||
var iblock = _sysDbus.CreateProxy<IBlock>("org.freedesktop.UDisks2", block.Key); |
|||
var iblockProps = await iblock.GetAllAsync(); |
|||
|
|||
var block_drive = await iblock.GetDriveAsync(); |
|||
if (!res_drives.Contains(block_drive)) continue; |
|||
|
|||
var drive_key = res_drives.Single(x => x == block_drive); |
|||
var drives = _sysDbus.CreateProxy<IDrive>("org.freedesktop.UDisks2", drive_key); |
|||
var drivesProps = await drives.GetAllAsync(); |
|||
|
|||
var devRawBytes = iblockProps.Device.Take(iblockProps.Device.Length - 1).ToArray(); |
|||
var devPath = System.Text.Encoding.UTF8.GetString(devRawBytes); |
|||
|
|||
var blockLabel = iblockProps.IdLabel; |
|||
var blockSize = iblockProps.Size; |
|||
var driveName = drivesProps.Id; |
|||
|
|||
// There should be something in udisks2 to
|
|||
// get this data but I have no idea where.
|
|||
var mountPoint = fProcMounts.Select(x => x.Split(' ')) |
|||
.Where(x => x[0] == devPath) |
|||
.Select(x => x[1]) |
|||
.SingleOrDefault(); |
|||
|
|||
if (mountPoint is null) continue; |
|||
|
|||
var k = new MountedDriveInfo() |
|||
{ |
|||
DriveLabel = blockLabel, |
|||
DriveName = driveName, |
|||
DriveSizeBytes = blockSize, |
|||
DevicePath = devPath, |
|||
MountPath = mountPoint |
|||
}; |
|||
|
|||
newDriveList.Add(k); |
|||
} |
|||
|
|||
UpdateCollection(newDriveList); |
|||
} |
|||
|
|||
// https://stackoverflow.com/questions/19558644/update-an-observablecollection-from-another-collection
|
|||
private void UpdateCollection(IEnumerable<MountedDriveInfo> newCollection) |
|||
{ |
|||
var newCollectionEnumerator = newCollection.GetEnumerator(); |
|||
var collectionEnumerator = CurrentDrives.GetEnumerator(); |
|||
|
|||
var itemsToDelete = new Collection<MountedDriveInfo>(); |
|||
while (collectionEnumerator.MoveNext()) |
|||
{ |
|||
var item = collectionEnumerator.Current; |
|||
|
|||
// Store item to delete (we can't do it while parse collection.
|
|||
if (!newCollection.Contains(item)) |
|||
{ |
|||
itemsToDelete.Add(item); |
|||
} |
|||
} |
|||
|
|||
// Handle item to delete.
|
|||
foreach (var itemToDelete in itemsToDelete) |
|||
{ |
|||
CurrentDrives.Remove(itemToDelete); |
|||
} |
|||
|
|||
var i = 0; |
|||
while (newCollectionEnumerator.MoveNext()) |
|||
{ |
|||
var item = newCollectionEnumerator.Current; |
|||
|
|||
// Handle new item.
|
|||
if (!CurrentDrives.Contains(item)) |
|||
{ |
|||
CurrentDrives.Insert(i, item); |
|||
} |
|||
|
|||
// Handle existing item, move at the good index.
|
|||
if (CurrentDrives.Contains(item)) |
|||
{ |
|||
int oldIndex = CurrentDrives.IndexOf(item); |
|||
CurrentDrives.Move(oldIndex, i); |
|||
} |
|||
i++; |
|||
} |
|||
} |
|||
|
|||
public async void Start() |
|||
{ |
|||
Disposables = new[] { |
|||
await udisk2Manager.WatchInterfacesAddedAsync(delegate { Poll(); }), |
|||
await udisk2Manager.WatchInterfacesRemovedAsync( delegate { Poll(); }) |
|||
}; |
|||
|
|||
Poll(); |
|||
|
|||
_isMonitoring = true; |
|||
} |
|||
|
|||
public void Stop() |
|||
{ |
|||
foreach (var Disposable in Disposables) |
|||
Disposable.Dispose(); |
|||
|
|||
CurrentDrives?.Clear(); |
|||
_isMonitoring = false; |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue