diff --git a/CMakeLists.txt b/CMakeLists.txt index 5826ebe..97650f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,9 +27,10 @@ qt_standard_project_setup() qt_add_executable(waycast) include_directories("${CMAKE_SOURCE_DIR}/lib") -include_directories("${CMAKE_SOURCE_DIR}/lib") +include_directories("${CMAKE_SOURCE_DIR}/lib/ui") file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/src/*.cpp") -target_sources(waycast PRIVATE ${SRC_FILES} src/main.cpp) +file(GLOB_RECURSE LIB_UI_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/lib/ui/*.cpp") +target_sources(waycast PRIVATE ${SRC_FILES} ${LIB_UI_FILES} src/main.cpp) target_include_directories(waycast PRIVATE ${CMAKE_SOURCE_DIR}/lib) # target_include_directories(waycast PRIVATE ${CMAKE_SOURCE_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/lib/dmenu.hpp b/lib/dmenu.hpp index f3d9f93..4c58340 100644 --- a/lib/dmenu.hpp +++ b/lib/dmenu.hpp @@ -62,7 +62,7 @@ namespace dmenu } }; - std::vector split(std::string s, char delimiter) + inline std::vector split(std::string s, char delimiter) { std::vector items; std::string line; @@ -77,7 +77,7 @@ namespace dmenu } using DEVec = std::unique_ptr>; - DEVec get_dmenu_app_data() + inline DEVec get_dmenu_app_data() { DEVec out = std::make_unique>(); const char* env_dirs = std::getenv("XDG_DATA_DIRS"); @@ -96,7 +96,10 @@ namespace dmenu for (const auto &dfile : desktopFiles) { - out->emplace_back(dfile.string()); + DesktopEntry entry(dfile.string()); + if (entry.display) { + out->push_back(std::move(entry)); + } } } diff --git a/lib/files.hpp b/lib/files.hpp index 721e104..005d2cc 100644 --- a/lib/files.hpp +++ b/lib/files.hpp @@ -12,7 +12,7 @@ namespace files { namespace fs = std::filesystem; - std::vector findFilesWithExtension(const std::string path, const std::string ext) + inline std::vector findFilesWithExtension(const std::string path, const std::string ext) { std::vector out; std::unordered_set seen; // canonicalized paths to dedupe @@ -40,7 +40,7 @@ namespace files return out; } - std::string readFile(const std::string &filename) + inline std::string readFile(const std::string &filename) { std::ifstream in(filename); if (!in) diff --git a/lib/ui/AppListModel.cpp b/lib/ui/AppListModel.cpp new file mode 100644 index 0000000..f317bf5 --- /dev/null +++ b/lib/ui/AppListModel.cpp @@ -0,0 +1,49 @@ +#include "AppListModel.hpp" +#include + +AppListModel::AppListModel(QObject *parent) + : QAbstractListModel(parent) +{ + loadApps(); +} + +int AppListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return m_apps ? static_cast(m_apps->size()) : 0; +} + +QVariant AppListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || !m_apps || index.row() >= static_cast(m_apps->size())) + return QVariant(); + + const dmenu::DesktopEntry &app = (*m_apps)[index.row()]; + + switch (role) { + case NameRole: + return QString::fromStdString(app.name); + case ExecRole: + return QString::fromStdString(app.exec); + case IdRole: + return QString::fromStdString(app.id); + default: + return QVariant(); + } +} + +QHash AppListModel::roleNames() const +{ + QHash roles; + roles[NameRole] = "name"; + roles[ExecRole] = "exec"; + roles[IdRole] = "id"; + return roles; +} + +void AppListModel::loadApps() +{ + beginResetModel(); + m_apps = dmenu::get_dmenu_app_data(); + endResetModel(); +} \ No newline at end of file diff --git a/lib/ui/AppListModel.hpp b/lib/ui/AppListModel.hpp new file mode 100644 index 0000000..a76a440 --- /dev/null +++ b/lib/ui/AppListModel.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#undef signals +#include "../dmenu.hpp" +#define signals public + +class AppListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum AppRoles { + NameRole = Qt::UserRole + 1, + ExecRole, + IdRole + }; + + explicit AppListModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + Q_INVOKABLE void loadApps(); + +private: + dmenu::DEVec m_apps; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 26c1b9a..54bcbc9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,11 @@ -#include "dmenu.hpp" -#include "files.hpp" #include #include #include #include #include +#include "ui/AppListModel.hpp" +#include "dmenu.hpp" +#include "files.hpp" #include #include #include @@ -37,12 +38,15 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); QCoreApplication::setApplicationName("waycast"); - + // Enable system theme support app.setDesktopSettingsAware(true); QQmlApplicationEngine engine; + // Register the AppListModel type with QML + qmlRegisterType("WayCast", 1, 0, "AppListModel"); + // Set up layer shell before creating any windows QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }); diff --git a/ui/Main.qml b/ui/Main.qml index 5010fee..5bc2462 100644 --- a/ui/Main.qml +++ b/ui/Main.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Window import QtQuick.Controls.Material import QtQuick.Controls.Universal +import WayCast ApplicationWindow { id: win @@ -44,7 +45,7 @@ ApplicationWindow { Keys.onUpPressed: listView.decrementCurrentIndex() Keys.onReturnPressed: { if (listView.currentItem) { - console.log("Selected:", listModel.get(listView.currentIndex).name) + console.log("Selected:", appModel.data(appModel.index(listView.currentIndex, 0), Qt.UserRole + 1)) } } } @@ -56,7 +57,7 @@ ApplicationWindow { ListView { id: listView - model: listModel + model: appModel currentIndex: 0 highlightFollowsCurrentItem: true @@ -112,12 +113,7 @@ ApplicationWindow { } } - ListModel { - id: listModel - ListElement { name: "Firefox"; exec: "firefox" } - ListElement { name: "Terminal"; exec: "gnome-terminal" } - ListElement { name: "File Manager"; exec: "nautilus" } - ListElement { name: "Text Editor"; exec: "gedit" } - ListElement { name: "Calculator"; exec: "gnome-calculator" } + AppListModel { + id: appModel } }