File indexing completed on 2024-04-14 05:39:36
0001 // SPDX-License-Identifier: GPL-3.0-or-later 0002 /* 0003 Copyright 2017 - 2023 Martin Koller, kollix@aon.at 0004 0005 This file is part of liquidshell. 0006 0007 liquidshell is free software: you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation, either version 3 of the License, or 0010 (at your option) any later version. 0011 0012 liquidshell is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with liquidshell. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include <OnScreenVolume.hxx> 0022 0023 #include <QDBusConnection> 0024 #include <QDBusConnectionInterface> 0025 #include <QDBusMessage> 0026 #include <QDBusReply> 0027 #include <QDBusServiceWatcher> 0028 #include <QRegularExpression> 0029 #include <QApplication> 0030 #include <QScreen> 0031 #include <QDebug> 0032 0033 #include <KWinCompat.hxx> 0034 #include <KConfig> 0035 #include <KConfigGroup> 0036 0037 //-------------------------------------------------------------------------------- 0038 0039 OnScreenVolume::OnScreenVolume(QWidget *parent) 0040 : QProgressBar(parent) 0041 { 0042 setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); 0043 0044 setFixedSize(400, 40); 0045 hide(); 0046 0047 KWindowSystem::setState(winId(), NET::KeepAbove); 0048 KWindowSystem::setType(winId(), NET::Dock); 0049 KWinCompat::setOnAllDesktops(winId(), true); 0050 0051 hideTimer.setInterval(1000); 0052 hideTimer.setSingleShot(true); 0053 connect(&hideTimer, &QTimer::timeout, this, &QWidget::hide); 0054 0055 QDBusConnection::sessionBus() 0056 .connect("org.kde.kmix", "/Mixers", 0057 "org.kde.KMix.MixSet", "masterChanged", 0058 this, SLOT(getMasterMixer())); 0059 0060 if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kmix") ) 0061 { 0062 QDBusServiceWatcher *w = new QDBusServiceWatcher("org.kde.kmix", QDBusConnection::sessionBus(), 0063 QDBusServiceWatcher::WatchForRegistration, this); 0064 connect(w, &QDBusServiceWatcher::serviceRegistered, this, &OnScreenVolume::getMasterMixer); 0065 } 0066 else 0067 getMasterMixer(); 0068 } 0069 0070 //-------------------------------------------------------------------------------- 0071 0072 void OnScreenVolume::getMasterMixer() 0073 { 0074 QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.kmix", "/Mixers", 0075 "org.freedesktop.DBus.Properties", 0076 "GetAll"); 0077 msg << "org.kde.KMix.MixSet"; 0078 0079 QDBusConnection::sessionBus() 0080 .callWithCallback(msg, this, 0081 SLOT(gotMasterMixer(QDBusMessage)), 0082 SLOT(gotMasterMixerError(QDBusError, QDBusMessage))); 0083 } 0084 0085 //-------------------------------------------------------------------------------- 0086 0087 void OnScreenVolume::gotMasterMixerError(QDBusError error, QDBusMessage msg) 0088 { 0089 Q_UNUSED(error) 0090 Q_UNUSED(msg) 0091 0092 if ( retryTimer.interval() == 0 ) 0093 { 0094 // the service could already be registered but no object yet 0095 retryTimer.setInterval(1000); 0096 retryTimer.setSingleShot(true); 0097 connect(&retryTimer, &QTimer::timeout, this, &OnScreenVolume::getMasterMixer); 0098 } 0099 retryTimer.start(); 0100 } 0101 0102 //-------------------------------------------------------------------------------- 0103 0104 void OnScreenVolume::gotMasterMixer(QDBusMessage msg) 0105 { 0106 QDBusReply<QVariantMap> reply = msg; 0107 0108 if ( !reply.isValid() ) 0109 return; 0110 0111 if ( !masterMixer.isEmpty() ) 0112 { 0113 // disconnect previous master mixer 0114 QDBusConnection::sessionBus() 0115 .disconnect("org.kde.kmix", "/Mixers/" + masterMixer, 0116 "org.kde.KMix.Mixer", "controlChanged", 0117 this, SLOT(controlChanged())); 0118 } 0119 0120 masterMixer = reply.value()["currentMasterMixer"].toString(); 0121 masterMixer.replace(QRegularExpression("[^a-zA-Z0-9_]"), "_"); 0122 0123 //qDebug() << __FUNCTION__ << masterMixer; 0124 0125 QDBusConnection::sessionBus() 0126 .connect("org.kde.kmix", "/Mixers/" + masterMixer, 0127 "org.kde.KMix.Mixer", "controlChanged", 0128 this, SLOT(controlChanged())); 0129 } 0130 0131 //-------------------------------------------------------------------------------- 0132 // called when e.g. volume changes but also if currentMasterControl changes 0133 // e.g. bluetooth headset connect/disconnect 0134 0135 void OnScreenVolume::controlChanged() 0136 { 0137 QDBusMessage msg = 0138 QDBusMessage::createMethodCall("org.kde.kmix", "/Mixers", 0139 "org.freedesktop.DBus.Properties", 0140 "Get"); 0141 0142 msg << "org.kde.KMix.MixSet" << "currentMasterControl"; 0143 0144 QDBusConnection::sessionBus().callWithCallback(msg, this, SLOT(gotCurrentControl(QDBusMessage))); 0145 } 0146 0147 //-------------------------------------------------------------------------------- 0148 0149 void OnScreenVolume::gotCurrentControl(QDBusMessage reply) 0150 { 0151 if ( reply.type() == QDBusMessage::ErrorMessage ) 0152 return; 0153 0154 QString masterControl = reply.arguments()[0].value<QDBusVariant>().variant().toString(); 0155 masterControl.replace(QRegularExpression("[^a-zA-Z0-9_]"), "_"); 0156 0157 //qDebug() << __FUNCTION__ << masterMixer << masterControl; 0158 0159 QDBusMessage msg = 0160 QDBusMessage::createMethodCall("org.kde.kmix", "/Mixers/" + masterMixer + '/' + masterControl, 0161 "org.freedesktop.DBus.Properties", 0162 "Get"); 0163 0164 msg << "org.kde.KMix.Control" << "volume"; 0165 0166 QDBusConnection::sessionBus().callWithCallback(msg, this, SLOT(volumeChanged(QDBusMessage))); 0167 } 0168 0169 //-------------------------------------------------------------------------------- 0170 0171 void OnScreenVolume::volumeChanged(QDBusMessage reply) 0172 { 0173 if ( reply.type() == QDBusMessage::ErrorMessage ) 0174 return; 0175 0176 if ( reply.arguments().count() && (reply.arguments()[0].value<QDBusVariant>().variant().toInt() != value()) ) 0177 { 0178 setValue(reply.arguments()[0].value<QDBusVariant>().variant().toInt()); 0179 0180 if ( !isVisible() ) // just always once before showing 0181 { 0182 KConfig config("kmixrc"); 0183 KConfigGroup group = config.group("Global"); 0184 if ( !group.readEntry("showOSD", true) ) 0185 return; 0186 } 0187 0188 move((QApplication::primaryScreen()->size().width() - width()) / 2, 0189 QApplication::primaryScreen()->size().height() * 0.8); 0190 0191 show(); 0192 hideTimer.start(); 0193 } 0194 } 0195 0196 //--------------------------------------------------------------------------------