xdg-desktop-portal-hyprland/hyprland-share-picker/main.cpp

257 lines
8.5 KiB
C++
Raw Permalink Normal View History

2022-12-03 22:27:49 +01:00
#include <QApplication>
2023-02-03 19:41:28 +01:00
#include <QEvent>
#include <QObject>
#include <QPushButton>
2022-12-03 22:27:49 +01:00
#include <QScreen>
#include <QTabWidget>
2023-02-03 19:41:28 +01:00
#include <QWidget>
2022-12-03 22:27:49 +01:00
#include <QtDebug>
2023-02-03 19:41:28 +01:00
#include <QtWidgets>
#include <QSettings>
2023-02-03 19:41:28 +01:00
#include <array>
2022-12-03 22:27:49 +01:00
#include <cstdio>
2023-02-03 19:41:28 +01:00
#include <iostream>
2022-12-03 22:27:49 +01:00
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
2022-12-03 22:27:49 +01:00
2023-02-03 19:41:28 +01:00
#include "mainpicker.h"
#include "elidedbutton.h"
2023-02-03 19:41:28 +01:00
2022-12-03 22:27:49 +01:00
std::string execAndGet(const char* cmd) {
2023-09-06 20:36:48 +02:00
std::array<char, 128> buffer;
std::string result;
2022-12-03 22:27:49 +01:00
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
2023-09-06 20:36:48 +02:00
QApplication* pickerPtr = nullptr;
MainPicker* mainPickerPtr = nullptr;
struct SWindowEntry {
2023-09-06 20:36:48 +02:00
std::string name;
std::string clazz;
2023-02-04 22:10:46 +01:00
unsigned long long id = 0;
};
std::vector<SWindowEntry> getWindows(const char* env) {
std::vector<SWindowEntry> result;
if (!env)
return result;
std::string rolling = env;
while (!rolling.empty()) {
// ID
2023-02-03 19:41:28 +01:00
const auto IDSEPPOS = rolling.find("[HC>]");
2023-09-06 20:36:48 +02:00
const auto IDSTR = rolling.substr(0, IDSEPPOS);
// class
2023-02-03 19:41:28 +01:00
const auto CLASSSEPPOS = rolling.find("[HT>]");
2023-09-06 20:36:48 +02:00
const auto CLASSSTR = rolling.substr(IDSEPPOS + 5, CLASSSEPPOS - IDSEPPOS - 5);
// title
2023-02-03 19:41:28 +01:00
const auto TITLESEPPOS = rolling.find("[HE>]");
2023-09-06 20:36:48 +02:00
const auto TITLESTR = rolling.substr(CLASSSEPPOS + 5, TITLESEPPOS - 5 - CLASSSEPPOS);
try {
2023-02-04 22:10:46 +01:00
result.push_back({TITLESTR, CLASSSTR, std::stoull(IDSTR)});
2023-02-03 20:05:59 +01:00
} catch (std::exception& e) {
2022-12-17 19:00:42 +01:00
// silent err
}
rolling = rolling.substr(TITLESEPPOS + 5);
}
return result;
}
2022-12-03 22:27:49 +01:00
2023-02-03 19:41:28 +01:00
int main(int argc, char* argv[]) {
2022-12-03 22:27:49 +01:00
qputenv("QT_LOGGING_RULES", "qml=false");
bool allowTokenByDefault = false;
for (int i = 1; i < argc; ++i) {
if (argv[i] == std::string{"--allow-token"})
allowTokenByDefault = true;
}
const char* WINDOWLISTSTR = getenv("XDPH_WINDOW_SHARING_LIST");
const auto WINDOWLIST = getWindows(WINDOWLISTSTR);
2022-12-03 22:27:49 +01:00
QApplication picker(argc, argv);
pickerPtr = &picker;
MainPicker w;
mainPickerPtr = &w;
2022-12-03 22:27:49 +01:00
QSettings* settings = new QSettings("/tmp/hypr/hyprland-share-picker.conf", QSettings::IniFormat);
w.setGeometry(0, 0, settings->value("width").toInt(), settings->value("height").toInt());
2022-12-03 22:27:49 +01:00
// get the tabwidget
const auto TABWIDGET = w.findChild<QTabWidget*>("tabWidget");
const auto ALLOWTOKENBUTTON = w.findChild<QCheckBox*>("checkBox");
if (allowTokenByDefault)
ALLOWTOKENBUTTON->setCheckState(Qt::CheckState::Checked);
2022-12-03 22:27:49 +01:00
const auto TAB1 = (QWidget*)TABWIDGET->children()[0];
2023-09-06 20:36:48 +02:00
const auto SCREENS_SCROLL_AREA_CONTENTS =
(QWidget*)TAB1->findChild<QWidget*>("screens")->findChild<QScrollArea*>("scrollArea")->findChild<QWidget*>("scrollAreaWidgetContents");
2022-12-03 22:27:49 +01:00
const auto SCREENS_SCROLL_AREA_CONTENTS_LAYOUT = SCREENS_SCROLL_AREA_CONTENTS->layout();
2022-12-03 22:27:49 +01:00
// add all screens
2023-09-06 20:36:48 +02:00
const auto SCREENS = picker.screens();
2022-12-03 22:27:49 +01:00
constexpr int BUTTON_HEIGHT = 41;
for (int i = 0; i < SCREENS.size(); ++i) {
const auto GEOMETRY = SCREENS[i]->geometry();
2022-12-03 22:27:49 +01:00
QString text = QString::fromStdString(std::string("Screen " + std::to_string(i) + " at " + std::to_string(GEOMETRY.x()) + ", " + std::to_string(GEOMETRY.y()) + " (" +
std::to_string(GEOMETRY.width()) + "x" + std::to_string(GEOMETRY.height()) + ") (") +
SCREENS[i]->name().toStdString() + ")");
QString outputName = SCREENS[i]->name();
ElidedButton* button = new ElidedButton(text);
button->setMinimumSize(0, BUTTON_HEIGHT);
SCREENS_SCROLL_AREA_CONTENTS_LAYOUT->addWidget(button);
2023-02-03 19:41:28 +01:00
QObject::connect(button, &QPushButton::clicked, [=]() {
std::cout << "[SELECTION]";
2023-09-06 20:36:48 +02:00
std::cout << (ALLOWTOKENBUTTON->isChecked() ? "r" : "");
std::cout << "/";
2022-12-03 22:27:49 +01:00
std::cout << "screen:" << outputName.toStdString() << "\n";
settings->setValue("width", mainPickerPtr->width());
settings->setValue("height", mainPickerPtr->height());
settings->sync();
2022-12-03 22:27:49 +01:00
pickerPtr->quit();
return 0;
2022-12-03 22:27:49 +01:00
});
}
QSpacerItem* SCREENS_SPACER = new QSpacerItem(0, 10000, QSizePolicy::Expanding, QSizePolicy::Expanding);
SCREENS_SCROLL_AREA_CONTENTS_LAYOUT->addItem(SCREENS_SPACER);
2022-12-03 22:27:49 +01:00
// windows
2023-09-06 20:36:48 +02:00
const auto WINDOWS_SCROLL_AREA_CONTENTS =
(QWidget*)TAB1->findChild<QWidget*>("windows")->findChild<QScrollArea*>("scrollArea_2")->findChild<QWidget*>("scrollAreaWidgetContents_2");
2022-12-03 22:27:49 +01:00
const auto WINDOWS_SCROLL_AREA_CONTENTS_LAYOUT = WINDOWS_SCROLL_AREA_CONTENTS->layout();
2022-12-03 22:27:49 +01:00
// loop over them
int windowIterator = 0;
for (auto& window : WINDOWLIST) {
QString text = QString::fromStdString(window.clazz + ": " + window.name);
2022-12-03 22:27:49 +01:00
ElidedButton* button = new ElidedButton(text);
button->setMinimumSize(0, BUTTON_HEIGHT);
WINDOWS_SCROLL_AREA_CONTENTS_LAYOUT->addWidget(button);
2022-12-03 22:27:49 +01:00
mainPickerPtr->windowIDs[button] = window.id;
2023-02-03 19:41:28 +01:00
QObject::connect(button, &QPushButton::clicked, [=]() {
std::cout << "[SELECTION]";
2023-09-06 20:36:48 +02:00
std::cout << (ALLOWTOKENBUTTON->isChecked() ? "r" : "");
std::cout << "/";
std::cout << "window:" << mainPickerPtr->windowIDs[button] << "\n";
settings->setValue("width", mainPickerPtr->width());
settings->setValue("height", mainPickerPtr->height());
settings->sync();
2022-12-03 22:27:49 +01:00
pickerPtr->quit();
return 0;
2022-12-03 22:27:49 +01:00
});
windowIterator++;
}
QSpacerItem* WINDOWS_SPACER = new QSpacerItem(0, 10000, QSizePolicy::Expanding, QSizePolicy::Expanding);
WINDOWS_SCROLL_AREA_CONTENTS_LAYOUT->addItem(WINDOWS_SPACER);
2022-12-03 22:27:49 +01:00
// lastly, region
const auto REGION_OBJECT = (QWidget*)TAB1->findChild<QWidget*>("region");
const auto REGION_LAYOUT = REGION_OBJECT->layout();
QString text = "Select region...";
2022-12-03 22:27:49 +01:00
ElidedButton* button = new ElidedButton(text);
button->setMaximumSize(400, BUTTON_HEIGHT);
REGION_LAYOUT->addWidget(button);
2023-02-03 19:41:28 +01:00
QObject::connect(button, &QPushButton::clicked, [=]() {
2022-12-03 22:27:49 +01:00
auto REGION = execAndGet("slurp -f \"%o %x %y %w %h\"");
2023-09-06 20:36:48 +02:00
REGION = REGION.substr(0, REGION.length());
2022-12-03 22:27:49 +01:00
// now, get the screen
QScreen* pScreen = nullptr;
if (REGION.find_first_of(' ') == std::string::npos) {
std::cout << "error1\n";
pickerPtr->quit();
return 1;
}
const auto SCREEN_NAME = REGION.substr(0, REGION.find_first_of(' '));
for (auto& screen : SCREENS) {
if (screen->name().toStdString() == SCREEN_NAME) {
pScreen = screen;
break;
}
}
if (!pScreen) {
std::cout << "error2\n";
pickerPtr->quit();
return 1;
}
// get all the coords
try {
2023-09-06 20:36:48 +02:00
REGION = REGION.substr(REGION.find_first_of(' ') + 1);
2022-12-03 22:27:49 +01:00
const auto X = std::stoi(REGION.substr(0, REGION.find_first_of(' ')));
2023-09-06 20:36:48 +02:00
REGION = REGION.substr(REGION.find_first_of(' ') + 1);
2022-12-03 22:27:49 +01:00
const auto Y = std::stoi(REGION.substr(0, REGION.find_first_of(' ')));
2023-09-06 20:36:48 +02:00
REGION = REGION.substr(REGION.find_first_of(' ') + 1);
2022-12-03 22:27:49 +01:00
const auto W = std::stoi(REGION.substr(0, REGION.find_first_of(' ')));
2023-09-06 20:36:48 +02:00
REGION = REGION.substr(REGION.find_first_of(' ') + 1);
2022-12-03 22:27:49 +01:00
const auto H = std::stoi(REGION);
std::cout << "[SELECTION]";
2023-09-06 20:36:48 +02:00
std::cout << (ALLOWTOKENBUTTON->isChecked() ? "r" : "");
std::cout << "/";
2022-12-03 22:27:49 +01:00
std::cout << "region:" << SCREEN_NAME << "@" << X - pScreen->geometry().x() << "," << Y - pScreen->geometry().y() << "," << W << "," << H << "\n";
settings->setValue("width", mainPickerPtr->width());
settings->setValue("height", mainPickerPtr->height());
settings->sync();
2022-12-03 22:27:49 +01:00
pickerPtr->quit();
return 0;
} catch (...) {
std::cout << "error3\n";
pickerPtr->quit();
return 1;
}
std::cout << "error4\n";
pickerPtr->quit();
return 1;
});
w.show();
return picker.exec();
}