App icons
This commit is contained in:
parent
fc2335f138
commit
3a66939627
@ -2,6 +2,12 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
AppListModel::AppListModel(QObject *parent)
|
AppListModel::AppListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
@ -30,6 +36,8 @@ QVariant AppListModel::data(const QModelIndex &index, int role) const
|
|||||||
return QString::fromStdString(app.exec);
|
return QString::fromStdString(app.exec);
|
||||||
case IdRole:
|
case IdRole:
|
||||||
return QString::fromStdString(app.id);
|
return QString::fromStdString(app.id);
|
||||||
|
case IconRole:
|
||||||
|
return getIconUrl(app);
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -41,6 +49,7 @@ QHash<int, QByteArray> AppListModel::roleNames() const
|
|||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[ExecRole] = "exec";
|
roles[ExecRole] = "exec";
|
||||||
roles[IdRole] = "id";
|
roles[IdRole] = "id";
|
||||||
|
roles[IconRole] = "icon";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,3 +115,57 @@ void AppListModel::updateFilteredApps()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl AppListModel::getIconUrl(const dmenu::DesktopEntry &app) const
|
||||||
|
{
|
||||||
|
QString iconName = QString::fromStdString(app.icon_path);
|
||||||
|
|
||||||
|
if (iconName.isEmpty())
|
||||||
|
return QUrl();
|
||||||
|
|
||||||
|
// If it's already a full path, use it directly
|
||||||
|
if (iconName.startsWith('/')) {
|
||||||
|
if (QFile::exists(iconName)) {
|
||||||
|
return QUrl::fromLocalFile(iconName);
|
||||||
|
}
|
||||||
|
return QUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Qt's proper icon theme search which follows XDG spec
|
||||||
|
QIcon icon = QIcon::fromTheme(iconName);
|
||||||
|
if (icon.isNull()) {
|
||||||
|
return QUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt doesn't expose the resolved file path directly, so let's use QStandardPaths
|
||||||
|
// to search in the proper system directories
|
||||||
|
QStringList dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||||
|
|
||||||
|
// Common icon subdirectories and sizes (prioritized)
|
||||||
|
QStringList iconSubDirs = {
|
||||||
|
"icons/hicolor/scalable/apps",
|
||||||
|
"icons/hicolor/48x48/apps",
|
||||||
|
"icons/hicolor/64x64/apps",
|
||||||
|
"icons/hicolor/32x32/apps",
|
||||||
|
"icons/hicolor/128x128/apps",
|
||||||
|
"icons/Adwaita/scalable/apps",
|
||||||
|
"icons/Adwaita/48x48/apps",
|
||||||
|
"pixmaps"
|
||||||
|
};
|
||||||
|
|
||||||
|
QStringList extensions = {"", ".png", ".svg", ".xpm"};
|
||||||
|
|
||||||
|
for (const QString &dataDir : dataDirs) {
|
||||||
|
for (const QString &iconSubDir : iconSubDirs) {
|
||||||
|
QString basePath = dataDir + "/" + iconSubDir + "/";
|
||||||
|
for (const QString &ext : extensions) {
|
||||||
|
QString fullPath = basePath + iconName + ext;
|
||||||
|
if (QFile::exists(fullPath)) {
|
||||||
|
return QUrl::fromLocalFile(fullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QUrl();
|
||||||
|
}
|
@ -16,7 +16,8 @@ public:
|
|||||||
enum AppRoles {
|
enum AppRoles {
|
||||||
NameRole = Qt::UserRole + 1,
|
NameRole = Qt::UserRole + 1,
|
||||||
ExecRole,
|
ExecRole,
|
||||||
IdRole
|
IdRole,
|
||||||
|
IconRole
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit AppListModel(QObject *parent = nullptr);
|
explicit AppListModel(QObject *parent = nullptr);
|
||||||
@ -36,6 +37,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFilteredApps();
|
void updateFilteredApps();
|
||||||
|
QUrl getIconUrl(const dmenu::DesktopEntry &app) const;
|
||||||
|
|
||||||
dmenu::DEVec m_apps;
|
dmenu::DEVec m_apps;
|
||||||
std::vector<int> m_filteredIndexes;
|
std::vector<int> m_filteredIndexes;
|
||||||
|
84
src/main.cpp
84
src/main.cpp
@ -30,48 +30,48 @@ std::vector<std::string> split(std::string s, char delimiter)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
dmenu::DEVec apps = dmenu::get_dmenu_app_data();
|
// dmenu::DEVec apps = dmenu::get_dmenu_app_data();
|
||||||
for (auto &app : *apps.get())
|
// for (auto &app : *apps.get())
|
||||||
|
// {
|
||||||
|
// std::cout << app.iconPath() << std::endl;
|
||||||
|
// // std::cout << std::format("---\nName: {}\nID: {}\nIcon: {}\nExec: {}\nDisp: {}\n---\n", app.id, app.name, app.iconPath(), app.exec, app.display ? "yes" : "no");
|
||||||
|
// }
|
||||||
|
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
QCoreApplication::setApplicationName("waycast");
|
||||||
|
|
||||||
|
// Enable system theme support
|
||||||
|
app.setDesktopSettingsAware(true);
|
||||||
|
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
|
// Register the AppListModel type with QML
|
||||||
|
qmlRegisterType<AppListModel>("WayCast", 1, 0, "AppListModel");
|
||||||
|
|
||||||
|
// Set up layer shell before creating any windows
|
||||||
|
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []()
|
||||||
|
{ QCoreApplication::exit(-1); });
|
||||||
|
|
||||||
|
engine.loadFromModule("WayCast", "Main");
|
||||||
|
|
||||||
|
// Get the root objects and configure layer shell
|
||||||
|
auto rootObjects = engine.rootObjects();
|
||||||
|
if (!rootObjects.isEmpty())
|
||||||
{
|
{
|
||||||
std::cout << app.iconPath() << std::endl;
|
QWindow *window = qobject_cast<QWindow *>(rootObjects.first());
|
||||||
// std::cout << std::format("---\nName: {}\nID: {}\nIcon: {}\nExec: {}\nDisp: {}\n---\n", app.id, app.name, app.iconPath(), app.exec, app.display ? "yes" : "no");
|
if (window)
|
||||||
|
{
|
||||||
|
LayerShellQt::Window *layerWindow = LayerShellQt::Window::get(window);
|
||||||
|
if (layerWindow)
|
||||||
|
{
|
||||||
|
layerWindow->setLayer(LayerShellQt::Window::LayerTop);
|
||||||
|
layerWindow->setAnchors({});
|
||||||
|
layerWindow->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityOnDemand);
|
||||||
|
|
||||||
|
// Now show the window after layer shell is configured
|
||||||
|
window->show();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// QGuiApplication app(argc, argv);
|
}
|
||||||
// QCoreApplication::setApplicationName("waycast");
|
return app.exec();
|
||||||
|
|
||||||
// // Enable system theme support
|
|
||||||
// app.setDesktopSettingsAware(true);
|
|
||||||
|
|
||||||
// QQmlApplicationEngine engine;
|
|
||||||
|
|
||||||
// // Register the AppListModel type with QML
|
|
||||||
// qmlRegisterType<AppListModel>("WayCast", 1, 0, "AppListModel");
|
|
||||||
|
|
||||||
// // Set up layer shell before creating any windows
|
|
||||||
// QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []()
|
|
||||||
// { QCoreApplication::exit(-1); });
|
|
||||||
|
|
||||||
// engine.loadFromModule("WayCast", "Main");
|
|
||||||
|
|
||||||
// // Get the root objects and configure layer shell
|
|
||||||
// auto rootObjects = engine.rootObjects();
|
|
||||||
// if (!rootObjects.isEmpty())
|
|
||||||
// {
|
|
||||||
// QWindow *window = qobject_cast<QWindow *>(rootObjects.first());
|
|
||||||
// if (window)
|
|
||||||
// {
|
|
||||||
// LayerShellQt::Window *layerWindow = LayerShellQt::Window::get(window);
|
|
||||||
// if (layerWindow)
|
|
||||||
// {
|
|
||||||
// layerWindow->setLayer(LayerShellQt::Window::LayerTop);
|
|
||||||
// layerWindow->setAnchors({});
|
|
||||||
// layerWindow->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityOnDemand);
|
|
||||||
|
|
||||||
// // Now show the window after layer shell is configured
|
|
||||||
// window->show();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return app.exec();
|
|
||||||
}
|
}
|
||||||
|
10
ui/Main.qml
10
ui/Main.qml
@ -89,11 +89,18 @@ ApplicationWindow {
|
|||||||
anchors.margins: 10
|
anchors.margins: 10
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
Rectangle {
|
Image {
|
||||||
width: 24
|
width: 24
|
||||||
height: 24
|
height: 24
|
||||||
|
source: model.icon
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
||||||
|
// Fallback if icon fails to load
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
color: palette.button
|
color: palette.button
|
||||||
radius: 4
|
radius: 4
|
||||||
|
visible: parent.status === Image.Error || parent.status === Image.Null
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@ -101,6 +108,7 @@ ApplicationWindow {
|
|||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user