Warning, file /plasma/wacomtablet/src/kded/tabletdaemon.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "tabletdaemon.h"
0021 
0022 #include "../wacomtablet-version.h"
0023 #include "dbustabletservice.h"
0024 #include "globalactions.h"
0025 #include "logging.h"
0026 #include "tabletfinder.h"
0027 #include "tablethandler.h"
0028 #include "wacomadaptor.h"
0029 #include "x11eventnotifier.h"
0030 
0031 // common includes
0032 #include "aboutdata.h"
0033 
0034 // stdlib includes
0035 #include <memory>
0036 
0037 // KDE includes
0038 #include <KIO/ApplicationLauncherJob>
0039 #include <KLocalizedString>
0040 #include <KNotification>
0041 #include <KPluginFactory>
0042 
0043 #include <QGuiApplication>
0044 #include <QScreen>
0045 
0046 #include "private/qtx11extras_p.h"
0047 
0048 using namespace Wacom;
0049 
0050 K_PLUGIN_FACTORY_WITH_JSON(WacomTabletFactory, "wacomtablet.json", registerPlugin<TabletDaemon>();)
0051 
0052 namespace Wacom
0053 {
0054 /**
0055  * Private class of the TabletDaemon for the d-pointer
0056  */
0057 class TabletDaemonPrivate
0058 {
0059 public:
0060     TabletDaemonPrivate()
0061         : tabletHandler()
0062         , dbusTabletService(tabletHandler)
0063     {
0064     }
0065 
0066     TabletHandler tabletHandler; /**< tablet handler */
0067     DBusTabletService dbusTabletService;
0068     std::shared_ptr<GlobalActions> actionCollection; /**< Collection of all global actions */
0069 
0070 }; // CLASS
0071 } // NAMESPACE
0072 
0073 TabletDaemon::TabletDaemon(QObject *parent, const QVariantList &args)
0074     : KDEDModule(parent)
0075     , d_ptr(new TabletDaemonPrivate)
0076 {
0077     Q_UNUSED(args);
0078     Q_D(TabletDaemon);
0079 
0080     setupApplication();
0081     setupDBus();
0082     setupEventNotifier();
0083     setupActions();
0084 
0085     // scan for connected devices
0086     TabletFinder::instance().scan();
0087 
0088     // connect profile changed handler after searching for tablets as this is only used for the global shortcut workaround.
0089     connect(&(d->tabletHandler), &TabletHandler::profileChanged, this, &TabletDaemon::onProfileChanged);
0090 
0091     // Connecting this after the device has been set up ensures that no notification is send on startup.
0092     connect(&(d->tabletHandler), &TabletHandler::notify, this, &TabletDaemon::onNotify);
0093 }
0094 
0095 TabletDaemon::~TabletDaemon()
0096 {
0097     X11EventNotifier::instance().stop();
0098     delete this->d_ptr;
0099 }
0100 
0101 void TabletDaemon::onNotify(const QString &eventId, const QString &title, const QString &message, bool suggestConfigure) const
0102 {
0103     KNotification *notification = new KNotification(eventId);
0104     notification->setComponentName(QStringLiteral("wacomtablet"));
0105     notification->setTitle(title);
0106     notification->setText(message);
0107     notification->setIconName(QLatin1String("preferences-desktop-tablet"));
0108 
0109     if (suggestConfigure) {
0110 #if QT_VERSION_MAJOR == 5
0111         notification->setActions(QStringList{i18nc("Button that shows up in notification of a new tablet being connected", "Configure")});
0112         connect(notification, &KNotification::action1Activated, this, [notification] {
0113 #else
0114         KNotificationAction *configureAction =
0115             notification->addAction(i18nc("Button that shows up in notification "
0116                                           "of a new tablet being connected",
0117                                           "Configure"));
0118         connect(configureAction, &KNotificationAction::activated, this, [notification] {
0119 #endif
0120             auto *job = new KIO::ApplicationLauncherJob(KService::serviceByDesktopName(QStringLiteral("kcm_wacomtablet")));
0121             job->setStartupId(notification->xdgActivationToken().toUtf8());
0122             job->start();
0123         });
0124     }
0125 
0126     notification->sendEvent();
0127 }
0128 
0129 void TabletDaemon::onProfileChanged(const QString &tabletId, const QString &profile)
0130 {
0131     Q_UNUSED(tabletId);
0132     Q_UNUSED(profile);
0133 
0134     // When closing the KCM module the KAction destructor disables all global shortcuts.
0135     // Make sure the global shortcuts are restored when a profile changes. This is not
0136     // optimal but at least it will enable the shortcuts again.
0137     qCDebug(KDED) << QLatin1String("Restoring global keyboard shortcuts...");
0138     setupActions();
0139 }
0140 
0141 void TabletDaemon::setupActions()
0142 {
0143     Q_D(TabletDaemon);
0144 
0145     // if someone adds another action also add it to kcmodule/generalwidget.cpp
0146 
0147     // This method is called multiple times - make sure the action collection is only created once.
0148     if (!d->actionCollection) {
0149         d->actionCollection = std::shared_ptr<GlobalActions>(new GlobalActions(false, this));
0150         d->actionCollection->setConfigGlobal(true);
0151     }
0152 
0153     connect(d->actionCollection.get(), &GlobalActions::toggleTouchTriggered, &(d->tabletHandler), &TabletHandler::onToggleTouch, Qt::UniqueConnection);
0154     connect(d->actionCollection.get(), &GlobalActions::toggleStylusTriggered, &(d->tabletHandler), &TabletHandler::onTogglePenMode, Qt::UniqueConnection);
0155     connect(d->actionCollection.get(),
0156             &GlobalActions::toggleScreenMapTriggered,
0157             &(d->tabletHandler),
0158             &TabletHandler::onToggleScreenMapping,
0159             Qt::UniqueConnection);
0160     connect(d->actionCollection.get(), &GlobalActions::mapToFullScreenTriggered, &(d->tabletHandler), &TabletHandler::onMapToFullScreen, Qt::UniqueConnection);
0161     connect(d->actionCollection.get(), &GlobalActions::mapToScreen1Triggered, &(d->tabletHandler), &TabletHandler::onMapToScreen1, Qt::UniqueConnection);
0162     connect(d->actionCollection.get(), &GlobalActions::mapToScreen2Triggered, &(d->tabletHandler), &TabletHandler::onMapToScreen2, Qt::UniqueConnection);
0163     connect(d->actionCollection.get(), &GlobalActions::nextProfileTriggered, &(d->tabletHandler), &TabletHandler::onNextProfile, Qt::UniqueConnection);
0164     connect(d->actionCollection.get(), &GlobalActions::previousProfileTriggered, &(d->tabletHandler), &TabletHandler::onPreviousProfile, Qt::UniqueConnection);
0165 }
0166 
0167 void TabletDaemon::setupApplication()
0168 {
0169     static AboutData about(QLatin1String("wacomtablet"),
0170                            i18n("Graphic Tablet Configuration daemon"),
0171                            QLatin1String(WACOMTABLET_VERSION_STRING),
0172                            i18n("A Wacom tablet control daemon"));
0173 }
0174 
0175 void TabletDaemon::setupDBus()
0176 {
0177     Q_D(TabletDaemon);
0178 
0179     // connect tablet handler events to D-Bus
0180     // this is done here and not in the D-Bus tablet service to facilitate unit testing
0181     connect(&(d->tabletHandler), &TabletHandler::profileChanged, &(d->dbusTabletService), &DBusTabletService::onProfileChanged);
0182     connect(&(d->tabletHandler), &TabletHandler::tabletAdded, &(d->dbusTabletService), &DBusTabletService::onTabletAdded);
0183     connect(&(d->tabletHandler), &TabletHandler::tabletRemoved, &(d->dbusTabletService), &DBusTabletService::onTabletRemoved);
0184 }
0185 
0186 void TabletDaemon::setupEventNotifier()
0187 {
0188     Q_D(TabletDaemon);
0189 
0190     // Set up monitoring for individual screen geometry changes
0191     monitorAllScreensGeometry();
0192 
0193     // Set up monitoring for screens being added, removed or reordered
0194     connect(qApp, &QGuiApplication::primaryScreenChanged, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved);
0195     connect(qApp, &QGuiApplication::screenAdded, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved);
0196     connect(qApp, &QGuiApplication::screenRemoved, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved);
0197 
0198     // Set up tablet connected/disconnected signals
0199     connect(&X11EventNotifier::instance(), &X11EventNotifier::tabletAdded, &TabletFinder::instance(), &TabletFinder::onX11TabletAdded);
0200     connect(&X11EventNotifier::instance(), &X11EventNotifier::tabletRemoved, &TabletFinder::instance(), &TabletFinder::onX11TabletRemoved);
0201 
0202     connect(&TabletFinder::instance(), &TabletFinder::tabletAdded, &(d->tabletHandler), &TabletHandler::onTabletAdded);
0203     connect(&TabletFinder::instance(), &TabletFinder::tabletRemoved, &(d->tabletHandler), &TabletHandler::onTabletRemoved);
0204 
0205     if (QX11Info::isPlatformX11()) {
0206         X11EventNotifier::instance().start();
0207     }
0208 }
0209 
0210 void TabletDaemon::monitorAllScreensGeometry()
0211 {
0212     // Add existing screens
0213     for (const auto &screen : QGuiApplication::screens()) {
0214         monitorScreenGeometry(screen);
0215     }
0216 
0217     // Monitor future screens
0218     connect(qApp, &QGuiApplication::screenAdded, this, &TabletDaemon::monitorScreenGeometry);
0219 }
0220 
0221 void TabletDaemon::monitorScreenGeometry(QScreen *screen)
0222 {
0223     Q_D(TabletDaemon);
0224 
0225     const auto &tabletHandler = &(d->tabletHandler);
0226 
0227     connect(screen, &QScreen::orientationChanged, [=](const Qt::ScreenOrientation &newScreenRotation) {
0228         tabletHandler->onScreenRotated(screen->name(), newScreenRotation);
0229     });
0230 
0231     connect(screen, &QScreen::geometryChanged, &(d->tabletHandler), &TabletHandler::onScreenGeometryChanged);
0232 }
0233 
0234 #include "tabletdaemon.moc"
0235 
0236 #include "moc_tabletdaemon.cpp"