File indexing completed on 2024-05-05 09:12:57

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