Internal
Public Access
Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
#include "rdp_display_widget.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
#include <QWheelEvent>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace {
|
||||
QSize sanitizeSize(const QSize& size)
|
||||
{
|
||||
return QSize(qMax(1, size.width()), qMax(1, size.height()));
|
||||
}
|
||||
}
|
||||
|
||||
RdpDisplayWidget::RdpDisplayWidget(QWidget* parent)
|
||||
: QWidget(parent), m_remoteSize(1280, 720)
|
||||
{
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMouseTracking(true);
|
||||
setAutoFillBackground(false);
|
||||
setMinimumSize(320, 200);
|
||||
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
const QSize size = sanitizeSize(this->size());
|
||||
emit viewportSizeChanged(size.width(), size.height());
|
||||
});
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::setFrame(const QImage& frame)
|
||||
{
|
||||
if (frame.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_frame = frame;
|
||||
m_remoteSize = sanitizeSize(frame.size());
|
||||
update();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::setRemoteDesktopSize(int width, int height)
|
||||
{
|
||||
if (width < 1 || height < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QSize nextSize(width, height);
|
||||
if (m_remoteSize == nextSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_remoteSize = nextSize;
|
||||
update();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::clearFrame()
|
||||
{
|
||||
m_frame = QImage();
|
||||
update();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect(), QColor(QStringLiteral("#101214")));
|
||||
|
||||
const QRectF target = renderRect();
|
||||
if (!m_frame.isNull()) {
|
||||
painter.drawImage(target, m_frame);
|
||||
} else {
|
||||
painter.setPen(QColor(QStringLiteral("#b0bec5")));
|
||||
painter.drawText(rect(),
|
||||
Qt::AlignCenter,
|
||||
QStringLiteral("Waiting for remote desktop frame..."));
|
||||
}
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
const QSize size = sanitizeSize(event->size());
|
||||
emit viewportSizeChanged(size.width(), size.height());
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if (event == nullptr || event->isAutoRepeat()) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit keyInput(event->key(),
|
||||
event->nativeScanCode(),
|
||||
event->text(),
|
||||
true,
|
||||
static_cast<int>(event->modifiers()));
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::keyReleaseEvent(QKeyEvent* event)
|
||||
{
|
||||
if (event == nullptr || event->isAutoRepeat()) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit keyInput(event->key(),
|
||||
event->nativeScanCode(),
|
||||
event->text(),
|
||||
false,
|
||||
static_cast<int>(event->modifiers()));
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
const QPoint mapped = mapToRemote(event->position());
|
||||
emit mouseButtonInput(mapped.x(), mapped.y(), static_cast<int>(event->button()), true);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint mapped = mapToRemote(event->position());
|
||||
emit mouseButtonInput(mapped.x(), mapped.y(), static_cast<int>(event->button()), false);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint mapped = mapToRemote(event->position());
|
||||
emit mouseMoveInput(mapped.x(), mapped.y());
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RdpDisplayWidget::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint mapped = mapToRemote(event->position());
|
||||
const QPoint angle = event->angleDelta();
|
||||
emit mouseWheelInput(mapped.x(), mapped.y(), angle.x(), angle.y());
|
||||
event->accept();
|
||||
}
|
||||
|
||||
QRectF RdpDisplayWidget::renderRect() const
|
||||
{
|
||||
const QSize remote = effectiveRemoteSize();
|
||||
const QRectF area = rect();
|
||||
if (area.isEmpty()) {
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
const qreal scale = qMin(area.width() / remote.width(), area.height() / remote.height());
|
||||
const qreal drawWidth = remote.width() * scale;
|
||||
const qreal drawHeight = remote.height() * scale;
|
||||
const qreal x = area.x() + ((area.width() - drawWidth) * 0.5);
|
||||
const qreal y = area.y() + ((area.height() - drawHeight) * 0.5);
|
||||
return QRectF(x, y, drawWidth, drawHeight);
|
||||
}
|
||||
|
||||
QPoint RdpDisplayWidget::mapToRemote(const QPointF& pos) const
|
||||
{
|
||||
const QSize remote = effectiveRemoteSize();
|
||||
const QRectF target = renderRect();
|
||||
if (target.isEmpty()) {
|
||||
return QPoint(0, 0);
|
||||
}
|
||||
|
||||
const qreal clampedX = qBound(target.left(), pos.x(), target.right());
|
||||
const qreal clampedY = qBound(target.top(), pos.y(), target.bottom());
|
||||
|
||||
const qreal normalizedX = (clampedX - target.left()) / qMax(1.0, target.width());
|
||||
const qreal normalizedY = (clampedY - target.top()) / qMax(1.0, target.height());
|
||||
|
||||
const int remoteX = qBound(0, static_cast<int>(normalizedX * remote.width()), remote.width() - 1);
|
||||
const int remoteY = qBound(0, static_cast<int>(normalizedY * remote.height()), remote.height() - 1);
|
||||
return QPoint(remoteX, remoteY);
|
||||
}
|
||||
|
||||
QSize RdpDisplayWidget::effectiveRemoteSize() const
|
||||
{
|
||||
if (m_remoteSize.width() > 0 && m_remoteSize.height() > 0) {
|
||||
return m_remoteSize;
|
||||
}
|
||||
if (!m_frame.isNull()) {
|
||||
return sanitizeSize(m_frame.size());
|
||||
}
|
||||
return QSize(1280, 720);
|
||||
}
|
||||
Reference in New Issue
Block a user