mirror-chatterino2/src/widgets/AttachedWindow.cpp

247 lines
6.2 KiB
C++
Raw Normal View History

2018-06-26 14:09:39 +02:00
#include "AttachedWindow.hpp"
2018-06-26 14:09:39 +02:00
#include "Application.hpp"
#include "util/DebugCount.hpp"
#include "widgets/splits/Split.hpp"
#include <QTimer>
#include <QVBoxLayout>
2018-04-26 20:58:32 +02:00
#ifdef USEWINSDK
2018-08-15 22:46:20 +02:00
# include "util/WindowsHelper.hpp"
2018-08-15 22:46:20 +02:00
# include "Windows.h"
2018-05-30 17:17:27 +02:00
// don't even think about reordering these
2018-08-15 22:46:20 +02:00
# include "Psapi.h"
# pragma comment(lib, "Dwmapi.lib")
2018-04-26 20:58:32 +02:00
#endif
namespace chatterino {
AttachedWindow::AttachedWindow(void *_target, int _yOffset)
2018-05-06 14:16:41 +02:00
: QWidget(nullptr, Qt::FramelessWindowHint | Qt::Window)
2018-05-30 17:17:27 +02:00
, target_(_target)
, yOffset_(_yOffset)
{
QLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
this->setLayout(layout);
auto *split = new Split(this);
2018-05-30 17:17:27 +02:00
this->ui_.split = split;
split->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
layout->addWidget(split);
2018-05-30 17:17:27 +02:00
2018-06-26 17:06:17 +02:00
DebugCount::increase("attached window");
}
AttachedWindow::~AttachedWindow()
{
2018-10-21 13:43:02 +02:00
for (auto it = items.begin(); it != items.end(); it++)
{
if (it->window == this)
{
items.erase(it);
break;
}
}
2018-05-30 17:17:27 +02:00
2018-06-26 17:06:17 +02:00
DebugCount::decrease("attached window");
}
2018-05-28 18:25:19 +02:00
AttachedWindow *AttachedWindow::get(void *target, const GetArgs &args)
{
2018-05-28 18:25:19 +02:00
AttachedWindow *window = [&]() {
2018-10-21 13:43:02 +02:00
for (Item &item : items)
{
if (item.hwnd == target)
{
2018-05-28 18:25:19 +02:00
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();
2018-10-21 13:43:02 +02:00
if (args.height != -1)
{
if (args.height == 0)
{
2018-05-28 18:25:19 +02:00
window->hide();
show = false;
2018-10-21 13:43:02 +02:00
}
else
{
2018-05-30 17:17:27 +02:00
window->height_ = args.height;
2018-05-28 18:25:19 +02:00
size.setHeight(args.height);
}
}
2018-10-21 13:43:02 +02:00
if (args.width != -1)
{
if (args.width == 0)
{
2018-05-28 18:25:19 +02:00
window->hide();
show = false;
2018-10-21 13:43:02 +02:00
}
else
{
2018-05-30 17:17:27 +02:00
window->width_ = args.width;
2018-05-28 18:25:19 +02:00
size.setWidth(args.width);
}
}
2018-10-21 13:43:02 +02:00
if (show)
{
2018-07-06 17:30:12 +02:00
window->updateWindowRect(window->target_);
2018-05-28 18:25:19 +02:00
window->show();
}
return window;
}
void AttachedWindow::detach(const QString &winId)
{
2018-10-21 13:43:02 +02:00
for (Item &item : items)
{
if (item.winId == winId)
{
item.window->deleteLater();
}
}
}
void AttachedWindow::setChannel(ChannelPtr channel)
{
2018-05-30 17:17:27 +02:00
this->ui_.split->setChannel(channel);
}
void AttachedWindow::showEvent(QShowEvent *)
{
2018-07-06 17:30:12 +02:00
this->attachToHwnd(this->target_);
}
2018-07-06 17:30:12 +02:00
void AttachedWindow::attachToHwnd(void *_attachedPtr)
{
2018-04-26 20:58:32 +02:00
#ifdef USEWINSDK
2018-10-21 13:43:02 +02:00
if (this->attached_)
{
2018-05-30 17:17:27 +02:00
return;
}
2018-05-30 17:17:27 +02:00
this->attached_ = true;
this->timer_.setInterval(1);
2018-05-28 18:25:19 +02:00
2018-05-30 17:17:27 +02:00
auto hwnd = HWND(this->winId());
auto attached = HWND(_attachedPtr);
2018-05-28 18:25:19 +02:00
2018-05-30 17:17:27 +02:00
QObject::connect(&this->timer_, &QTimer::timeout, [this, hwnd, attached] {
2018-05-28 18:25:19 +02:00
// check process id
2018-10-21 13:43:02 +02:00
if (!this->validProcessName_)
{
2018-05-30 17:17:27 +02:00
DWORD processId;
::GetWindowThreadProcessId(attached, &processId);
2018-08-06 21:17:03 +02:00
HANDLE process = ::OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId);
2018-05-30 17:17:27 +02:00
std::unique_ptr<TCHAR[]> filename(new TCHAR[512]);
2018-08-06 21:17:03 +02:00
DWORD filenameLength =
::GetModuleFileNameEx(process, nullptr, filename.get(), 512);
QString qfilename =
QString::fromWCharArray(filename.get(), filenameLength);
2018-05-30 17:17:27 +02:00
2018-08-06 21:17:03 +02:00
if (!qfilename.endsWith("chrome.exe") &&
2018-10-21 13:43:02 +02:00
!qfilename.endsWith("firefox.exe"))
{
2018-05-30 17:17:27 +02:00
qDebug() << "NM Illegal caller" << qfilename;
this->timer_.stop();
this->deleteLater();
return;
}
this->validProcessName_ = true;
2018-05-28 18:25:19 +02:00
}
2018-07-06 17:30:12 +02:00
this->updateWindowRect(attached);
2018-05-30 17:17:27 +02:00
});
this->timer_.start();
#endif
}
2018-07-06 17:30:12 +02:00
void AttachedWindow::updateWindowRect(void *_attachedPtr)
2018-05-30 17:17:27 +02:00
{
2018-05-30 18:30:26 +02:00
#ifdef USEWINSDK
2018-05-30 17:17:27 +02:00
auto hwnd = HWND(this->winId());
auto attached = HWND(_attachedPtr);
2018-08-06 21:17:03 +02:00
// 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.
2018-05-30 17:17:27 +02:00
::SetLastError(0);
RECT rect;
::GetWindowRect(attached, &rect);
2018-10-21 13:43:02 +02:00
if (::GetLastError() != 0)
{
2018-05-30 17:17:27 +02:00
qDebug() << "NM GetLastError()" << ::GetLastError();
this->timer_.stop();
this->deleteLater();
return;
}
2018-05-30 17:17:27 +02:00
// set the correct z-order
HWND next = ::GetNextWindow(attached, GW_HWNDPREV);
2018-05-28 18:25:19 +02:00
2018-05-30 17:17:27 +02:00
::SetWindowPos(hwnd, next ? next : HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2018-05-28 18:25:19 +02:00
float scale = 1.f;
2018-10-21 13:43:02 +02:00
if (auto dpi = getWindowDpi(attached))
{
scale = dpi.get() / 96.f;
// for (auto w : this->ui_.split->findChildren<BaseWidget *>()) {
// w->setOverrideScale(scale);
// }
// this->ui_.split->setOverrideScale(scale);
}
2018-10-21 13:43:02 +02:00
if (this->height_ == -1)
{
2018-08-06 21:17:03 +02:00
// ::MoveWindow(hwnd, rect.right - this->width_ - 8, rect.top +
// this->yOffset_ - 8,
// this->width_, rect.bottom - rect.top - this->yOffset_,
// false);
2018-10-21 13:43:02 +02:00
}
else
{
::MoveWindow(hwnd, //
int(rect.right - this->width_ * scale - 8), //
int(rect.bottom - this->height_ * scale - 8), //
2018-08-06 21:17:03 +02:00
int(this->width_ * scale), int(this->height_ * scale),
true);
2018-05-30 17:17:27 +02:00
}
2018-08-06 21:17:03 +02:00
// ::MoveWindow(hwnd, rect.right - 360, rect.top + 82, 360 - 8,
// rect.bottom - rect.top - 82 - 8, false);
2018-05-30 18:30:26 +02:00
#endif
}
2018-08-06 21:17:03 +02:00
// void AttachedWindow::nativeEvent(const QByteArray &eventType, void *message,
// long *result)
//{
// MSG *msg = reinterpret_cast
// case WM_NCCALCSIZE: {
// }
//}
std::vector<AttachedWindow::Item> AttachedWindow::items;
} // namespace chatterino