diff --git a/krfb/CMakeLists.txt b/krfb/CMakeLists.txt index 665c1a1..96d50f6 100644 --- a/krfb/CMakeLists.txt +++ b/krfb/CMakeLists.txt @@ -1,121 +1,122 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config-krfb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-krfb.h ) include(GenerateExportHeader) ##################################### # First target: libkrfbprivate - a library # for linking plugins against. set (krfbprivate_SRCS framebuffer.cpp framebufferplugin.cpp ) add_library (krfbprivate SHARED ${krfbprivate_SRCS} ) generate_export_header(krfbprivate BASE_NAME krfbprivate) target_link_libraries (krfbprivate Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${LIBVNCSERVER_LIBRARIES} ) set_target_properties (krfbprivate PROPERTIES VERSION 5 SOVERSION 5.0 ) install (TARGETS krfbprivate ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP ) install (FILES krfb-framebuffer.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) ##################################### # Second target: krfb - the app # itself. set (krfb_SRCS connectiondialog.cpp events.cpp framebuffermanager.cpp main.cpp mainwindow.cpp sockethelpers.cpp trayicon.cpp rfbservermanager.cpp rfbserver.cpp rfbclient.cpp invitationsrfbserver.cpp invitationsrfbclient.cpp ) kconfig_add_kcfg_files (krfb_SRCS krfbconfig.kcfgc ) ki18n_wrap_ui (krfb_SRCS ui/configtcp.ui ui/configsecurity.ui + ui/configframebuffer.ui ui/connectionwidget.ui ui/mainwidget.ui ) add_executable (krfb ${krfb_SRCS} ) target_link_libraries (krfb krfbprivate ${JPEG_LIBRARIES} ${X11_Xext_LIB} ${X11_X11_LIB} ${X11_Xdamage_LIB} Qt5::Network KF5::Completion KF5::CoreAddons KF5::DBusAddons KF5::DNSSD KF5::I18n KF5::Notifications KF5::Wallet KF5::WidgetsAddons KF5::XmlGui ${LIBVNCSERVER_LIBRARIES} ) if (X11_XTest_FOUND) target_link_libraries (krfb ${X11_XTest_LIB} ) endif (X11_XTest_FOUND) install (TARGETS krfb ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### install files ############### install (PROGRAMS org.kde.krfb.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install(FILES org.kde.krfb.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) install (FILES krfb.notifyrc DESTINATION ${DATA_INSTALL_DIR}/krfb ) diff --git a/krfb/framebuffermanager.cpp b/krfb/framebuffermanager.cpp index b57799a..1a36d8b 100644 --- a/krfb/framebuffermanager.cpp +++ b/krfb/framebuffermanager.cpp @@ -1,141 +1,141 @@ /* This file is part of the KDE project Copyright (C) 2009 Collabora Ltd @author George Goldberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "framebuffermanager.h" #include "framebufferplugin.h" #include "krfbconfig.h" #include #include #include #include #include #include class FrameBufferManagerStatic { public: FrameBufferManager instance; }; Q_GLOBAL_STATIC(FrameBufferManagerStatic, frameBufferManagerStatic) FrameBufferManager::FrameBufferManager() { //qDebug(); loadPlugins(); } FrameBufferManager::~FrameBufferManager() { //qDebug(); } FrameBufferManager *FrameBufferManager::instance() { //qDebug(); return &frameBufferManagerStatic->instance; } void FrameBufferManager::loadPlugins() { //qDebug(); const QVector plugins = KPluginLoader::findPlugins(QStringLiteral("krfb"), [](const KPluginMetaData & md) { return md.serviceTypes().contains(QStringLiteral("krfb/framebuffer")); }); QVectorIterator i(plugins); i.toBack(); QSet unique; while (i.hasPrevious()) { - KPluginMetaData data = i.previous(); + const KPluginMetaData &data = i.previous(); // only load plugins once, even if found multiple times! if (unique.contains(data.name())) continue; - KPluginFactory *factory = KPluginLoader(data.fileName()).factory(); - - if (!factory) { - qDebug() << "KPluginFactory could not load the plugin:" << data.fileName(); - } else { - qDebug() << "found plugin at " << data.fileName(); - } - - FrameBufferPlugin *plugin = factory->create(this); - if (plugin) { - m_plugins.insert(data.pluginId(), plugin); - qDebug() << "Loaded plugin with name " << data.pluginId(); - } else { - qDebug() << "unable to load pluign for " << data.fileName(); - } + KPluginFactory *factory = KPluginLoader(data.fileName()).factory(); + + if (!factory) { + qDebug() << "KPluginFactory could not load the plugin:" << data.fileName(); + } else { + qDebug() << "found plugin at " << data.fileName(); + } + + FrameBufferPlugin *plugin = factory->create(this); + if (plugin) { + m_plugins.insert(data.pluginId(), plugin); + qDebug() << "Loaded plugin with name " << data.pluginId(); + } else { + qDebug() << "unable to load pluign for " << data.fileName(); + } unique.insert (data.name()); } } QSharedPointer FrameBufferManager::frameBuffer(WId id) { //qDebug(); // See if there is still an existing framebuffer to this WId. if (m_frameBuffers.contains(id)) { QWeakPointer weakFrameBuffer = m_frameBuffers.value(id); if (weakFrameBuffer) { //qDebug() << "Found cached frame buffer."; return weakFrameBuffer.toStrongRef(); } else { //qDebug() << "Found deleted cached frame buffer. Don't use."; m_frameBuffers.remove(id); } } // We don't already have that frame buffer. QMap::const_iterator iter = m_plugins.constBegin(); while (iter != m_plugins.constEnd()) { if (iter.key() == KrfbConfig::preferredFrameBufferPlugin()) { qDebug() << "Using FrameBuffer:" << KrfbConfig::preferredFrameBufferPlugin(); QSharedPointer frameBuffer(iter.value()->frameBuffer(id)); if (frameBuffer) { m_frameBuffers.insert(id, frameBuffer.toWeakRef()); return frameBuffer; } } ++iter; } // No valid framebuffer plugin found. qDebug() << "No valid framebuffer found. returning null."; return QSharedPointer(); } #include "framebuffermanager.moc" diff --git a/krfb/main.cpp b/krfb/main.cpp index fb860f5..fd327d6 100644 --- a/krfb/main.cpp +++ b/krfb/main.cpp @@ -1,133 +1,151 @@ /*************************************************************************** main.cpp ------------------- begin : Sat Dec 8 03:23:02 CET 2001 copyright : (C) 2001-2003 by Tim Jansen email : tim@tjansen.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "mainwindow.h" #include "trayicon.h" #include "invitationsrfbserver.h" #include "krfbconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include static const char KRFB_VERSION[] = "5.0"; static const char description[] = I18N_NOOP("VNC-compatible server to share " "desktops"); static bool checkX11Capabilities() { int bp1, bp2, majorv, minorv; Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2, &majorv, &minorv); if ((!r) || (((majorv * 1000) + minorv) < 2002)) { KMessageBox::error(0, i18n("Your X11 Server does not support the required XTest extension " "version 2.2. Sharing your desktop is not possible."), i18n("Desktop Sharing Error")); return false; } return true; } + +static void checkOldX11PluginConfig() { + if (KrfbConfig::preferredFrameBufferPlugin() == QStringLiteral("x11")) { + qDebug() << "Detected deprecated configuration: preferredFrameBufferPlugin = x11"; + KConfigSkeletonItem *config_item = KrfbConfig::self()->findItem( + QStringLiteral("preferredFrameBufferPlugin")); + if (config_item) { + config_item->setProperty(QStringLiteral("xcb")); + KrfbConfig::self()->save(); + qDebug() << " Fixed preferredFrameBufferPlugin from x11 to xcb."; + } + } +} + + int main(int argc, char *argv[]) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain("krfb"); KAboutData aboutData("krfb", i18n("Desktop Sharing"), KRFB_VERSION, i18n(description), KAboutLicense::GPL, i18n("(c) 2009-2010, Collabora Ltd.\n" "(c) 2007, Alessandro Praduroux\n" "(c) 2001-2003, Tim Jansen\n" "(c) 2001, Johannes E. Schindelin\n" "(c) 2000-2001, Const Kaplinsky\n" "(c) 2000, Tridia Corporation\n" "(c) 1999, AT&T Laboratories Boston\n")); aboutData.addAuthor(i18n("George Goldberg"), i18n("Telepathy tubes support"), "george.goldberg@collabora.co.uk"); aboutData.addAuthor(i18n("George Kiagiadakis"), QString(), "george.kiagiadakis@collabora.co.uk"); aboutData.addAuthor(i18n("Alessandro Praduroux"), i18n("KDE4 porting"), "pradu@pradu.it"); aboutData.addAuthor(i18n("Tim Jansen"), i18n("Original author"), "tim@tjansen.de"); aboutData.addCredit(i18n("Johannes E. Schindelin"), i18n("libvncserver")); aboutData.addCredit(i18n("Const Kaplinsky"), i18n("TightVNC encoder")); aboutData.addCredit(i18n("Tridia Corporation"), i18n("ZLib encoder")); aboutData.addCredit(i18n("AT&T Laboratories Boston"), i18n("original VNC encoders and " "protocol design")); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); parser.addVersionOption(); parser.addHelpOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); KDBusService service(KDBusService::Unique, &app); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("nodialog"), i18n("Do not show the invitations management dialog at startup"))); app.setQuitOnLastWindowClosed(false); if (!checkX11Capabilities()) { return 1; } + // upgrade the configuration + checkOldX11PluginConfig(); + //init the core InvitationsRfbServer::init(); //init the GUI MainWindow mainWindow; TrayIcon trayicon(&mainWindow); if (KrfbConfig::startMinimized()) { mainWindow.hide(); } else if (app.isSessionRestored() && KMainWindow::canBeRestored(1)) { mainWindow.restore(1, false); } else if (!parser.isSet("nodialog")) { mainWindow.show(); } sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGPIPE); sigprocmask(SIG_BLOCK, &sigs, 0); return app.exec(); } diff --git a/krfb/mainwindow.cpp b/krfb/mainwindow.cpp index 197719b..b88cd93 100644 --- a/krfb/mainwindow.cpp +++ b/krfb/mainwindow.cpp @@ -1,210 +1,266 @@ /* This file is part of the KDE project Copyright (C) 2007 Alessandro Praduroux Copyright (C) 2013 Amandeep Singh This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "mainwindow.h" #include "invitationsrfbserver.h" #include "krfbconfig.h" #include "ui_configtcp.h" #include "ui_configsecurity.h" +#include "ui_configframebuffer.h" #include #include #include #include #include #include #include +#include +#include #include #include +#include +#include #include +#include +#include #include + class TCP: public QWidget, public Ui::TCP { public: TCP(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; class Security: public QWidget, public Ui::Security { public: Security(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; +class ConfigFramebuffer: public QWidget, public Ui::Framebuffer +{ +public: + ConfigFramebuffer(QWidget *parent = 0) : QWidget(parent) { + setupUi(this); + // hide the line edit with framebuffer string + kcfg_preferredFrameBufferPlugin->hide(); + // fill drop-down combo with a list of real existing plugins + this->fillFrameBuffersCombo(); + // initialize combo with currently configured framebuffer plugin + cb_preferredFrameBufferPlugin->setCurrentText(KrfbConfig::preferredFrameBufferPlugin()); + // connect signals between combo<->lineedit + // if we change selection in combo, lineedit is updated + QObject::connect(cb_preferredFrameBufferPlugin, &QComboBox::currentTextChanged, + kcfg_preferredFrameBufferPlugin, &QLineEdit::setText); + } + + void fillFrameBuffersCombo() { + const QVector plugins = KPluginLoader::findPlugins( + QStringLiteral("krfb"), [](const KPluginMetaData & md) { + return md.serviceTypes().contains(QStringLiteral("krfb/framebuffer")); + }); + QSet unique; + QVectorIterator i(plugins); + i.toBack(); + while (i.hasPrevious()) { + const KPluginMetaData &metadata = i.previous(); + if (unique.contains(metadata.pluginId())) continue; + cb_preferredFrameBufferPlugin->addItem(metadata.pluginId()); + unique.insert(metadata.pluginId()); + } + } +}; + MainWindow::MainWindow(QWidget *parent) : KXmlGuiWindow(parent) { setAttribute(Qt::WA_DeleteOnClose, false); m_passwordEditable = false; m_passwordLineEdit = new KLineEdit(this); m_passwordLineEdit->setVisible(false); m_passwordLineEdit->setAlignment(Qt::AlignHCenter); QWidget *mainWidget = new QWidget; m_ui.setupUi(mainWidget); m_ui.krfbIconLabel->setPixmap(QIcon::fromTheme("krfb").pixmap(128)); m_ui.enableUnattendedCheckBox->setChecked( InvitationsRfbServer::instance->allowUnattendedAccess()); setCentralWidget(mainWidget); connect(m_ui.passwordEditButton, &QToolButton::clicked, this, &MainWindow::editPassword); connect(m_ui.enableSharingCheckBox, &QCheckBox::toggled, this, &MainWindow::toggleDesktopSharing); connect(m_ui.enableUnattendedCheckBox, &QCheckBox::toggled, InvitationsRfbServer::instance, &InvitationsRfbServer::toggleUnattendedAccess); connect(m_ui.unattendedPasswordButton, &QPushButton::clicked, this, &MainWindow::editUnattendedPassword); connect(m_ui.addressAboutButton, &QToolButton::clicked, this, &MainWindow::aboutConnectionAddress); connect(m_ui.unattendedAboutButton, &QToolButton::clicked, this, &MainWindow::aboutUnattendedMode); connect(InvitationsRfbServer::instance, &InvitationsRfbServer::passwordChanged, this, &MainWindow::passwordChanged); // Figure out the address int port = KrfbConfig::port(); QList interfaceList = QNetworkInterface::allInterfaces(); foreach(const QNetworkInterface & interface, interfaceList) { if(interface.flags() & QNetworkInterface::IsLoopBack) continue; if(interface.flags() & QNetworkInterface::IsRunning && !interface.addressEntries().isEmpty()) m_ui.addressDisplayLabel->setText(QString("%1 : %2") .arg(interface.addressEntries().first().ip().toString()) .arg(port)); } //Figure out the password m_ui.passwordDisplayLabel->setText( InvitationsRfbServer::instance->desktopPassword()); KStandardAction::quit(QCoreApplication::instance(), SLOT(quit()), actionCollection()); KStandardAction::preferences(this, SLOT(showConfiguration()), actionCollection()); setupGUI(); if (KrfbConfig::allowDesktopControl()) { m_ui.enableSharingCheckBox->setChecked(true); } setAutoSaveSettings(); } MainWindow::~MainWindow() { } void MainWindow::editPassword() { if(m_passwordEditable) { m_passwordEditable = false; m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-properties")); m_ui.passwordGridLayout->removeWidget(m_passwordLineEdit); InvitationsRfbServer::instance->setDesktopPassword( m_passwordLineEdit->text()); m_ui.passwordDisplayLabel->setText( InvitationsRfbServer::instance->desktopPassword()); m_passwordLineEdit->setVisible(false); } else { m_passwordEditable = true; m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-save")); m_ui.passwordGridLayout->addWidget(m_passwordLineEdit,0,0); m_passwordLineEdit->setText( InvitationsRfbServer::instance->desktopPassword()); m_passwordLineEdit->setVisible(true); m_passwordLineEdit->setFocus(Qt::MouseFocusReason); } } void MainWindow::editUnattendedPassword() { KNewPasswordDialog dialog(this); dialog.setPrompt(i18n("Enter a new password for Unattended Access")); if(dialog.exec()) { InvitationsRfbServer::instance->setUnattendedPassword(dialog.password()); } } void MainWindow::toggleDesktopSharing(bool enable) { if(enable) { if(!InvitationsRfbServer::instance->start()) { KMessageBox::error(this, i18n("Failed to start the krfb server. Desktop sharing " "will not work. Try setting another port in the settings " "and restart krfb.")); } } else { InvitationsRfbServer::instance->stop(); if(m_passwordEditable) { m_passwordEditable = false; m_passwordLineEdit->setVisible(false); m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-properties")); } } } void MainWindow::passwordChanged(const QString& password) { m_passwordLineEdit->setText(password); m_ui.passwordDisplayLabel->setText(password); } void MainWindow::aboutConnectionAddress() { KMessageBox::about(this, i18n("This field contains the address of your computer and the port number, separated by a colon.\n\nThe address is just a hint - you can use any address that can reach your computer.\n\nDesktop Sharing tries to guess your address from your network configuration, but does not always succeed in doing so.\n\nIf your computer is behind a firewall it may have a different address or be unreachable for other computers."), i18n("KDE Desktop Sharing")); } void MainWindow::aboutUnattendedMode() { KMessageBox::about(this, i18n("Any remote user with normal desktop sharing password will have to be authenticated.\n\nIf unattended access is on, and the remote user provides unattended mode password, desktop sharing access will be granted without explicit confirmation."), i18n("KDE Desktop Sharing")); } void MainWindow::showConfiguration() { + static QString s_prevFramebufferPlugin; + // ^^ needs to be static, because lambda will be called long time + // after showConfiguration() ends, so auto variable would go out of scope + // save previously selected framebuffer plugin config + s_prevFramebufferPlugin = KrfbConfig::preferredFrameBufferPlugin(); + if (KConfigDialog::showDialog("settings")) { return; } KConfigDialog *dialog = new KConfigDialog(this, "settings", KrfbConfig::self()); - dialog->addPage(new TCP, i18n("Network"), "network-workgroup"); + dialog->addPage(new TCP, i18n("Network"), "network-wired"); dialog->addPage(new Security, i18n("Security"), "security-high"); + dialog->addPage(new ConfigFramebuffer, i18n("Screen capture"), "video-display"); dialog->show(); + connect(dialog, &KConfigDialog::settingsChanged, [this] () { + // check if framebuffer plugin config has changed + if (s_prevFramebufferPlugin != KrfbConfig::preferredFrameBufferPlugin()) { + KMessageBox::information(this, i18n("To apply framebuffer plugin setting, " + "you need to restart the program.")); + } + }); } void MainWindow::readProperties(const KConfigGroup& group) { if (group.readEntry("Visible", true)) { show(); } KMainWindow::readProperties(group); } void MainWindow::saveProperties(KConfigGroup& group) { group.writeEntry("Visible", isVisible()); KMainWindow::saveProperties(group); } #include "mainwindow.moc" diff --git a/krfb/ui/configframebuffer.ui b/krfb/ui/configframebuffer.ui new file mode 100644 index 0000000..4f43e2c --- /dev/null +++ b/krfb/ui/configframebuffer.ui @@ -0,0 +1,90 @@ + + + Framebuffer + + + + 0 + 0 + 418 + 186 + + + + Framebuffer + + + + + + + + Preferred frameb&uffer plugin: + + + cb_preferredFrameBufferPlugin + + + + + + + false + + + + + + + + + + + + true + + + <html><head/><body><p>When using x11, <span style=" font-weight:600;">xcb</span> plugin should be preferred, because it is more performant.<br/><span style=" font-weight:600;">qt</span> plugin is a safe fallback, if for some reason others don't work. But also it is very slow.</p></body></html> + + + Qt::RichText + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + 5 + + + Qt::NoTextInteraction + + + + + + + Qt::Vertical + + + + 20 + 63 + + + + + + + + cb_preferredFrameBufferPlugin + kcfg_preferredFrameBufferPlugin + + + +