File indexing completed on 2024-04-21 04:58:35

0001 /*
0002     SPDX-FileCopyrightText: 2002 Arend van Beelen jr. <arend@auton.nl>
0003     SPDX-FileCopyrightText: 2007-2012 Urs Wolfer <uwolfer@kde.org>
0004     SPDX-FileCopyrightText: 2012 AceLan Kao <acelan@acelan.idv.tw>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "rdpview.h"
0010 
0011 #include "krdc_debug.h"
0012 #include "rdphostpreferences.h"
0013 
0014 #include <KMessageBox>
0015 #include <KPasswordDialog>
0016 #include <KShell>
0017 #include <KWindowSystem>
0018 
0019 #include <QDir>
0020 #include <QEvent>
0021 #include <QInputDialog>
0022 #include <QKeyEvent>
0023 #include <QMouseEvent>
0024 #include <QPainter>
0025 #include <QScreen>
0026 #include <QWindow>
0027 
0028 #include "rdpsession.h"
0029 
0030 RdpView::RdpView(QWidget *parent, const QUrl &url, KConfigGroup configGroup, const QString &user, const QString &password)
0031     : RemoteView(parent)
0032     , m_user(user)
0033     , m_password(password)
0034 {
0035     m_url = url;
0036     m_host = url.host();
0037     m_port = url.port();
0038 
0039     if (m_user.isEmpty() && !m_url.userName().isEmpty()) {
0040         m_user = m_url.userName();
0041     }
0042 
0043     if (m_password.isEmpty() && !m_url.password().isEmpty()) {
0044         m_password = m_url.password();
0045     }
0046 
0047     if (m_port <= 0) {
0048         m_port = TCP_PORT_RDP;
0049     }
0050 
0051     setMouseTracking(true);
0052 
0053     m_hostPreferences = std::make_unique<RdpHostPreferences>(configGroup);
0054 }
0055 
0056 RdpView::~RdpView()
0057 {
0058     startQuitting();
0059 }
0060 
0061 QSize RdpView::framebufferSize()
0062 {
0063     if (m_session) {
0064         return m_session->size();
0065     }
0066 
0067     return QSize{};
0068 }
0069 
0070 void RdpView::scaleResize(int w, int h)
0071 {
0072     RemoteView::scaleResize(w, h);
0073 
0074     // handle window resizes
0075     resize(sizeHint());
0076 }
0077 
0078 QSize RdpView::sizeHint() const
0079 {
0080     if (!m_session) {
0081         return QSize{};
0082     }
0083 
0084     // when parent is resized and scaling is enabled, resize the view, preserving aspect ratio
0085     if (m_hostPreferences->scaleToSize()) {
0086         return m_session->size().scaled(parentWidget()->size(), Qt::KeepAspectRatio);
0087     }
0088 
0089     return m_session->size();
0090 }
0091 
0092 void RdpView::startQuitting()
0093 {
0094     m_quitting = true;
0095     m_session->stop();
0096 }
0097 
0098 bool RdpView::isQuitting()
0099 {
0100     return m_quitting;
0101 }
0102 
0103 bool RdpView::start()
0104 {
0105     m_session = std::make_unique<RdpSession>(this);
0106     m_session->setHostPreferences(m_hostPreferences.get());
0107     m_session->setHost(m_host);
0108     m_session->setPort(m_port);
0109     m_session->setUser(m_user);
0110     m_session->setSize(initialSize());
0111 
0112     if (m_password.isEmpty()) {
0113         m_session->setPassword(readWalletPassword());
0114     } else {
0115         m_session->setPassword(m_password);
0116     }
0117 
0118     connect(m_session.get(), &RdpSession::sizeChanged, this, [this]() {
0119         resize(sizeHint());
0120         qCDebug(KRDC) << "freerdp resized rdp view" << sizeHint();
0121         Q_EMIT framebufferSizeChanged(width(), height());
0122     });
0123     connect(m_session.get(), &RdpSession::rectangleUpdated, this, &RdpView::onRectangleUpdated);
0124     connect(m_session.get(), &RdpSession::stateChanged, this, [this]() {
0125         switch (m_session->state()) {
0126         case RdpSession::State::Starting:
0127             setStatus(Authenticating);
0128             break;
0129         case RdpSession::State::Connected:
0130             setStatus(Preparing);
0131             break;
0132         case RdpSession::State::Running:
0133             setStatus(Connected);
0134             break;
0135         case RdpSession::State::Closed:
0136             setStatus(Disconnected);
0137             break;
0138         default:
0139             break;
0140         }
0141     });
0142     connect(m_session.get(), &RdpSession::errorMessage, this, [this](const QString &title, const QString &message) {
0143         KMessageBox::error(this, message, title);
0144     });
0145 
0146     setStatus(RdpView::Connecting);
0147     if (!m_session->start()) {
0148         Q_EMIT disconnected();
0149         return false;
0150     }
0151 
0152     setFocus();
0153 
0154     return true;
0155 }
0156 
0157 HostPreferences *RdpView::hostPreferences()
0158 {
0159     return m_hostPreferences.get();
0160 }
0161 
0162 void RdpView::switchFullscreen(bool on)
0163 {
0164     if (on) {
0165         showFullScreen();
0166     } else {
0167         showNormal();
0168     }
0169 }
0170 
0171 QPixmap RdpView::takeScreenshot()
0172 {
0173     if (!m_session->videoBuffer()->isNull()) {
0174         return QPixmap::fromImage(*m_session->videoBuffer());
0175     }
0176     return QPixmap{};
0177 }
0178 
0179 bool RdpView::supportsScaling() const
0180 {
0181     return true;
0182 }
0183 
0184 bool RdpView::scaling() const
0185 {
0186     return m_hostPreferences->scaleToSize();
0187 }
0188 
0189 void RdpView::enableScaling(bool scale)
0190 {
0191     m_hostPreferences->setScaleToSize(scale);
0192     qCDebug(KRDC) << "Scaling changed" << scale;
0193     resize(sizeHint());
0194     update();
0195 }
0196 
0197 void RdpView::setScaleFactor(float factor)
0198 {
0199 }
0200 
0201 QSize RdpView::initialSize()
0202 {
0203     switch (m_hostPreferences->resolution()) {
0204     case RdpHostPreferences::Resolution::Small:
0205         return QSize{1280, 720};
0206     case RdpHostPreferences::Resolution::Medium:
0207         return QSize{1600, 900};
0208     case RdpHostPreferences::Resolution::Large:
0209         return QSize{1920, 1080};
0210     case RdpHostPreferences::Resolution::MatchWindow:
0211         return parentWidget()->size();
0212     case RdpHostPreferences::Resolution::MatchScreen:
0213         return window()->windowHandle()->screen()->size();
0214     case RdpHostPreferences::Resolution::Custom:
0215         return QSize{m_hostPreferences->width(), m_hostPreferences->height()};
0216     }
0217 
0218     return parentWidget()->size();
0219 }
0220 
0221 void RdpView::savePassword(const QString &password)
0222 {
0223     saveWalletPassword(password);
0224 }
0225 
0226 void RdpView::paintEvent(QPaintEvent *event)
0227 {
0228     if (m_session->videoBuffer()->isNull()) {
0229         return;
0230     }
0231 
0232     QPainter painter;
0233 
0234     painter.begin(this);
0235     painter.setClipRect(event->rect());
0236 
0237     auto image = *m_session->videoBuffer();
0238 
0239     if (m_hostPreferences->scaleToSize()) {
0240         painter.drawImage(QPoint{0, 0}, image.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
0241     } else {
0242         painter.drawImage(QPoint{0, 0}, image);
0243     }
0244     painter.end();
0245 }
0246 
0247 void RdpView::keyPressEvent(QKeyEvent *event)
0248 {
0249     m_session->sendEvent(event, this);
0250     event->accept();
0251 }
0252 
0253 void RdpView::keyReleaseEvent(QKeyEvent *event)
0254 {
0255     m_session->sendEvent(event, this);
0256     event->accept();
0257 }
0258 
0259 void RdpView::mousePressEvent(QMouseEvent *event)
0260 {
0261     if (!hasFocus()) {
0262         setFocus();
0263     }
0264 
0265     m_session->sendEvent(event, this);
0266     event->accept();
0267 }
0268 
0269 void RdpView::mouseDoubleClickEvent(QMouseEvent *event)
0270 {
0271     if (!hasFocus()) {
0272         setFocus();
0273     }
0274 
0275     m_session->sendEvent(event, this);
0276     event->accept();
0277 }
0278 
0279 void RdpView::mouseReleaseEvent(QMouseEvent *event)
0280 {
0281     m_session->sendEvent(event, this);
0282     event->accept();
0283 }
0284 
0285 void RdpView::mouseMoveEvent(QMouseEvent *event)
0286 {
0287     m_session->sendEvent(event, this);
0288     event->accept();
0289 }
0290 
0291 void RdpView::wheelEvent(QWheelEvent *event)
0292 {
0293     m_session->sendEvent(event, this);
0294     event->accept();
0295 }
0296 
0297 void RdpView::onRectangleUpdated(const QRect &rect)
0298 {
0299     m_pendingRectangle = rect;
0300     update();
0301 }