diff --git a/CMakeLists.txt b/CMakeLists.txt index fa0dfb7..b37f3ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,59 +1,61 @@ project(plasma-phone-components) # minimal requirements cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR) set (QT_MIN_VERSION "5.2.0") set(KF5_MIN_VERSION "5.0.0") set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_CXX_STANDARD 14) + find_package(ECM 5.41.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) include(ECMOptionalAddSubdirectory) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(FeatureSummary) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Core Gui Widgets Qml Quick Test) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma Service Declarative I18n KIO People) find_package(KF5 REQUIRED COMPONENTS PlasmaQuick DBusAddons Notifications) find_package(TelepathyQt5 REQUIRED) find_package(KF5Wayland CONFIG) set_package_properties(KF5Wayland PROPERTIES TYPE REQUIRED PURPOSE "Required for interacting with the compositor") # torch find_package(GStreamer 1.1.90 REQUIRED) find_package(GLIB2 REQUIRED) find_package(GObject REQUIRED) include(CheckIncludeFiles) plasma_install_package(look-and-feel org.kde.plasma.phone look-and-feel) plasma_install_package(shell org.kde.plasma.phone shells) install(DIRECTORY wallpaper/ DESTINATION "${WALLPAPER_INSTALL_DIR}/org.kde.plasma.phone.lockers") install( DIRECTORY kwinmultitasking/ DESTINATION ${DATA_INSTALL_DIR}/kwin/scripts/org.kde.phone.multitasking ) install( FILES kwinmultitasking/metadata.desktop DESTINATION ${SERVICES_INSTALL_DIR} RENAME kwin-script-org.kde.phone.multitasking.desktop ) install( DIRECTORY qtvirtualkeyboardplugin/ DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/VirtualKeyboard/Styles/Plasma ) add_subdirectory(bin) add_subdirectory(applets) add_subdirectory(containments) add_subdirectory(dialer) add_subdirectory(sounds) #add_subdirectory(touchscreentest) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/containments/homescreen/applicationlistmodel.cpp b/containments/homescreen/applicationlistmodel.cpp index 5300d21..776f171 100644 --- a/containments/homescreen/applicationlistmodel.cpp +++ b/containments/homescreen/applicationlistmodel.cpp @@ -1,362 +1,361 @@ /* * Copyright (C) 2014 Antonis Tsiapaliokas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include "applicationlistmodel.h" // Qt #include #include #include // KDE #include #include #include #include #include #include #include ApplicationListModel::ApplicationListModel(HomeScreen *parent) : QAbstractListModel(parent), m_homeScreen(parent) { - //can't use the new syntax as this signal is overloaded - connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), - this, SLOT(sycocaDbChanged(QStringList))); + connect(KSycoca::self(), qOverload(&KSycoca::databaseChanged), + this, &ApplicationListModel::sycocaDbChanged); loadSettings(); } ApplicationListModel::~ApplicationListModel() = default; void ApplicationListModel::loadSettings() { m_favorites = m_homeScreen->config().readEntry("Favorites", QStringList()); m_desktopItems = m_homeScreen->config().readEntry("DesktopItems", QStringList()).toSet(); m_appOrder = m_homeScreen->config().readEntry("AppOrder", QStringList()); m_maxFavoriteCount = m_homeScreen->config().readEntry("MaxFavoriteCount", 5); int i = 0; for (const QString &app : qAsConst(m_appOrder)) { m_appPositions[app] = i; ++i; } loadApplications(); } QHash ApplicationListModel::roleNames() const { QHash roleNames; roleNames[ApplicationNameRole] = "ApplicationNameRole"; roleNames[ApplicationIconRole] = "ApplicationIconRole"; roleNames[ApplicationStorageIdRole] = "ApplicationStorageIdRole"; roleNames[ApplicationEntryPathRole] = "ApplicationEntryPathRole"; roleNames[ApplicationOriginalRowRole] = "ApplicationOriginalRowRole"; roleNames[ApplicationStartupNotifyRole] = "ApplicationStartupNotifyRole"; roleNames[ApplicationLocationRole] = "ApplicationLocationRole"; return roleNames; } void ApplicationListModel::sycocaDbChanged(const QStringList &changes) { if (!changes.contains("apps") && !changes.contains("xdgdata-apps")) { return; } m_applicationList.clear(); loadApplications(); } bool appNameLessThan(const ApplicationData &a1, const ApplicationData &a2) { return a1.name.toLower() < a2.name.toLower(); } void ApplicationListModel::loadApplications() { auto cfg = KSharedConfig::openConfig("applications-blacklistrc"); auto blgroup = KConfigGroup(cfg, QStringLiteral("Applications")); // This is only temporary to get a clue what those apps' desktop files are called // I'll remove it once I've done a blacklist QStringList bl; QStringList blacklist = blgroup.readEntry("blacklist", QStringList()); beginResetModel(); m_applicationList.clear(); KServiceGroup::Ptr group = KServiceGroup::root(); if (!group || !group->isValid()) return; KServiceGroup::List subGroupList = group->entries(true); QMap orderedList; QList unorderedList; // Iterate over all entries in the group while (!subGroupList.isEmpty()) { KSycocaEntry::Ptr groupEntry = subGroupList.first(); subGroupList.pop_front(); if (groupEntry->isType(KST_KServiceGroup)) { KServiceGroup::Ptr serviceGroup(static_cast(groupEntry.data())); if (!serviceGroup->noDisplay()) { KServiceGroup::List entryGroupList = serviceGroup->entries(true); for(KServiceGroup::List::ConstIterator it = entryGroupList.constBegin(); it != entryGroupList.constEnd(); it++) { KSycocaEntry::Ptr entry = (*it); if (entry->isType(KST_KServiceGroup)) { KServiceGroup::Ptr serviceGroup(static_cast(entry.data())); subGroupList << serviceGroup; } else if (entry->property("Exec").isValid()) { KService::Ptr service(static_cast(entry.data())); if (service->isApplication() && !blacklist.contains(service->desktopEntryName()) && service->showOnCurrentPlatform() && !service->property("Terminal", QVariant::Bool).toBool()) { bl << service->desktopEntryName(); ApplicationData data; data.name = service->name(); data.icon = service->icon(); data.storageId = service->storageId(); data.entryPath = service->exec(); data.startupNotify = service->property("StartupNotify").toBool(); if (m_favorites.contains(data.storageId)) { data.location = Favorites; } else if (m_desktopItems.contains(data.storageId)) { data.location = Desktop; } auto it = m_appPositions.constFind(service->storageId()); if (it != m_appPositions.constEnd()) { orderedList[*it] = data; } else { unorderedList << data; } } } } } } } blgroup.writeEntry("allapps", bl); blgroup.writeEntry("blacklist", blacklist); cfg->sync(); std::sort(unorderedList.begin(), unorderedList.end(), appNameLessThan); m_applicationList << orderedList.values(); m_applicationList << unorderedList; endResetModel(); emit countChanged(); } QVariant ApplicationListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } switch (role) { case Qt::DisplayRole: case ApplicationNameRole: return m_applicationList.at(index.row()).name; case ApplicationIconRole: return m_applicationList.at(index.row()).icon; case ApplicationStorageIdRole: return m_applicationList.at(index.row()).storageId; case ApplicationEntryPathRole: return m_applicationList.at(index.row()).entryPath; case ApplicationOriginalRowRole: return index.row(); case ApplicationStartupNotifyRole: return m_applicationList.at(index.row()).startupNotify; case ApplicationLocationRole: return m_applicationList.at(index.row()).location; default: return QVariant(); } } Qt::ItemFlags ApplicationListModel::flags(const QModelIndex &index) const { if (!index.isValid()) return nullptr; return Qt::ItemIsDragEnabled|QAbstractListModel::flags(index); } int ApplicationListModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_applicationList.count(); } void ApplicationListModel::moveRow(const QModelIndex& /* sourceParent */, int sourceRow, const QModelIndex& /* destinationParent */, int destinationChild) { moveItem(sourceRow, destinationChild); } void ApplicationListModel::setLocation(int row, LauncherLocation location) { if (row < 0 || row >= m_applicationList.length()) { return; } ApplicationData &data = m_applicationList[row]; if (data.location == location) { return; } if (location == Favorites) {qWarning()<<"favoriting"<= m_maxFavoriteCount || m_favorites.count() >= m_maxFavoriteCount) { return; } m_favorites.insert(row, data.storageId); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); // Out of favorites } else if (data.location == Favorites) { m_favorites.removeAll(data.storageId); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); } // In Desktop if (location == Desktop) { m_desktopItems.insert(data.storageId); m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList()); // Out of Desktop } else if (data.location == Desktop) { m_desktopItems.remove(data.storageId); m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList()); } data.location = location; emit m_homeScreen->configNeedsSaving(); emit dataChanged(index(row, 0), index(row, 0)); } void ApplicationListModel::moveItem(int row, int destination) { if (row < 0 || destination < 0 || row >= m_applicationList.length() || destination >= m_applicationList.length() || row == destination) { return; } if (destination > row) { ++destination; } beginMoveRows(QModelIndex(), row, row, QModelIndex(), destination); if (destination > row) { ApplicationData data = m_applicationList.at(row); m_applicationList.insert(destination, data); m_applicationList.takeAt(row); } else { ApplicationData data = m_applicationList.takeAt(row); m_applicationList.insert(destination, data); } m_appOrder.clear(); m_appPositions.clear(); int i = 0; for (const ApplicationData &app : qAsConst(m_applicationList)) { m_appOrder << app.storageId; m_appPositions[app.storageId] = i; ++i; } m_homeScreen->config().writeEntry("AppOrder", m_appOrder); endMoveRows(); } void ApplicationListModel::runApplication(const QString &storageId) { if (storageId.isEmpty()) { return; } KService::Ptr service = KService::serviceByStorageId(storageId); KRun::runService(*service, QList(), nullptr); } int ApplicationListModel::maxFavoriteCount() const { return m_maxFavoriteCount; } void ApplicationListModel::setMaxFavoriteCount(int count) { if (m_maxFavoriteCount == count) { return; } if (m_maxFavoriteCount > count) { while (m_favorites.size() > count && m_favorites.count() > 0) { m_favorites.pop_back(); } emit favoriteCountChanged(); int i = 0; for (auto &app : m_applicationList) { if (i >= count && app.location == Favorites) { app.location = Grid; emit dataChanged(index(i, 0), index(i, 0)); } ++i; } } m_maxFavoriteCount = count; m_homeScreen->config().writeEntry("MaxFavoriteCount", m_maxFavoriteCount); emit maxFavoriteCountChanged(); } #include "moc_applicationlistmodel.cpp" diff --git a/containments/taskpanel/taskpanel.cpp b/containments/taskpanel/taskpanel.cpp index 818a931..174a998 100644 --- a/containments/taskpanel/taskpanel.cpp +++ b/containments/taskpanel/taskpanel.cpp @@ -1,201 +1,203 @@ /*************************************************************************** * Copyright (C) 2015 Marco Martin * * * * 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; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "taskpanel.h" #include #include #include #include #include #include #include #include #include #include #include static const QString s_kwinService = QStringLiteral("org.kde.KWin"); TaskPanel::TaskPanel(QObject *parent, const QVariantList &args) : Plasma::Containment(parent, args) , m_showingDesktop(false) , m_windowManagement(nullptr) { setHasConfigurationInterface(true); m_activeTimer = new QTimer(this); m_activeTimer->setSingleShot(true); m_activeTimer->setInterval(250); connect(m_activeTimer, &QTimer::timeout, this, &TaskPanel::updateActiveWindow); initWayland(); } TaskPanel::~TaskPanel() { } void TaskPanel::requestShowingDesktop(bool showingDesktop) { if (!m_windowManagement) { return; } m_windowManagement->setShowingDesktop(showingDesktop); } void TaskPanel::initWayland() { if (!QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { return; } using namespace KWayland::Client; ConnectionThread *connection = ConnectionThread::fromApplication(this); if (!connection) { return; } auto *registry = new Registry(this); registry->create(connection); connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [this, registry] (quint32 name, quint32 version) { m_windowManagement = registry->createPlasmaWindowManagement(name, version, this); qRegisterMetaType >("QVector"); connect(m_windowManagement, &PlasmaWindowManagement::showingDesktopChanged, this, [this] (bool showing) { if (showing == m_showingDesktop) { return; } m_showingDesktop = showing; emit showingDesktopChanged(m_showingDesktop); } ); //FIXME //connect(m_windowManagement, &PlasmaWindowManagement::activeWindowChanged, this, &TaskPanel::updateActiveWindow, Qt::QueuedConnection); - - connect(m_windowManagement, SIGNAL(activeWindowChanged()), m_activeTimer, SLOT(start())); + + connect(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::activeWindowChanged, + m_activeTimer, qOverload<>(&QTimer::start)); + updateActiveWindow(); } ); connect(registry, &Registry::plasmaShellAnnounced, this, [this, registry] (quint32 name, quint32 version) { m_shellInterface = registry->createPlasmaShell(name, version, this); if (!m_panel) { return; } Surface *s = Surface::fromWindow(m_panel); if (!s) { return; } m_shellSurface = m_shellInterface->createSurface(s, this); m_shellSurface->setSkipTaskbar(true); } ); registry->setup(); connection->roundtrip(); } QWindow *TaskPanel::panel() { return m_panel; } void TaskPanel::setPanel(QWindow *panel) { if (panel == m_panel) { return; } if (m_panel) { disconnect(m_panel, &QWindow::visibilityChanged, this, &TaskPanel::updatePanelVisibility); } m_panel = panel; connect(m_panel, &QWindow::visibilityChanged, this, &TaskPanel::updatePanelVisibility, Qt::QueuedConnection); emit panelChanged(); updatePanelVisibility(); } void TaskPanel::updatePanelVisibility() { using namespace KWayland::Client; if (!m_panel->isVisible()) { return; } Surface *s = Surface::fromWindow(m_panel); if (!s) { return; } m_shellSurface = m_shellInterface->createSurface(s, this); if (m_shellSurface) { m_shellSurface->setSkipTaskbar(true); } } void TaskPanel::updateActiveWindow() { if (!m_windowManagement || m_activeWindow == m_windowManagement->activeWindow()) { return; } if (m_activeWindow) { disconnect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::closeableChanged, this, &TaskPanel::hasCloseableActiveWindowChanged); disconnect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::unmapped, this, &TaskPanel::forgetActiveWindow); } m_activeWindow = m_windowManagement->activeWindow(); if (m_activeWindow) { connect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::closeableChanged, this, &TaskPanel::hasCloseableActiveWindowChanged); connect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::unmapped, this, &TaskPanel::forgetActiveWindow); } // TODO: connect to closeableChanged, not needed right now as KWin doesn't provide this changeable emit hasCloseableActiveWindowChanged(); } bool TaskPanel::hasCloseableActiveWindow() const { return m_activeWindow && m_activeWindow->isCloseable() /*&& !m_activeWindow->isMinimized()*/; } void TaskPanel::forgetActiveWindow() { if (m_activeWindow) { disconnect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::closeableChanged, this, &TaskPanel::hasCloseableActiveWindowChanged); disconnect(m_activeWindow.data(), &KWayland::Client::PlasmaWindow::unmapped, this, &TaskPanel::forgetActiveWindow); } m_activeWindow.clear(); emit hasCloseableActiveWindowChanged(); } void TaskPanel::closeActiveWindow() { if (m_activeWindow) { m_activeWindow->requestClose(); } } K_EXPORT_PLASMA_APPLET_WITH_JSON(taskpanel, TaskPanel, "metadata.json") #include "taskpanel.moc" diff --git a/dialer/src/call-manager.cpp b/dialer/src/call-manager.cpp index f08f9a9..9c369a5 100644 --- a/dialer/src/call-manager.cpp +++ b/dialer/src/call-manager.cpp @@ -1,272 +1,272 @@ /* Copyright (C) 2012 George Kiagiadakis This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "call-manager.h" #include "dialerutils.h" #include #include #include // #include "call-window.h" // #include "approver.h" // #include "../libktpcall/call-channel-handler.h" // #include "ktp_call_ui_debug.h" // #include struct CallManager::Private { Tp::CallChannelPtr callChannel; // CallChannelHandler *channelHandler; // QPointer callWindow; // QPointer approver; DialerUtils *dialerUtils; KNotification *ringingNotification; KNotification *callsNotification; uint missedCalls; QTimer *callTimer; }; CallManager::CallManager(const Tp::CallChannelPtr &callChannel, DialerUtils *dialerUtils, QObject *parent) : QObject(parent), d(new Private) { // KTp::TelepathyHandlerApplication::newJob(); d->dialerUtils = dialerUtils; d->callChannel = callChannel; - connect(callChannel.data(), SIGNAL(callStateChanged(Tp::CallState)), - SLOT(onCallStateChanged(Tp::CallState))); + connect(callChannel.data(), &Tp::CallChannel::callStateChanged, + this, &CallManager::onCallStateChanged); connect(d->dialerUtils, &DialerUtils::acceptCall, this, &CallManager::onCallAccepted); connect(d->dialerUtils, &DialerUtils::rejectCall, this, &CallManager::onCallRejected); connect(d->dialerUtils, &DialerUtils::hangUp, this, &CallManager::onHangUpRequested); connect(d->callChannel.data(), &Tp::CallChannel::invalidated, this, [=]() { qDebug() << "Channel invalidated"; d->dialerUtils->setCallState("idle"); d->dialerUtils->emitCallEnded(); deleteLater(); }); d->ringingNotification = nullptr; d->callsNotification = nullptr; d->callTimer = nullptr; //create the channel handler // d->channelHandler = new CallChannelHandler(callChannel, this); //delete the CallManager when the channel has closed //and the farstream side has safely shut down. //NOTE this MUST be used with Qt::QueuedConnection because of // https://bugreports.qt-project.org/browse/QTBUG-24571 // connect(d->channelHandler, SIGNAL(channelClosed()), // this, SLOT(deleteLater()), Qt::QueuedConnection); //bring us up-to-date with the current call state onCallStateChanged(d->callChannel->callState()); } CallManager::~CallManager() { qDebug() << "Deleting CallManager"; //delete the window just in case CallManager was deleted //before the channel entered CallStateEnded // delete d->callWindow.data(); // delete d; // KTp::TelepathyHandlerApplication::jobFinished(); } void CallManager::onCallStateChanged(Tp::CallState state) { qDebug() << "new call state:" << state; if (d->callChannel->targetContact()) { d->dialerUtils->setCallContactAlias(d->callChannel->targetContact()->alias()); d->dialerUtils->setCallContactNumber(d->callChannel->targetContact()->id()); } if (d->callChannel->isValid()) { d->dialerUtils->setIsIncomingCall(!d->callChannel->isRequested()); } switch (state) { case Tp::CallStatePendingInitiator: Q_ASSERT(d->callChannel->isRequested()); (void) d->callChannel->accept(); break; case Tp::CallStateInitialising: if (d->callChannel->isRequested()) { d->dialerUtils->setCallState("dialing"); //show status that the call is connecting // ensureCallWindow(); // d->callWindow.data()->setStatus(CallWindow::StatusConnecting); } else { qDebug() << "Call is initialising"; } break; case Tp::CallStateInitialised: if (d->callChannel->isRequested()) { d->dialerUtils->setCallState("dialing"); //show status that the remote end is ringing // ensureCallWindow(); // d->callWindow.data()->setStatus(CallWindow::StatusRemoteRinging); } else { d->dialerUtils->setCallState("incoming"); //show approver; (void) d->callChannel->setRinging(); if (!d->ringingNotification) { d->ringingNotification = new KNotification("ringing", KNotification::Persistent | KNotification::LoopSound, nullptr); d->ringingNotification->setComponentName("plasma_dialer"); } d->ringingNotification->sendEvent(); } break; case Tp::CallStateAccepted: if (d->callChannel->isRequested()) { d->dialerUtils->setCallState("answered"); //show status that the remote end accepted the call // ensureCallWindow(); // d->callWindow.data()->setStatus(CallWindow::StatusRemoteAccepted); } else { //hide approver & show call window if (d->ringingNotification) { d->ringingNotification->close(); } // delete d->approver.data(); // ensureCallWindow(); // d->callWindow.data()->setStatus(CallWindow::StatusConnecting); } break; case Tp::CallStateActive: //normally the approver is already deleted and the call window //already exists at this point, but we just want to be safe //in case the CM decides to do a weird state jump if (!d->callChannel->isRequested()) { // delete d->approver.data(); } d->dialerUtils->setCallState("active"); d->callTimer = new QTimer(this); connect(d->callTimer, &QTimer::timeout, d->callTimer, [=]() { d->dialerUtils->setCallDuration(d->dialerUtils->callDuration() + 1); }); d->callTimer->start(1000); // ensureCallWindow(); // d->callWindow.data()->setStatus(CallWindow::StatusActive); break; case Tp::CallStateEnded: d->dialerUtils->setCallState("ended"); if (d->ringingNotification) { d->ringingNotification->close(); } //FIXME this is defined in the spec, but try to find a proper enum value for it if (d->callChannel->callStateReason().reason == 5) { qDebug() << "Adding notification"; d->missedCalls++; if (!d->callsNotification) { d->callsNotification = new KNotification("callMissed", KNotification::Persistent, nullptr); } d->callsNotification->setComponentName("plasma_dialer"); d->callsNotification->setIconName("call-start"); if (d->missedCalls == 1) { d->callsNotification->setTitle(i18n("Missed call from %1", d->callChannel->targetContact()->alias())); d->callsNotification->setText(QTime::currentTime().toString("HH:mm")); } else { d->callsNotification->setTitle(i18n("%1 calls missed", d->missedCalls)); d->callsNotification->setText(i18n("Last call: %1", QTime::currentTime().toString("HH:mm"))); } if (d->missedCalls == 1) { d->callsNotification->sendEvent(); } else { d->callsNotification->update(); } } if (d->callTimer) { d->callTimer->stop(); d->callTimer->deleteLater(); d->callTimer = nullptr; } //if we requested the call, make sure we have a window to show the error (if any) // if (d->callChannel->isRequested()) { // ensureCallWindow(); // } // if (d->callWindow) { // Tp::CallStateReason reason = d->callChannel->callStateReason(); // d->callWindow.data()->setStatus(CallWindow::StatusDisconnected, reason); // // //kill the call manager when the call window is closed, // //after shutting down the channelHandler // connect(d->callWindow.data(), SIGNAL(destroyed()), d->channelHandler, SLOT(shutdown())); // } else { // //missed the call // qCDebug(KTP_CALL_UI) << "missed call"; // delete d->approver.data(); // d->channelHandler->shutdown(); // } break; default: Q_ASSERT(false); } } void CallManager::onCallAccepted() { (void) d->callChannel->accept(); } void CallManager::onCallRejected() { (void) d->callChannel->hangup(Tp::CallStateChangeReasonRejected, TP_QT_ERROR_REJECTED); } void CallManager::onHangUpRequested() { if (d->callChannel && d->callChannel->isValid()) { qDebug() << "Hanging up"; Tp::PendingOperation *op = d->callChannel->hangup(); connect(op, &Tp::PendingOperation::finished, [=]() { if (op->isError()) { qWarning() << "Unable to hang up:" << op->errorMessage(); } // d->callChannel->requestClose(); }); } } void CallManager::ensureCallWindow() { // if (!d->callWindow) { // d->callWindow = new CallWindow(d->callChannel); // d->callWindow.data()->show(); // d->callWindow.data()->setAttribute(Qt::WA_DeleteOnClose); // // connect(d->channelHandler, SIGNAL(contentAdded(CallContentHandler*)), // d->callWindow.data(), SLOT(onContentAdded(CallContentHandler*))); // connect(d->channelHandler, SIGNAL(contentRemoved(CallContentHandler*)), // d->callWindow.data(), SLOT(onContentRemoved(CallContentHandler*))); // // //inform the ui about already existing contents // Q_FOREACH(CallContentHandler *content, d->channelHandler->contents()) { // d->callWindow.data()->onContentAdded(content); // } // } }