improved chatterino native
This commit is contained in:
@@ -20,12 +20,6 @@
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
using namespace chatterino::singletons;
|
||||
|
||||
namespace chatterino {
|
||||
@@ -234,52 +228,6 @@ void Application::save()
|
||||
this->commands->save();
|
||||
}
|
||||
|
||||
void Application::runNativeMessagingHost()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
app->nativeMessaging = new singletons::NativeMessagingManager;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
bool bigEndian = isBigEndian();
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
char size_c[4];
|
||||
std::cin.read(size_c, 4);
|
||||
|
||||
if (std::cin.eof()) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t size = *reinterpret_cast<uint32_t *>(size_c);
|
||||
#if 0
|
||||
// To avoid breaking strict-aliasing rules and potentially inducing undefined behaviour, the following code can be run instead
|
||||
uint32_t size = 0;
|
||||
if (bigEndian) {
|
||||
size = size_c[3] | static_cast<uint32_t>(size_c[2]) << 8 |
|
||||
static_cast<uint32_t>(size_c[1]) << 16 | static_cast<uint32_t>(size_c[0]) << 24;
|
||||
} else {
|
||||
size = size_c[0] | static_cast<uint32_t>(size_c[1]) << 8 |
|
||||
static_cast<uint32_t>(size_c[2]) << 16 | static_cast<uint32_t>(size_c[3]) << 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *b = reinterpret_cast<char *>(malloc(size + 1));
|
||||
std::cin.read(b, size);
|
||||
*(b + size) = '\0';
|
||||
|
||||
app->nativeMessaging->sendToGuiProcess(QByteArray(b, static_cast<int32_t>(size)));
|
||||
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
|
||||
Application *getApp()
|
||||
{
|
||||
assert(staticApp != nullptr);
|
||||
|
||||
@@ -22,9 +22,8 @@ std::shared_ptr<Account> AccountModel::getItemFromRow(std::vector<QStandardItem
|
||||
void AccountModel::getRowFromItem(const std::shared_ptr<Account> &item,
|
||||
std::vector<QStandardItem *> &row)
|
||||
{
|
||||
row[0]->setData(item->toString(), Qt::DisplayRole);
|
||||
util::setStringItem(row[0], item->toString(), false);
|
||||
row[0]->setData(QFont("Segoe UI", 10), Qt::FontRole);
|
||||
// row[0]->setData(QColor(255, 255, 255), Qt::BackgroundRole);
|
||||
}
|
||||
|
||||
int AccountModel::beforeInsert(const std::shared_ptr<Account> &item,
|
||||
@@ -34,8 +33,6 @@ int AccountModel::beforeInsert(const std::shared_ptr<Account> &item,
|
||||
auto row = this->createRow();
|
||||
|
||||
util::setStringItem(row[0], item->getCategory(), false, false);
|
||||
// row[0]->setData(QColor(142, 36, 170), Qt::ForegroundRole);
|
||||
// row[0]->setData(QColor(255, 255, 255), Qt::BackgroundRole);
|
||||
row[0]->setData(QFont("Segoe UI Light", 16), Qt::FontRole);
|
||||
|
||||
this->insertCustomRow(std::move(row), proposedIndex);
|
||||
|
||||
+50
-5
@@ -18,7 +18,14 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
int runGui(int argc, char *argv[]);
|
||||
void runNativeMessagingHost();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -31,11 +38,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// TODO: can be any argument
|
||||
if (args.size() > 0 && args[0].startsWith("chrome-extension://")) {
|
||||
chatterino::Application::instantiate(argc, argv);
|
||||
auto app = chatterino::getApp();
|
||||
app->construct();
|
||||
|
||||
chatterino::Application::runNativeMessagingHost();
|
||||
runNativeMessagingHost();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -132,3 +135,45 @@ int runGui(int argc, char *argv[])
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void runNativeMessagingHost()
|
||||
{
|
||||
auto *nm = new chatterino::singletons::NativeMessagingManager;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
bool bigEndian = isBigEndian();
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
char size_c[4];
|
||||
std::cin.read(size_c, 4);
|
||||
|
||||
if (std::cin.eof()) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t size = *reinterpret_cast<uint32_t *>(size_c);
|
||||
#if 0
|
||||
// To avoid breaking strict-aliasing rules and potentially inducing undefined behaviour, the following code can be run instead
|
||||
uint32_t size = 0;
|
||||
if (bigEndian) {
|
||||
size = size_c[3] | static_cast<uint32_t>(size_c[2]) << 8 |
|
||||
static_cast<uint32_t>(size_c[1]) << 16 | static_cast<uint32_t>(size_c[0]) << 24;
|
||||
} else {
|
||||
size = size_c[0] | static_cast<uint32_t>(size_c[1]) << 8 |
|
||||
static_cast<uint32_t>(size_c[2]) << 16 | static_cast<uint32_t>(size_c[3]) << 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<char[]> b(new char[size + 1]);
|
||||
std::cin.read(b.get(), size);
|
||||
*(b.get() + size) = '\0';
|
||||
|
||||
nm->sendToGuiProcess(QByteArray::fromRawData(b.get(), static_cast<int32_t>(size)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ void NativeMessagingManager::registerHost()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
if (app->paths->isPortable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create manifest
|
||||
QJsonDocument document;
|
||||
QJsonObject root_obj;
|
||||
@@ -144,26 +148,33 @@ void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &ro
|
||||
QString _type = root.value("type").toString();
|
||||
bool attach = root.value("attach").toBool();
|
||||
QString name = root.value("name").toString();
|
||||
QString winId = root.value("winId").toString();
|
||||
int yOffset = root.value("yOffset").toInt(-1);
|
||||
|
||||
if (_type.isNull() || name.isNull() || winId.isNull()) {
|
||||
widgets::AttachedWindow::GetArgs args;
|
||||
args.winId = root.value("winId").toString();
|
||||
args.yOffset = root.value("yOffset").toInt(-1);
|
||||
args.width = root.value("size").toObject().value("width").toInt(-1);
|
||||
args.height = root.value("size").toObject().value("height").toInt(-1);
|
||||
|
||||
if (_type.isNull() || args.winId.isNull()) {
|
||||
qDebug() << "NM type, name or winId missing";
|
||||
attach = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_type == "twitch") {
|
||||
util::postToThread([name, attach, winId, yOffset, app] {
|
||||
app->twitch.server->watchingChannel.update(
|
||||
app->twitch.server->getOrAddChannel(name));
|
||||
util::postToThread([=] {
|
||||
if (!name.isEmpty()) {
|
||||
app->twitch.server->watchingChannel.update(
|
||||
app->twitch.server->getOrAddChannel(name));
|
||||
}
|
||||
|
||||
if (attach) {
|
||||
#ifdef USEWINSDK
|
||||
auto *window =
|
||||
widgets::AttachedWindow::get(::GetForegroundWindow(), winId, yOffset);
|
||||
window->setChannel(app->twitch.server->getOrAddChannel(name));
|
||||
window->show();
|
||||
auto *window = widgets::AttachedWindow::get(::GetForegroundWindow(), args);
|
||||
if (!name.isEmpty()) {
|
||||
window->setChannel(app->twitch.server->getOrAddChannel(name));
|
||||
}
|
||||
// window->show();
|
||||
#endif
|
||||
}
|
||||
});
|
||||
@@ -185,7 +196,7 @@ void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &ro
|
||||
} else {
|
||||
qDebug() << "NM unknown action " + action;
|
||||
}
|
||||
}
|
||||
} // namespace singletons
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -19,21 +19,21 @@ PathManager::PathManager(int argc, char **argv)
|
||||
.replace("/", "x");
|
||||
|
||||
// Options
|
||||
bool portable = false;
|
||||
this->portable = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "portable") == 0) {
|
||||
portable = true;
|
||||
this->portable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/portable")) {
|
||||
portable = true;
|
||||
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/this->portable")) {
|
||||
this->portable = true;
|
||||
}
|
||||
|
||||
// Root path = %APPDATA%/Chatterino or the folder that the executable resides in
|
||||
QString rootPath;
|
||||
if (portable) {
|
||||
if (this->portable) {
|
||||
rootPath.append(QCoreApplication::applicationDirPath());
|
||||
} else {
|
||||
// Get settings path
|
||||
@@ -91,5 +91,10 @@ bool PathManager::createFolder(const QString &folderPath)
|
||||
return QDir().mkpath(folderPath);
|
||||
}
|
||||
|
||||
bool PathManager::isPortable()
|
||||
{
|
||||
return this->portable;
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -28,6 +28,10 @@ public:
|
||||
QString appPathHash;
|
||||
|
||||
bool createFolder(const QString &folderPath);
|
||||
bool isPortable();
|
||||
|
||||
private:
|
||||
bool portable;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#include "Windows.h"
|
||||
|
||||
#include "Psapi.h"
|
||||
#pragma comment(lib, "Dwmapi.lib")
|
||||
#endif
|
||||
|
||||
@@ -40,16 +42,47 @@ AttachedWindow::~AttachedWindow()
|
||||
}
|
||||
}
|
||||
|
||||
AttachedWindow *AttachedWindow::get(void *target, const QString &winId, int yOffset)
|
||||
AttachedWindow *AttachedWindow::get(void *target, const GetArgs &args)
|
||||
{
|
||||
for (Item &item : items) {
|
||||
if (item.hwnd == target) {
|
||||
return item.window;
|
||||
AttachedWindow *window = [&]() {
|
||||
for (Item &item : items) {
|
||||
if (item.hwnd == target) {
|
||||
return item.window;
|
||||
}
|
||||
}
|
||||
|
||||
auto *window = new AttachedWindow(target, args.yOffset);
|
||||
items.push_back(Item{target, window, args.winId});
|
||||
return window;
|
||||
}();
|
||||
|
||||
bool show = true;
|
||||
QSize size = window->size();
|
||||
|
||||
if (args.height != -1) {
|
||||
if (args.height == 0) {
|
||||
window->hide();
|
||||
show = false;
|
||||
} else {
|
||||
window->_height = args.height;
|
||||
size.setHeight(args.height);
|
||||
}
|
||||
}
|
||||
if (args.width != -1) {
|
||||
if (args.width == 0) {
|
||||
window->hide();
|
||||
show = false;
|
||||
} else {
|
||||
window->_width = args.width;
|
||||
size.setWidth(args.width);
|
||||
}
|
||||
}
|
||||
|
||||
auto *window = new AttachedWindow(target, yOffset);
|
||||
items.push_back(Item{target, window, winId});
|
||||
if (show) {
|
||||
window->show();
|
||||
window->resize(size);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -80,26 +113,58 @@ void AttachedWindow::attachToHwnd(void *_hwnd)
|
||||
|
||||
HWND hwnd = HWND(this->winId());
|
||||
HWND attached = HWND(_hwnd);
|
||||
|
||||
QObject::connect(timer, &QTimer::timeout, [this, hwnd, attached, timer] {
|
||||
|
||||
// check process id
|
||||
DWORD processId;
|
||||
::GetWindowThreadProcessId(attached, &processId);
|
||||
|
||||
HANDLE process =
|
||||
::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId);
|
||||
|
||||
std::unique_ptr<TCHAR[]> filename(new TCHAR[512]);
|
||||
DWORD filenameLength = ::GetModuleFileNameEx(process, nullptr, filename.get(), 512);
|
||||
QString qfilename = QString::fromWCharArray(filename.get(), filenameLength);
|
||||
|
||||
if (!qfilename.endsWith("chrome.exe")) {
|
||||
qDebug() << "NM Illegal callee" << qfilename;
|
||||
timer->stop();
|
||||
timer->deleteLater();
|
||||
this->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// We get the window rect first so we can close this window when it returns an error.
|
||||
// If we query the process first and check the filename then it will return and empty string
|
||||
// that doens't match.
|
||||
::SetLastError(0);
|
||||
RECT xD;
|
||||
::GetWindowRect(attached, &xD);
|
||||
RECT rect;
|
||||
::GetWindowRect(attached, &rect);
|
||||
|
||||
if (::GetLastError() != 0) {
|
||||
timer->stop();
|
||||
timer->deleteLater();
|
||||
this->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// set the correct z-order
|
||||
HWND next = ::GetNextWindow(attached, GW_HWNDPREV);
|
||||
|
||||
::SetWindowPos(hwnd, next ? next : HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
::MoveWindow(hwnd, xD.right - 360, xD.top + this->yOffset - 8, 360 - 8,
|
||||
xD.bottom - xD.top - this->yOffset, false);
|
||||
// ::MoveWindow(hwnd, xD.right - 360, xD.top + 82, 360 - 8, xD.bottom - xD.top - 82 -
|
||||
// 8,
|
||||
// false);
|
||||
|
||||
if (this->_height == -1) {
|
||||
::MoveWindow(hwnd, rect.right - this->_width - 8, rect.top + this->yOffset - 8,
|
||||
this->_width, rect.bottom - rect.top - this->yOffset, false);
|
||||
} else {
|
||||
::MoveWindow(hwnd, rect.right - this->_width - 8, rect.bottom - this->_height - 8,
|
||||
this->_width, this->_height, false);
|
||||
}
|
||||
|
||||
// ::MoveWindow(hwnd, rect.right - 360, rect.top + 82, 360 - 8, rect.bottom -
|
||||
// rect.top - 82 - 8, false);
|
||||
});
|
||||
timer->start();
|
||||
#endif
|
||||
|
||||
@@ -13,9 +13,16 @@ class AttachedWindow : public QWidget
|
||||
AttachedWindow(void *target, int asdf);
|
||||
|
||||
public:
|
||||
struct GetArgs {
|
||||
QString winId;
|
||||
int yOffset = -1;
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
};
|
||||
|
||||
~AttachedWindow();
|
||||
|
||||
static AttachedWindow *get(void *target, const QString &winId, int yOffset);
|
||||
static AttachedWindow *get(void *target, const GetArgs &args);
|
||||
static void detach(const QString &winId);
|
||||
|
||||
void setChannel(ChannelPtr channel);
|
||||
@@ -28,6 +35,9 @@ protected:
|
||||
private:
|
||||
void *target;
|
||||
int yOffset;
|
||||
int currentYOffset;
|
||||
int _width = 360;
|
||||
int _height = -1;
|
||||
|
||||
struct {
|
||||
Split *split;
|
||||
|
||||
Reference in New Issue
Block a user