From 88f999171b34dccc76512e80c2b0de44e949ae4a Mon Sep 17 00:00:00 2001 From: uwolfer Date: Mon, 24 Mar 2008 12:30:29 +0000 Subject: [PATCH] Implement scaling of remote desktop for VNC protocol. Allows up- and downscaling with free ascpect ratio. There are sometimes small roundig errors, what results small artefacts (KDE 3 version had this issue too). Need to find a solution for this issue later, but this implementation is already usable without problems. This is still work in progress,; fixes for small problems will follow. BUG:151519 FEATURE:148214 FEATURE:151099 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/KDE/kdenetwork@789489 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- krdc/krdcui.rc | 2 ++ krdc/mainwindow.cpp | 37 +++++++++++++++++++++++-------- krdc/mainwindow.h | 21 ++++++++++++++++++ krdc/remoteview.cpp | 6 ++++-- krdc/remoteview.h | 3 ++- krdc/vnc/vncview.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++-------- krdc/vnc/vncview.h | 8 +++++++ 7 files changed, 117 insertions(+), 21 deletions(-) diff --git a/krdc/krdcui.rc b/krdc/krdcui.rc index 625bb1499..8553475e5 100644 --- a/krdc/krdcui.rc +++ b/krdc/krdcui.rc @@ -16,6 +16,7 @@ + @@ -38,6 +39,7 @@ + Address Toolbar diff --git a/krdc/mainwindow.cpp b/krdc/mainwindow.cpp index 3a1015b78..c2c13b142 100644 --- a/krdc/mainwindow.cpp +++ b/krdc/mainwindow.cpp @@ -172,7 +172,6 @@ void MainWindow::setupActions() zeroconfAction->setVisible(false); #endif - QAction *screenshotAction = actionCollection()->addAction("take_screenshot"); screenshotAction->setText(i18n("Copy Screenshot to Clipboard")); screenshotAction->setIcon(KIcon("ksnapshot")); @@ -206,6 +205,12 @@ void MainWindow::setupActions() grabAllKeysAction->setText(i18n("Grab all possible keys")); connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool))); + QAction *scaleAction = actionCollection()->addAction("scale"); + scaleAction->setCheckable(true); + scaleAction->setIcon(KIcon("zoom-fit-best")); + scaleAction->setText(i18n("Scale remote screen to fit window size")); + connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool))); + QAction *quitAction = KStandardAction::quit(this, SLOT(quit()), actionCollection()); actionCollection()->addAction("quit", quitAction); QAction *preferencesAction = KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); @@ -297,25 +302,23 @@ void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConn m_addressNavigator->setUrl(KUrl(url.scheme().toLower() + "://")); - QScrollArea *scrollArea = createScrollArea(m_tabWidget, 0); - RemoteView *view; #ifdef BUILD_VNC if (url.scheme().toLower() == "vnc") { - view = new VncView(scrollArea, url); + view = new VncView(this, url); } else #endif #ifdef BUILD_NX if (url.scheme().toLower() == "nx") { - view = new NxView(scrollArea, url); + view = new NxView(this, url); } else #endif #ifdef BUILD_RDP if (url.scheme().toLower() == "rdp") { - view = new RdpView(scrollArea, url); + view = new RdpView(this, url); } else #endif { @@ -338,7 +341,7 @@ void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConn if (m_zeroconfPage) numNonRemoteView++; - scrollArea->setWidget(m_remoteViewList.at(m_remoteViewList.count() - 1)); + QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_remoteViewList.count() - 1)); int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), url.prettyUrl(KUrl::RemoveTrailingSlash)); m_tabWidget->setCurrentIndex(newIndex); @@ -479,10 +482,10 @@ void MainWindow::switchFullscreen() if (m_toolBar) { m_toolBar->hideAndDestroy(); + m_toolBar->deleteLater(); m_toolBar = 0; } - actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen")); actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Fullscreen Mode")); @@ -518,9 +521,11 @@ void MainWindow::switchFullscreen() QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView) { - QScrollArea *scrollArea = new QScrollArea(parent); + RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent); scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + connect(scrollArea, SIGNAL(resized(int, int)), remoteView, SLOT(scaleResize(int, int))); + QPalette palette = scrollArea->palette(); palette.setColor(QPalette::Dark, Settings::backgroundColor()); scrollArea->setPalette(palette); @@ -569,6 +574,13 @@ void MainWindow::grabAllKeys(bool grabAllKeys) m_remoteViewList.at(m_currentRemoteView)->setGrabAllKeys(grabAllKeys); } +void MainWindow::scale(bool scale) +{ + kDebug(5010); + + m_remoteViewList.at(m_currentRemoteView)->enableScaling(scale); +} + void MainWindow::showRemoteViewToolbar() { kDebug(5010); @@ -610,6 +622,7 @@ void MainWindow::showRemoteViewToolbar() m_toolBar->addAction(actionCollection()->action("view_only")); m_toolBar->addAction(actionCollection()->action("show_local_cursor")); m_toolBar->addAction(actionCollection()->action("grab_all_keys")); + m_toolBar->addAction(actionCollection()->action("scale")); m_toolBar->addAction(actionCollection()->action("logout")); QAction *stickToolBarAction = new QAction(m_toolBar); @@ -642,6 +655,7 @@ void MainWindow::updateActionStatus() actionCollection()->action("take_screenshot")->setEnabled(enabled); actionCollection()->action("view_only")->setEnabled(enabled); actionCollection()->action("grab_all_keys")->setEnabled(enabled); + actionCollection()->action("scale")->setEnabled(enabled); actionCollection()->action("logout")->setEnabled(enabled); bool viewOnlyChecked = false; @@ -658,6 +672,11 @@ void MainWindow::updateActionStatus() if (m_currentRemoteView >= 0) showLocalCursorVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsLocalCursor(); actionCollection()->action("show_local_cursor")->setVisible(showLocalCursorVisible); + + bool scaleVisible = false; + if (m_currentRemoteView >= 0) + scaleVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsScaling(); + actionCollection()->action("scale")->setVisible(scaleVisible); } void MainWindow::preferences() diff --git a/krdc/mainwindow.h b/krdc/mainwindow.h index 4499e4f8b..29014c9cf 100644 --- a/krdc/mainwindow.h +++ b/krdc/mainwindow.h @@ -74,6 +74,7 @@ private slots: void viewOnly(bool viewOnly); void showLocalCursor(bool showLocalCursor); void grabAllKeys(bool grabAllKeys); + void scale(bool scale); void updateActionStatus(); void updateConfiguration(); void tabChanged(int index); @@ -137,4 +138,24 @@ protected: } }; +#include + +class RemoteViewScrollArea : public QScrollArea +{ + Q_OBJECT +public: + RemoteViewScrollArea(QWidget *parent) + : QScrollArea(parent) { + } + +signals: + void resized(int w, int h); + +protected: + void resizeEvent(QResizeEvent *event) { + QScrollArea::resizeEvent(event); + emit resized(width() - 2*frameWidth(), height() - 2*frameWidth()); + } +}; + #endif diff --git a/krdc/remoteview.cpp b/krdc/remoteview.cpp index 491b5b5da..171047fdc 100644 --- a/krdc/remoteview.cpp +++ b/krdc/remoteview.cpp @@ -38,6 +38,7 @@ RemoteView::RemoteView(QWidget *parent) m_port(0), m_viewOnly(false), m_grabAllKeys(false), + m_scale(false), m_keyboardIsGrabbed(false), #ifndef QTONLY m_wallet(0), @@ -161,11 +162,12 @@ RemoteView::DotCursorState RemoteView::dotCursorState() const bool RemoteView::scaling() const { - return false; + return m_scale; } -void RemoteView::enableScaling(bool) +void RemoteView::enableScaling(bool scale) { + m_scale = scale; } void RemoteView::switchFullscreen(bool) diff --git a/krdc/remoteview.h b/krdc/remoteview.h index 56e387108..040ec6a81 100644 --- a/krdc/remoteview.h +++ b/krdc/remoteview.h @@ -258,7 +258,7 @@ public slots: * @see supportsScaling() * @see scaling() */ - virtual void enableScaling(bool s); + virtual void enableScaling(bool scale); /** * Enables/disables the view-only mode. @@ -366,6 +366,7 @@ protected: int m_port; bool m_viewOnly; bool m_grabAllKeys; + bool m_scale; bool m_keyboardIsGrabbed; KUrl m_url; diff --git a/krdc/vnc/vncview.cpp b/krdc/vnc/vncview.cpp index b41eaf217..7a4197f99 100644 --- a/krdc/vnc/vncview.cpp +++ b/krdc/vnc/vncview.cpp @@ -46,7 +46,9 @@ VncView::VncView(QWidget *parent, const KUrl &url) m_repaint(false), m_quitFlag(false), m_firstPasswordTry(true), - m_dontSendClipboard(false) + m_dontSendClipboard(false), + m_horizontalFactor(1.0), + m_verticalFactor(1.0) { m_url = url; m_host = url.host(); @@ -98,6 +100,13 @@ QSize VncView::minimumSizeHint() const return size(); } +void VncView::scaleResize(int w, int h) +{ + kDebug(5011) << w << h; + if (m_scale) + resize(w, h); +} + void VncView::startQuitting() { kDebug(5011) << "about to quit"; @@ -142,6 +151,11 @@ bool VncView::start() return true; } +bool VncView::supportsScaling() const +{ + return true; +} + bool VncView::supportsLocalCursor() const { return true; @@ -216,7 +230,7 @@ void VncView::updateImage(int x, int y, int w, int h) setMouseTracking(true); // get mouse events even when there is no mousebutton pressed setFocusPolicy(Qt::WheelFocus); - setFixedSize(m_frame.width(), m_frame.height()); + resize(m_frame.width(), m_frame.height()); setStatus(Connected); emit changeSize(m_frame.width(), m_frame.height()); emit connected(); @@ -230,29 +244,43 @@ void VncView::updateImage(int x, int y, int w, int h) } if ((y == 0 && x == 0) && (m_frame.size() != size())) { - setFixedSize(m_frame.width(), m_frame.height()); + resize(m_frame.width(), m_frame.height()); emit changeSize(m_frame.width(), m_frame.height()); } m_repaint = true; - repaint(x, y, w, h); + repaint(qRound(x * m_horizontalFactor), qRound(y * m_verticalFactor), qRound(w * m_horizontalFactor), qRound(h * m_verticalFactor)); m_repaint = false; } void VncView::setViewOnly(bool viewOnly) { + RemoteView::setViewOnly(viewOnly); + if (viewOnly) setCursor(Qt::ArrowCursor); else setCursor(m_dotCursorState == CursorOn ? localDotCursor() : Qt::BlankCursor); - - m_viewOnly = viewOnly; } void VncView::showDotCursor(DotCursorState state) { + RemoteView::showDotCursor(state); + setCursor(state == CursorOn ? localDotCursor() : Qt::BlankCursor); - m_dotCursorState = state; +} + +void VncView::enableScaling(bool scale) +{ + RemoteView::enableScaling(scale); + + if (scale) { + if (parentWidget()) + resize(parentWidget()->width(), parentWidget()->height()); + } else { + resize(m_frame.width(), m_frame.height()); + emit changeSize(m_frame.width(), m_frame.height()); + } } void VncView::setCut(const QString &text) @@ -273,15 +301,30 @@ void VncView::paintEvent(QPaintEvent *event) if (m_repaint) { // kDebug(5011) << "normal repaint"; - painter.drawImage(QRect(m_x, m_y, m_w, m_h), m_frame.copy(m_x, m_y, m_w, m_h)); + painter.drawImage(QRect(qRound(m_x*m_horizontalFactor), qRound(m_y*m_verticalFactor), + qRound(m_w*m_horizontalFactor), qRound(m_h*m_verticalFactor)), + m_frame.copy(m_x, m_y, m_w, m_h).scaled(qRound(m_w*m_horizontalFactor), + qRound(m_h*m_verticalFactor), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } else { // kDebug(5011) << "resize repaint"; - painter.drawImage(m_frame.rect(), m_frame); + painter.drawImage(QRect(0, 0, width(), height()), m_frame.scaled(width(), height(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } RemoteView::paintEvent(event); } +void VncView::resizeEvent(QResizeEvent *event) +{ + RemoteView::resizeEvent(event); + + m_verticalFactor = (qreal) height() / m_frame.height(); + m_horizontalFactor = (qreal) width() / m_frame.width(); + + update(); +} + void VncView::focusOutEvent(QFocusEvent *event) { // kDebug(5011) << "focusOutEvent"; diff --git a/krdc/vnc/vncview.h b/krdc/vnc/vncview.h index b484a685a..917dff619 100644 --- a/krdc/vnc/vncview.h +++ b/krdc/vnc/vncview.h @@ -51,13 +51,19 @@ public: void startQuitting(); bool isQuitting(); bool start(); + bool supportsScaling() const; bool supportsLocalCursor() const; void keyEvent(QKeyEvent *e); void setViewOnly(bool viewOnly); void showDotCursor(DotCursorState state); + void enableScaling(bool scale); + +public slots: + void scaleResize(int w, int h); protected: void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); void focusOutEvent(QFocusEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); @@ -78,6 +84,8 @@ private: bool m_quitFlag; bool m_firstPasswordTry; bool m_dontSendClipboard; + qreal m_horizontalFactor; + qreal m_verticalFactor; #ifndef QTONLY VncHostPreferences *m_hostPreferences; #endif -- 2.11.4.GIT