Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1 @@
add_subdirectory(solid-hardware)
@@ -0,0 +1,7 @@
add_executable(solid-hardware6 solid-hardware.cpp)
ecm_mark_nongui_executable(solid-hardware6)
target_link_libraries(solid-hardware6 PUBLIC KF6::Solid)
if (HAVE_DBUS)
target_link_libraries(solid-hardware6 PRIVATE Qt6::DBus)
endif()
install(TARGETS solid-hardware6 ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
@@ -0,0 +1,570 @@
/* This file is part of the KDE project
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2014 Alejandro Fiestas Olivares <afiestas@kde.org>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "solid-hardware.h"
#ifdef HAVE_DBUS
#include <QDBusArgument>
#include <QDBusObjectPath>
#endif
#include <QMetaEnum>
#include <QMetaProperty>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <QCommandLineParser>
#include <solid/device.h>
#include <solid/genericinterface.h>
#include <solid/opticaldrive.h>
#include <iostream>
#include <solid/devicenotifier.h>
using namespace std;
static const QString appName{QStringLiteral("solid-hardware")};
static const QString version{QStringLiteral("0.1a")};
std::ostream &operator<<(std::ostream &out, const QString &msg)
{
return (out << msg.toLocal8Bit().constData());
}
std::ostream &operator<<(std::ostream &out, const QVariant &value);
#ifdef HAVE_DBUS
std::ostream &operator<<(std::ostream &out, const QDBusArgument &arg)
{
auto type = arg.currentType();
switch (type) {
case QDBusArgument::ArrayType:
out << " { ";
arg.beginArray();
while (!arg.atEnd()) {
out << arg;
if (!arg.atEnd()) {
out << ", ";
}
}
arg.endArray();
out << " }";
break;
case QDBusArgument::StructureType:
out << " ( ";
arg.beginStructure();
while (!arg.atEnd()) {
out << arg.asVariant();
}
arg.endStructure();
out << " )";
break;
case QDBusArgument::MapType:
out << " [ ";
arg.beginMap();
if (!arg.atEnd()) {
out << arg;
}
arg.endMap();
out << " ]";
break;
case QDBusArgument::MapEntryType:
arg.beginMapEntry();
out << arg.asVariant() << " = " << arg;
arg.endMapEntry();
break;
case QDBusArgument::UnknownType:
out << "(unknown DBus type)";
break;
case QDBusArgument::BasicType:
case QDBusArgument::VariantType:
out << arg.asVariant();
}
return out;
}
#endif
std::ostream &operator<<(std::ostream &out, const QVariant &value)
{
switch (value.userType()) {
case QMetaType::QStringList: {
out << "{";
const QStringList list = value.toStringList();
QStringList::ConstIterator it = list.constBegin();
QStringList::ConstIterator end = list.constEnd();
for (; it != end; ++it) {
out << "'" << *it << "'";
if (it + 1 != end) {
out << ", ";
}
}
out << "} (string list)";
break;
}
case QMetaType::QString:
out << "'" << value.toString() << "' (string)";
break;
case QMetaType::Bool:
out << (value.toBool() ? "true" : "false") << " (bool)";
break;
case QMetaType::Int:
case QMetaType::LongLong:
out << value.toString() << " (0x" << QString::number(value.toLongLong(), 16) << ") (" << value.typeName() << ")";
break;
case QMetaType::UInt:
case QMetaType::ULongLong:
out << value.toString() << " (0x" << QString::number(value.toULongLong(), 16) << ") (" << value.typeName() << ")";
break;
case QMetaType::Double:
out << value.toString() << " (double)";
break;
case QMetaType::QByteArray:
out << "'" << value.toString() << "' (bytes)";
break;
case QMetaType::User:
// qDebug() << "got variant type:" << value.typeName();
if (value.canConvert<QList<int>>()) {
const QList<int> intlist = value.value<QList<int>>();
QStringList tmp;
for (const int val : intlist) {
tmp.append(QString::number(val));
}
out << "{" << tmp.join(QStringLiteral(",")) << "} (int list)";
#ifdef HAVE_DBUS
} else if (value.canConvert<QDBusObjectPath>()) {
out << value.value<QDBusObjectPath>().path() << " (ObjectPath)";
} else if (value.canConvert<QDBusVariant>()) {
out << value.value<QDBusVariant>().variant() << "(Variant)";
} else if (value.canConvert<QDBusArgument>()) {
out << value.value<QDBusArgument>();
#endif
} else {
out << value.toString() << " (unhandled)";
}
break;
default:
out << "'" << value.toString() << "' (" << value.typeName() << ")";
break;
}
return out;
}
std::ostream &operator<<(std::ostream &out, const Solid::Device &device)
{
out << " parent = " << QVariant(device.parentUdi()) << endl;
out << " vendor = " << QVariant(device.vendor()) << endl;
out << " product = " << QVariant(device.product()) << endl;
out << " description = " << QVariant(device.description()) << endl;
out << " icon = " << QVariant(device.icon()) << endl;
int index = Solid::DeviceInterface::staticMetaObject.indexOfEnumerator("Type");
QMetaEnum typeEnum = Solid::DeviceInterface::staticMetaObject.enumerator(index);
for (int i = 0; i < typeEnum.keyCount(); i++) {
Solid::DeviceInterface::Type type = (Solid::DeviceInterface::Type)typeEnum.value(i);
const Solid::DeviceInterface *interface = device.asDeviceInterface(type);
if (interface) {
const QMetaObject *meta = interface->metaObject();
for (int i = meta->propertyOffset(); i < meta->propertyCount(); i++) {
QMetaProperty property = meta->property(i);
out << " " << QByteArray(meta->className()).mid(7).constData() << "." << property.name() << " = ";
QVariant value = property.read(interface);
if (property.isEnumType()) {
QMetaEnum metaEnum = property.enumerator();
if (metaEnum.isFlag()) {
out << "'" << metaEnum.valueToKeys(value.toInt()).constData() << "'"
<< " (0x" << QString::number(value.toInt(), 16) << ") (flag)";
} else {
out << "'" << metaEnum.valueToKey(value.toInt()) << "'"
<< " (0x" << QString::number(value.toInt(), 16) << ") (enum)";
}
out << endl;
} else {
out << value << endl;
}
}
}
}
return out;
}
std::ostream &operator<<(std::ostream &out, const QMap<QString, QVariant> &properties)
{
for (auto it = properties.cbegin(); it != properties.cend(); ++it) {
out << " " << it.key() << " = " << it.value() << endl;
}
return out;
}
QString getUdiFromArguments(QCoreApplication &app, QCommandLineParser &parser)
{
parser.addPositionalArgument(QStringLiteral("udi"), QCoreApplication::translate("solid-hardware", "Device udi"));
parser.process(app);
if (parser.positionalArguments().count() < 2) {
parser.showHelp(1);
}
return parser.positionalArguments().at(1);
}
static QString commandsHelp()
{
QString data;
QTextStream cout(&data);
cout << '\n' << QCoreApplication::translate("solid-hardware", "Syntax:") << '\n' << '\n';
cout << " solid-hardware list [details|nonportableinfo]" << '\n';
cout << QCoreApplication::translate("solid-hardware",
" # List the hardware available in the system.\n"
" # - If the 'nonportableinfo' option is specified, the device\n"
" # properties are listed (be careful, in this case property names\n"
" # are backend dependent),\n"
" # - If the 'details' option is specified, the device interfaces\n"
" # and the corresponding properties are listed in a platform\n"
" # neutral fashion,\n"
" # - Otherwise only device UDIs are listed.\n")
<< '\n';
cout << " solid-hardware details 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware",
" # Display all the interfaces and properties of the device\n"
" # corresponding to 'udi' in a platform neutral fashion.\n")
<< '\n';
cout << " solid-hardware nonportableinfo 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware",
" # Display all the properties of the device corresponding to 'udi'\n"
" # (be careful, in this case property names are backend dependent).\n")
<< '\n';
cout << " solid-hardware query 'predicate' ['parentUdi']" << '\n';
cout << QCoreApplication::translate("solid-hardware",
" # List the UDI of devices corresponding to 'predicate'.\n"
" # - If 'parentUdi' is specified, the search is restricted to the\n"
" # branch of the corresponding device,\n"
" # - Otherwise the search is done on all the devices.\n")
<< '\n';
cout << " solid-hardware mount 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # If applicable, mount the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware unmount 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # If applicable, unmount the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware eject 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # If applicable, eject the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware listen" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Listen to all add/remove events on supported hardware.\n") << '\n';
cout << " solid-hardware monitor 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Monitor devices for changes.\n") << '\n';
cout << " solid-hardware CanCheck 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Send \"CanCheck\" request to the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware Check 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Send \"Check\" request to the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware CanRepair 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Send \"CanRepair\" request to the device corresponding to 'udi'.\n") << '\n';
cout << " solid-hardware Repair 'udi'" << '\n';
cout << QCoreApplication::translate("solid-hardware", " # Send \"Repair\" request to the device corresponding to 'udi'.\n");
return data;
}
int main(int argc, char **argv)
{
SolidHardware app(argc, argv);
app.setApplicationName(appName);
app.setApplicationVersion(version);
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::translate("solid-hardware", "KDE tool for querying your hardware from the command line"));
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("command"), QCoreApplication::translate("solid-hardware", "Command to execute"), commandsHelp());
QCommandLineOption commands(QStringLiteral("commands"), QCoreApplication::translate("solid-hardware", "Show available commands"));
// --commands only for backwards compat, it's now in the "syntax help"
// of the positional argument.
commands.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(commands);
parser.process(app);
if (parser.isSet(commands)) {
cout << commandsHelp() << endl;
return 0;
}
QStringList args = parser.positionalArguments();
if (args.count() < 1) {
parser.showHelp(1);
}
parser.clearPositionalArguments();
QString command(args.at(0));
if (command == QLatin1String("list")) {
parser.addPositionalArgument(QStringLiteral("details"), QCoreApplication::translate("solid-hardware", "Show device details"));
parser.addPositionalArgument(QStringLiteral("nonportableinfo"), QCoreApplication::translate("solid-hardware", "Show non portable information"));
parser.process(app);
args = parser.positionalArguments();
QByteArray extra(args.count() == 2 ? args.at(1).toLocal8Bit() : QByteArray());
return app.hwList(extra == "details", extra == "nonportableinfo");
} else if (command == QLatin1String("details")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwCapabilities(udi);
} else if (command == QLatin1String("nonportableinfo")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwProperties(udi);
} else if (command == QLatin1String("query")) {
parser.addPositionalArgument(QStringLiteral("udi"), QCoreApplication::translate("solid-hardware", "Device udi"));
parser.addPositionalArgument(QStringLiteral("parent"), QCoreApplication::translate("solid-hardware", "Parent device udi"));
parser.process(app);
if (parser.positionalArguments().count() < 2 || parser.positionalArguments().count() > 3) {
parser.showHelp(1);
}
QString query = args.at(1);
QString parent;
if (args.count() == 3) {
parent = args.at(2);
}
return app.hwQuery(parent, query);
} else if (command == QLatin1String("mount")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::Mount, udi);
} else if (command == QLatin1String("unmount")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::Unmount, udi);
} else if (command == QLatin1String("eject")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::Eject, udi);
} else if (command == QLatin1String("listen")) {
return app.listen();
} else if (command == QLatin1String("monitor")) {
const QString udi = getUdiFromArguments(app, parser);
return app.monitor(udi);
} else if (command == QLatin1String("CanCheck")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::CanCheck, udi);
} else if (command == QLatin1String("Check")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::Check, udi);
} else if (command == QLatin1String("CanRepair")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::CanRepair, udi);
} else if (command == QLatin1String("Repair")) {
const QString udi = getUdiFromArguments(app, parser);
return app.hwVolumeCall(SolidHardware::Repair, udi);
}
cerr << QCoreApplication::translate("solid-hardware", "Syntax Error: Unknown command '%1'").arg(command) << endl;
return 1;
}
bool SolidHardware::hwList(bool interfaces, bool system)
{
const QList<Solid::Device> all = Solid::Device::allDevices();
for (const Solid::Device &device : all) {
cout << "udi = '" << device.udi() << "'" << endl;
if (interfaces) {
cout << device << endl;
} else if (system && device.is<Solid::GenericInterface>()) {
QMap<QString, QVariant> properties = device.as<Solid::GenericInterface>()->allProperties();
cout << properties << endl;
}
}
return true;
}
bool SolidHardware::hwCapabilities(const QString &udi)
{
const Solid::Device device(udi);
cout << "udi = '" << device.udi() << "'" << endl;
cout << device << endl;
return true;
}
bool SolidHardware::hwProperties(const QString &udi)
{
const Solid::Device device(udi);
cout << "udi = '" << device.udi() << "'" << endl;
if (device.is<Solid::GenericInterface>()) {
QMap<QString, QVariant> properties = device.as<Solid::GenericInterface>()->allProperties();
cout << properties << endl;
}
return true;
}
bool SolidHardware::hwQuery(const QString &parentUdi, const QString &query)
{
const QList<Solid::Device> devices = Solid::Device::listFromQuery(query, parentUdi);
for (const Solid::Device &device : devices) {
cout << "udi = '" << device.udi() << "'" << endl;
}
return true;
}
bool SolidHardware::hwVolumeCall(SolidHardware::VolumeCallType type, const QString &udi)
{
Solid::Device device(udi);
if (!device.is<Solid::StorageAccess>() && type != Eject) {
cerr << tr("Error: %1 does not have the interface StorageAccess.").arg(udi) << endl;
return false;
} else if (!device.is<Solid::OpticalDrive>() && type == Eject) {
cerr << tr("Error: %1 does not have the interface OpticalDrive.").arg(udi) << endl;
return false;
}
switch (type) {
case Mount:
connect(device.as<Solid::StorageAccess>(),
SIGNAL(setupDone(Solid::ErrorType, QVariant, QString)),
this,
SLOT(slotStorageResult(Solid::ErrorType, QVariant)));
device.as<Solid::StorageAccess>()->setup();
break;
case Unmount:
connect(device.as<Solid::StorageAccess>(),
SIGNAL(teardownDone(Solid::ErrorType, QVariant, QString)),
this,
SLOT(slotStorageResult(Solid::ErrorType, QVariant)));
device.as<Solid::StorageAccess>()->teardown();
break;
case Eject:
connect(device.as<Solid::OpticalDrive>(),
SIGNAL(ejectDone(Solid::ErrorType, QVariant, QString)),
this,
SLOT(slotStorageResult(Solid::ErrorType, QVariant)));
device.as<Solid::OpticalDrive>()->eject();
break;
case CanCheck:
cout << tr("Device CanCheck: %1").arg(device.as<Solid::StorageAccess>()->canCheck() == 0 ? tr("no") : tr("yes")) << endl;
cout << "udi = '" << udi << "'" << endl;
return true;
case Check:
if (device.as<Solid::StorageAccess>()->canCheck()) {
cout << tr("Device Check: %1").arg(device.as<Solid::StorageAccess>()->check() == 0 ? tr("has error") : tr("no error")) << endl;
} else {
cout << tr("Device Check: operation is not supported") << endl;
}
cout << "udi = '" << udi << "'" << endl;
return true;
case CanRepair:
cout << tr("Device CanRepair: %1").arg(device.as<Solid::StorageAccess>()->canRepair() == 0 ? tr("no") : tr("yes")) << endl;
cout << "udi = '" << udi << "'" << endl;
return true;
case Repair:
connect(device.as<Solid::StorageAccess>(),
SIGNAL(repairDone(Solid::ErrorType, QVariant, QString)),
this,
SLOT(slotStorageResult(Solid::ErrorType, QVariant)));
device.as<Solid::StorageAccess>()->repair();
break;
}
m_loop.exec();
if (m_error) {
cerr << tr("Error: %1").arg(m_errorString) << endl;
return false;
}
return true;
}
bool SolidHardware::listen()
{
Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
bool a = connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(deviceAdded(QString)));
bool d = connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(deviceRemoved(QString)));
if (!a || !d) {
return false;
}
cout << "Listening to add/remove events: " << endl;
m_loop.exec();
return true;
}
bool SolidHardware::monitor(const QString &udi)
{
Solid::Device device(udi);
if (!device.is<Solid::GenericInterface>())
return false;
auto genericInterface = device.as<Solid::GenericInterface>();
cout << "udi = '" << device.udi() << "'" << endl;
cout << genericInterface->allProperties();
connect(genericInterface, &Solid::GenericInterface::propertyChanged,
this, [genericInterface](const auto &changes) {
cout << endl;
for (auto it = changes.begin(); it != changes.end(); ++it) {
cout << " " << it.key() << " = " << genericInterface->property(it.key()) << endl;
}
});
m_loop.exec();
return true;
}
void SolidHardware::deviceAdded(const QString &udi)
{
cout << "Device Added:" << endl;
cout << "udi = '" << udi << "'" << endl;
}
void SolidHardware::deviceRemoved(const QString &udi)
{
cout << "Device Removed:" << endl;
cout << "udi = '" << udi << "'" << endl;
}
void SolidHardware::slotStorageResult(Solid::ErrorType error, const QVariant &errorData)
{
if (error) {
m_error = 1;
m_errorString = errorData.toString();
}
m_loop.exit();
}
#include "moc_solid-hardware.cpp"
@@ -0,0 +1,48 @@
/* This file is part of the KDE project
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2014 Alejandro Fiestas Olivares <afiestas@kde.org>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef SOLID_HARDWARE_H
#define SOLID_HARDWARE_H
#include <QCoreApplication>
#include <QEventLoop>
#include <solid/storageaccess.h>
class QCommandLineParser;
class SolidHardware : public QCoreApplication
{
Q_OBJECT
public:
SolidHardware(int &argc, char **argv)
: QCoreApplication(argc, argv)
, m_error(0)
{
}
bool hwList(bool interfaces, bool system);
bool hwCapabilities(const QString &udi);
bool hwProperties(const QString &udi);
bool hwQuery(const QString &parentUdi, const QString &query);
bool listen();
bool monitor(const QString &udi);
enum VolumeCallType { Mount, Unmount, Eject, CanCheck, Check, CanRepair, Repair };
bool hwVolumeCall(VolumeCallType type, const QString &udi);
private:
QEventLoop m_loop;
int m_error;
QString m_errorString;
private Q_SLOTS:
void slotStorageResult(Solid::ErrorType error, const QVariant &errorData);
void deviceAdded(const QString &udi);
void deviceRemoved(const QString &udi);
};
#endif // SOLID_HARDWARE_H