Skip to content

Commit 868285a

Browse files
committed
Implement gpu_identifier, UI updates
1 parent bf9f704 commit 868285a

File tree

8 files changed

+252
-17
lines changed

8 files changed

+252
-17
lines changed

CM_Config/LibraryHandler.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
set(CMAKE_AUTOMOC ON)
2+
13
find_package(PkgConfig REQUIRED)
24
find_package(Qt6 REQUIRED COMPONENTS Widgets Gui Core)
35

Sources/AppGUI/UI/MainWindow.cpp

Lines changed: 104 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,56 @@
22
#include "UnitSelector.hpp"
33

44
#include <QMessageBox>
5-
#include <QStringListModel>
65

76
#include <RunAsGPU/Shared/GraphicalUnit.hpp>
87
#include <RunAsGPU/Shared/Runner.hpp>
98

9+
#include "Model/AppListModel.hpp"
10+
#include "Model/AppListDelegate.hpp"
11+
1012
#include <filesystem>
1113
#include <fstream>
1214
#include <iostream>
15+
#include <QProcess>
1316

1417
namespace fs = std::filesystem;
1518

16-
static QStringListModel appListModel;
17-
static QStringList appEntries;
19+
AppListModel *model;
20+
AppListDelegate *delegate;
21+
22+
void save_default_gpu(const std::vector<GraphicalUnit> &gpu_list, int gpu_unit) {
23+
const char *home_dir = getenv("HOME");
24+
if (!home_dir)
25+
return;
26+
27+
std::string dir_path = std::string(home_dir) + "/.config/RunAsGPU";
28+
if (!fs::exists(dir_path)) {
29+
if (!fs::create_directory(dir_path)) {
30+
std::cerr << "Failed to create config directory, exiting application" << std::endl;
31+
std::abort();
32+
}
33+
}
34+
35+
std::string file_path = std::string(home_dir) + "/.config/RunAsGPU/gpu_identifier";
36+
std::ofstream file(file_path);
37+
if (file.is_open()) {
38+
file << "GPU_VENDOR_ID=" << std::hex << gpu_list[gpu_unit].vendor << std::endl;
39+
file << "GPU_DEVICE_ID=" << std::hex << gpu_list[gpu_unit].product << std::endl;
40+
file.close();
41+
} else
42+
std::cerr << "Failed to open file for writing: " << file_path << std::endl;
43+
}
1844

1945
int get_default_gpu(const std::vector<GraphicalUnit> &gpu_list) {
2046
const char *home_dir = getenv("HOME");
2147
if (!home_dir)
2248
return -1;
2349

2450
std::string file_path = std::string(home_dir) + "/.config/RunAsGPU/gpu_identifier";
25-
if (!fs::exists(file_path))
51+
if (!fs::exists(file_path)) {
52+
save_default_gpu(gpu_list, 0);
2653
return 0;
54+
}
2755

2856
std::string VID, DID;
2957
std::ifstream file(file_path);
@@ -52,34 +80,93 @@ int get_default_gpu(const std::vector<GraphicalUnit> &gpu_list) {
5280
return 0;
5381
}
5482

83+
int gpuUnit;
84+
5585
void Ui_MainWindow::performLogic() const {
5686
std::vector<GraphicalUnit> gpu_list = Runner::ListGraphicalUnits();
5787
if (gpu_list.empty()) {
5888
std::cerr << "GPU list empty, exiting..." << std::endl;
5989
std::abort();
60-
return;
6190
}
6291

63-
int gpuUnit = get_default_gpu(gpu_list);
64-
65-
appListModel.setStringList(appEntries);
66-
appList->setModel(&appListModel);
92+
gpuUnit = get_default_gpu(gpu_list);
93+
if (gpuUnit == -1)
94+
gpuUnit = 0;
95+
96+
model = new AppListModel(appList);
97+
delegate = new AppListDelegate(appList);
98+
99+
appList->setModel(model);
100+
appList->setItemDelegate(delegate);
101+
appList->setViewMode(QListView::ListMode);
102+
appList->setUniformItemSizes(true);
103+
appList->setSpacing(5);
104+
appList->setSelectionMode(QAbstractItemView::SingleSelection);
105+
appList->setEditTriggers(QAbstractItemView::NoEditTriggers);
106+
appList->setFocusPolicy(Qt::StrongFocus);
107+
108+
model->addItem(Application("Blender", "3D modeling software", "/usr/bin/blender",
109+
QIcon("/home/bc100dev/.local/share/icons/kora/apps/scalable/blender.svg")));
110+
model->addItem(Application("Firefox", "Mozilla Firefox", "/usr/bin/firefox",
111+
QIcon("/home/bc100dev/.local/share/icons/kora/apps/scalable/firefox.svg")));
112+
113+
QObject::connect(appList->selectionModel(), &QItemSelectionModel::currentChanged,
114+
[&](const QModelIndex &current, const QModelIndex &) {
115+
if (current.isValid()) {
116+
qDebug() << "Selected App:" << current.data(Qt::DisplayRole).toString();
117+
}
118+
});
119+
120+
QObject::connect(appList, &QListView::doubleClicked, [&](const QModelIndex &index) {
121+
if (index.isValid()) {
122+
QString execPath = index.data(Qt::UserRole).toString();
123+
if (!execPath.isEmpty())
124+
QProcess::startDetached(execPath);
125+
}
126+
});
67127

68128
// "Add Application" button logic
69129
QObject::connect(btnApplicationAdd, &QPushButton::clicked, [&]() {
70-
QString appEntry = "New Application Entry"; // Placeholder for actual selection logic
71-
appEntries.append(appEntry); // Add entry to QStringList
72-
appListModel.setStringList(appEntries); // Update QListView
130+
// TODO: show app selection dialog
131+
model->addItem(
132+
Application(QString("Terminator"), QString("Nice looking Terminal"), QString("/usr/bin/terminator"),
133+
QIcon("/usr/share/icons/HighContrast/16x16/apps/terminator.png")));
73134
});
74135

75136
// "Run Application" button logic
76137
QObject::connect(btnRun, &QPushButton::clicked, [&]() {
77-
if (appEntries.isEmpty()) {
78-
QMessageBox::warning(nullptr, "Run Application", "No application selected.");
79-
} else {
80-
QMessageBox::information(nullptr, "Run Application", "Running: " + appEntries.first());
81-
// TODO: Implement actual GPU switching logic
138+
QModelIndex index = appList->currentIndex();
139+
if (!index.isValid()) {
140+
qDebug() << "No application selected";
141+
QMessageBox::warning(nullptr, "No Application selected", "Please select an application to run.");
142+
return;
143+
}
144+
145+
QString execPath = index.data(Qt::UserRole).toString();
146+
if (execPath.isEmpty()) {
147+
QMessageBox::warning(nullptr, "Invalid application", "The selected application has no executable path.");
148+
return;
82149
}
150+
151+
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
152+
env.insert("DRI_PRIME", QString::number(gpuUnit));
153+
154+
auto *process = new QProcess();
155+
process->setProcessEnvironment(env);
156+
process->setProgram(execPath);
157+
process->setArguments(QStringList());
158+
159+
qDebug() << "Running: " << execPath;
160+
process->start();
161+
if (!process->waitForStarted()) {
162+
QMessageBox::warning(nullptr, "Execution Failed", "Failed to start application: " + execPath);
163+
delete process;
164+
return;
165+
}
166+
167+
168+
process->disconnect();
169+
process->setParent(nullptr);
83170
});
84171

85172
// "Select GPU" button logic

Sources/AppGUI/UI/MainWindow.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class Ui_MainWindow {
4545
appList = new QListView(centralwidget);
4646
appList->setObjectName("appList");
4747
appList->setGeometry(QRect(0, 20, 581, 281));
48+
appList->setStyleSheet("QListView::item:selected { background-color: #0078d7; }");
49+
appList->setFocusPolicy(Qt::StrongFocus);
50+
appList->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
4851
btnApplicationAdd = new QPushButton(centralwidget);
4952
btnApplicationAdd->setObjectName("btnApplicationAdd");
5053
btnApplicationAdd->setGeometry(QRect(0, 310, 121, 34));

Sources/AppGUI/UI/MainWindow.ui

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858
<height>281</height>
5959
</rect>
6060
</property>
61+
<property name="selectionBehavior">
62+
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
63+
</property>
64+
<property name="wordWrap">
65+
<bool>true</bool>
66+
</property>
6167
</widget>
6268
<widget class="QPushButton" name="btnApplicationAdd">
6369
<property name="geometry">
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "AppListDelegate.hpp"
2+
3+
AppListDelegate::AppListDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
4+
5+
void AppListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
6+
painter->save();
7+
8+
if (option.state & QStyle::State_Selected)
9+
painter->fillRect(option.rect, option.palette.highlight());
10+
else if (option.state & QStyle::State_MouseOver)
11+
painter->fillRect(option.rect, option.palette.light());
12+
else
13+
painter->fillRect(option.rect, option.palette.base());
14+
15+
QRect rect = option.rect;
16+
QVariant var = index.data(Qt::DecorationRole);
17+
QIcon icon;
18+
19+
if (var.metaType() == QMetaType::fromType<QIcon>())
20+
icon = var.value<QIcon>();
21+
22+
QString name = index.data(Qt::DisplayRole).toString();
23+
24+
QRect iconRect = QRect(rect.left() + 5, rect.top() + 5, 32, 32);
25+
icon.paint(painter, iconRect);
26+
27+
QRect textRect = QRect(iconRect.right() + 12, rect.top(), rect.width() - 50, rect.height());
28+
painter->drawText(textRect, Qt::AlignVCenter, name);
29+
30+
painter->restore();
31+
}
32+
33+
QSize AppListDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const {
34+
return QSize(150, 40);
35+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef RUNASGPU_APPLISTDELEGATE_HPP
2+
#define RUNASGPU_APPLISTDELEGATE_HPP
3+
4+
#include <QStyledItemDelegate>
5+
#include <QPainter>
6+
#include <QStyleOptionViewItem>
7+
8+
class AppListDelegate : public QStyledItemDelegate {
9+
Q_OBJECT
10+
11+
public:
12+
explicit AppListDelegate(QObject *parent = nullptr);
13+
14+
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
15+
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
16+
};
17+
18+
#endif //RUNASGPU_APPLISTDELEGATE_HPP
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "AppListModel.hpp"
2+
3+
AppListModel::AppListModel(QObject *parent) : QAbstractListModel() {}
4+
5+
int AppListModel::rowCount(const QModelIndex &parent) const {
6+
if (parent.isValid())
7+
return 0;
8+
9+
return apps.size();
10+
}
11+
12+
QVariant AppListModel::data(const QModelIndex &index, int role) const {
13+
if (!index.isValid() || index.row() >= apps.size())
14+
return QVariant();
15+
16+
const Application &app = apps[index.row()];
17+
18+
switch (role) {
19+
case Qt::DisplayRole:
20+
return app.name;
21+
case Qt::DecorationRole:
22+
return app.icon;
23+
case Qt::ToolTipRole:
24+
return app.description;
25+
case Qt::UserRole:
26+
return app.execPath;
27+
default:
28+
return QVariant();
29+
}
30+
}
31+
32+
Qt::ItemFlags AppListModel::flags(const QModelIndex &index) const {
33+
if (!index.isValid())
34+
return Qt::NoItemFlags;
35+
36+
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
37+
}
38+
39+
void AppListModel::addItem(const Application &app) {
40+
beginInsertRows(QModelIndex(), apps.size(), apps.size());
41+
apps.append(app);
42+
endInsertRows();
43+
}
44+
45+
void AppListModel::clear() {
46+
beginResetModel();
47+
apps.clear();
48+
endResetModel();
49+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef RUNASGPU_APPLISTMODEL_HPP
2+
#define RUNASGPU_APPLISTMODEL_HPP
3+
4+
#include <QString>
5+
#include <QIcon>
6+
#include <QAbstractListModel>
7+
8+
struct Application {
9+
QString name;
10+
QString description;
11+
QString execPath;
12+
QIcon icon;
13+
14+
Application(const QString &n, const QString &d, const QString &e, const QIcon &i)
15+
: name(n), description(d), execPath(e), icon(i) {}
16+
};
17+
18+
class AppListModel : public QAbstractListModel {
19+
Q_OBJECT
20+
21+
public:
22+
explicit AppListModel(QObject *parent = nullptr);
23+
24+
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
25+
QVariant data(const QModelIndex &index, int role) const override;
26+
Qt::ItemFlags flags(const QModelIndex &index) const override;
27+
28+
void addItem(const Application &app);
29+
void clear();
30+
31+
private:
32+
QVector<Application> apps;
33+
};
34+
35+
#endif //RUNASGPU_APPLISTMODEL_HPP

0 commit comments

Comments
 (0)