Compare commits

..

13 Commits

Author SHA1 Message Date
Aaron Rainbolt
217d71ba43
Change debconf frontend to noninteractive 2024-12-24 13:52:18 -06:00
Aaron Rainbolt
fed35d17a8 Release to Oracular. 2024-08-15 16:58:55 -05:00
Aaron Rainbolt
d418d68a29 Port to Qt6. 2024-08-13 19:33:21 -05:00
978e9bfa5f Take out of beta testing, use D-Bus rather than drop files. 2024-03-25 16:18:11 -05:00
953908831e Fix notification bug, switch to beta testing 2024-03-06 22:13:45 -06:00
9a2b5b6450 Sync with archive 2024-02-12 17:32:51 -06:00
Aaron Rainbolt
7daa5ffbb7 Minor UI tweaks 2024-02-02 12:29:44 -05:00
64ba4f8a12 Update README.md 2024-02-02 11:10:36 -06:00
9a41afd011 Major bugfixes to do-release-upgrade code 2024-02-02 11:09:29 -06:00
Aaron Rainbolt
86c512a2ff Finish do-release-upgrade support (untested) 2024-02-01 10:44:01 -05:00
Aaron Rainbolt
d71a36f0ef More do-release-upgrade progress 2024-01-30 13:43:06 -05:00
Aaron Rainbolt
1821373141 ignore a build folder in gitignore 2024-01-29 22:17:12 -05:00
Aaron Rainbolt
2a7548e4ce Add new release detection code (not very user-visible yet) 2024-01-29 21:38:08 -05:00
25 changed files with 811 additions and 153 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
CMakeLists.txt.user CMakeLists.txt.user
build

View File

@ -9,8 +9,7 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools) find_package(Qt6 REQUIRED COMPONENTS Widgets DBus LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)
set(TS_FILES set(TS_FILES
src/translations/lubuntu-update_en_US.ts src/translations/lubuntu-update_en_US.ts
@ -36,16 +35,22 @@ set(PROJECT_SOURCES
src/conffilehandlerdialog.h src/conffilehandlerdialog.h
src/conffilehandlerdialog.cpp src/conffilehandlerdialog.cpp
src/conffilehandlerdialog.ui src/conffilehandlerdialog.ui
src/ipcfilewatcher.h src/releaseupgradewindow.h
src/ipcfilewatcher.cpp src/releaseupgradewindow.cpp
src/releaseupgradewindow.ui
src/upgradedelaywindow.h
src/upgradedelaywindow.cpp
src/upgradedelaywindow.ui
src/windowshowwatcher.h
src/windowshowwatcher.cpp
${TS_FILES} ${TS_FILES}
) )
set(TRANSLATION_RESOURCES "src/translations.qrc") set(TRANSLATION_RESOURCES "src/translations.qrc")
configure_file(${TRANSLATION_RESOURCES} translations.qrc COPYONLY) configure_file(${TRANSLATION_RESOURCES} translations.qrc COPYONLY)
qt5_add_translation(QM_FILES ${TS_FILES}) qt6_add_translation(QM_FILES ${TS_FILES})
qt5_add_resources(QM_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc) qt6_add_resources(QM_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
add_custom_target(translations ALL DEPENDS ${QM_FILES}) add_custom_target(translations ALL DEPENDS ${QM_FILES})
@ -57,7 +62,9 @@ add_executable(lubuntu-update
add_dependencies(lubuntu-update translations) add_dependencies(lubuntu-update translations)
target_link_libraries(lubuntu-update PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) target_link_libraries(lubuntu-update PRIVATE
Qt6::Widgets
Qt6::DBus)
install(TARGETS lubuntu-update install(TARGETS lubuntu-update
BUNDLE DESTINATION . BUNDLE DESTINATION .

View File

@ -2,7 +2,7 @@
Copyright (c) 2023-2024 Lubuntu Contributors. Licensed under the GNU General Public License version 2, or (at your option) any later version. Copyright (c) 2023-2024 Lubuntu Contributors. Licensed under the GNU General Public License version 2, or (at your option) any later version.
Build dependencies are Qt 5.15 and cmake, runtime dependencies are apt, apt-get, and diff. Build dependencies are Qt 5.15 and cmake, runtime dependencies are apt, apt-get, curl, and diff.
To build: To build:
@ -20,6 +20,11 @@ It is highly recommended that you use a Lubuntu virtual machine for testing and
Qt Creator is recommended for editing the code. It is present in Ubuntu's official repos and can be installed using `sudo apt install qtcreator`. Qt Creator is recommended for editing the code. It is present in Ubuntu's official repos and can be installed using `sudo apt install qtcreator`.
## Config file format:
There's only one field here:
* nextDoReleaseUpgradeNotify=123456789 - Value is number of seconds since the UNIX epoch. Used to determine when to offer the user an upgrade.
## Missing features ## Missing features
* Double-clicking on a package doesn't show detailed information for it yet. * Double-clicking on a package doesn't show detailed information for it yet.

43
debian/changelog vendored
View File

@ -1,3 +1,46 @@
lubuntu-update-notifier (1.1.1) plucky; urgency=medium
* Switch debconf frontend to noninteractive. (LP: #2091704)
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Tue, 24 Dec 2024 13:51:28 -0600
lubuntu-update-notifier (1.1.0) oracular; urgency=medium
* Port to Qt6.
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Thu, 15 Aug 2024 16:58:41 -0500
lubuntu-update-notifier (1.0.0) noble; urgency=medium
* Change from beta to final release.
* Use D-Bus as a window show trigger rather than clunky drop files, this
will prevent issues if multiple users are logged in at once.
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Mon, 25 Mar 2024 16:15:49 -0500
lubuntu-update-notifier (1.0.0~beta1) noble; urgency=medium
* Change from alpha to beta testing phase, this has been tested for a while
and looks pretty stable so far.
* Wait to start until lxqt-notificationd is present. (LP: #2056379)
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Thu, 07 Mar 2024 04:06:13 +0000
lubuntu-update-notifier (1.0.0~alpha4) noble; urgency=medium
* Fix infinite loop when no eligible new release is available.
* Fix a bug where only the first eligible new release would be considered.
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Fri, 09 Feb 2024 22:26:59 +0000
lubuntu-update-notifier (1.0.0~alpha3) noble; urgency=medium
* New feature release. Notable additions:
- do-release-upgrade support
* Updated runtime dependencies.
-- Aaron Rainbolt <arraybolt3@ubuntu.com> Fri, 02 Feb 2024 11:37:36 -0600
lubuntu-update-notifier (1.0.0~alpha2) noble; urgency=medium lubuntu-update-notifier (1.0.0~alpha2) noble; urgency=medium
* New feature release. Notable additions: * New feature release. Notable additions:

7
debian/control vendored
View File

@ -5,14 +5,15 @@ Maintainer: Lubuntu Developers <lubuntu-devel@lists.ubuntu.com>
Build-Depends: cmake, Build-Depends: cmake,
debhelper-compat (= 13), debhelper-compat (= 13),
lxqt-sudo (>= 1.4.0-0ubuntu2), lxqt-sudo (>= 1.4.0-0ubuntu2),
qtbase5-dev, qt6-base-dev,
qttools5-dev qt6-tools-dev
Standards-Version: 4.6.2 Standards-Version: 4.6.2
Rules-Requires-Root: no Rules-Requires-Root: no
Package: lubuntu-update-notifier Package: lubuntu-update-notifier
Architecture: any Architecture: any
Depends: ${misc:Depends}, Depends: curl,
${misc:Depends},
${shlibs:Depends} ${shlibs:Depends}
Description: Lubuntu's update installer Description: Lubuntu's update installer
Lubuntu Update is an enhanced, modern update installer for the Lubuntu Lubuntu Update is an enhanced, modern update installer for the Lubuntu

1
debian/files vendored Normal file
View File

@ -0,0 +1 @@
lubuntu-update-notifier_1.1.0~ppa1_source.buildinfo admin optional

View File

@ -88,10 +88,10 @@ void AptManager::handleUpdateProcessBuffer()
// yes, this gave me a headache also // yes, this gave me a headache also
if (dlLineMatch.hasMatch()) { // Increments the progress counter for each package downloaded if (dlLineMatch.hasMatch()) { // Increments the progress counter for each package downloaded
internalUpdateProgress++; internalUpdateProgress++;
} else if (line.count() >= 25 && line.left(24) == "Preparing to unpack .../" && numPackagesToPrep != 0) { } else if (line.length() >= 25 && line.left(24) == "Preparing to unpack .../" && numPackagesToPrep != 0) {
internalUpdateProgress++; // Increments the progress counter for each package that is "prepared to unpack" internalUpdateProgress++; // Increments the progress counter for each package that is "prepared to unpack"
numPackagesToPrep--; numPackagesToPrep--;
} else if (line.count() >= 10 && line.left(9) == "Unpacking") { } else if (line.length() >= 10 && line.left(9) == "Unpacking") {
/* /*
* Increments the progress counter for each package that is unpacked * Increments the progress counter for each package that is unpacked
* The package name may be suffixed with ":amd64" or some other * The package name may be suffixed with ":amd64" or some other
@ -109,7 +109,7 @@ void AptManager::handleUpdateProcessBuffer()
internalUpdateProgress++; internalUpdateProgress++;
} }
} }
} else if (line.count() >= 11 && line.left(10) == "Setting up") { } else if (line.length() >= 11 && line.left(10) == "Setting up") {
QStringList parts = line.split(' '); QStringList parts = line.split(' ');
QString packageName; QString packageName;
if (parts.count() >= 3) { if (parts.count() >= 3) {
@ -118,7 +118,7 @@ void AptManager::handleUpdateProcessBuffer()
internalUpdateProgress++; internalUpdateProgress++;
} }
} }
} else if (line.count() >= 9 && line.left(8) == "Removing") { } else if (line.length() >= 9 && line.left(8) == "Removing") {
QStringList parts = line.split(' '); QStringList parts = line.split(' ');
QString packageName; QString packageName;
if (parts.count() >= 2) { if (parts.count() >= 2) {
@ -136,7 +136,7 @@ void AptManager::handleUpdateProcessBuffer()
} }
aptProcess->readLine(lineBuf, 2048); aptProcess->readLine(lineBuf, 2048);
QString confLine = QString(lineBuf); QString confLine = QString(lineBuf);
confLine = confLine.left(confLine.count() - 2); confLine = confLine.left(confLine.length() - 2);
if (confLine == "Lubuntu Update !!! CONFIGURATION FILE LIST END") { if (confLine == "Lubuntu Update !!! CONFIGURATION FILE LIST END") {
emit conffileListReady(conffileList); // this triggers the main window to show the conffile handler window emit conffileListReady(conffileList); // this triggers the main window to show the conffile handler window
break; break;
@ -144,6 +144,15 @@ void AptManager::handleUpdateProcessBuffer()
conffileList.append(confLine); conffileList.append(confLine);
} }
} }
} else if (line == "Lubuntu Update !!! NEW RELEASE\r\n") {
// Same busy-wait technique, but here we're just getting one extra line, the release code.
while (!aptProcess->canReadLine()) {
QThread::msleep(20);
}
aptProcess->readLine(lineBuf, 2048);
QString releaseCode = QString(lineBuf);
releaseCode = releaseCode.left(releaseCode.length() - 2);
emit newRelease(releaseCode);
} }
double percentageDone = (static_cast<double>(internalUpdateProgress) / (((internalUpdateInfo[0].count() + internalUpdateInfo[1].count()) * 4) + internalUpdateInfo[2].count())) * 100; double percentageDone = (static_cast<double>(internalUpdateProgress) / (((internalUpdateInfo[0].count() + internalUpdateInfo[1].count()) * 4) + internalUpdateInfo[2].count())) * 100;
@ -237,7 +246,7 @@ QList<QStringList> AptManager::getUpdateInfo()
* spaces, we know we're no longer reading a package list. * spaces, we know we're no longer reading a package list.
*/ */
if (stdoutLine.count() < 3 || stdoutLine.left(2) != " ") { if (stdoutLine.length() < 3 || stdoutLine.left(2) != " ") {
gettingInstallPackages = false; gettingInstallPackages = false;
gettingUpgradePackages = false; gettingUpgradePackages = false;
gettingUninstallPackages = false; gettingUninstallPackages = false;
@ -308,7 +317,7 @@ QStringList AptManager::getSecurityUpdateList()
QString distroLine; QString distroLine;
while (distroFinder.readLineInto(&distroLine)) { while (distroFinder.readLineInto(&distroLine)) {
// The line has to be at least 18 characters long - 16 for the string "DISTRIB_CODENAME", one for the = sign, and one for a codename with a length of at least one. // The line has to be at least 18 characters long - 16 for the string "DISTRIB_CODENAME", one for the = sign, and one for a codename with a length of at least one.
if (distroLine.count() >= 18 && distroLine.left(16) == "DISTRIB_CODENAME") { if (distroLine.length() >= 18 && distroLine.left(16) == "DISTRIB_CODENAME") {
QStringList distroParts = distroLine.split('='); QStringList distroParts = distroLine.split('=');
if (distroParts.count() >= 2) { if (distroParts.count() >= 2) {
distroName = distroParts[1]; distroName = distroParts[1];

View File

@ -28,6 +28,7 @@ signals:
void progressUpdated(int progress); void progressUpdated(int progress);
void logLineReady(QString logLine); void logLineReady(QString logLine);
void conffileListReady(QStringList conffileList); void conffileListReady(QStringList conffileList);
void newRelease(QString code);
private slots: private slots:
void handleUpdateProcessBuffer(); void handleUpdateProcessBuffer();

View File

@ -1,38 +0,0 @@
#include "ipcfilewatcher.h"
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QFileSystemWatcher>
#include <QDebug>
IPCFileWatcher::IPCFileWatcher(QObject *parent)
: QObject{parent}
{
QDir targetDir("/dev/shm/lubuntu-update");
bool couldRemove = targetDir.removeRecursively();
if (!couldRemove) {
qCritical() << "Could not clear IPC directory. Ensure that /dev/shm and /dev/shm/lubuntu-update are world-readable and world-writable.";
initFailed = true;
return;
}
targetDir.mkdir("/dev/shm/lubuntu-update");
QFileSystemWatcher *watcher = new QFileSystemWatcher(QStringList() << "/dev/shm/lubuntu-update");
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &IPCFileWatcher::checkForShowWindowFile);
initFailed = false;
}
bool IPCFileWatcher::didInitFail()
{
return initFailed;
}
void IPCFileWatcher::checkForShowWindowFile()
{
QFile flagFile("/dev/shm/lubuntu-update/lubuntu-update-show-win");
if (flagFile.exists()) {
flagFile.remove();
emit showWindowFlagDetected();
}
}

View File

@ -1,22 +0,0 @@
#ifndef IPCFILEWATCHER_H
#define IPCFILEWATCHER_H
#include <QObject>
class IPCFileWatcher : public QObject
{
Q_OBJECT
public:
explicit IPCFileWatcher(QObject *parent = nullptr);
bool didInitFail();
signals:
void showWindowFlagDetected();
private:
bool initFailed;
void checkForShowWindowFile();
};
#endif // IPCFILEWATCHER_H

View File

@ -4,6 +4,43 @@
set -e set -e
export LC_ALL='C' export LC_ALL='C'
# Returns 0 if the release is supported, 1 if unsupported, 2 if if didn't exist at all, and 3 if something went wrong.
isReleaseSupported () {
releaseYear="${1:-}";
releaseMonth="${2:-}";
metaReleaseStr="${3:-}";
if [ -z "$releaseYear" ]; then
echo '! ! ! releaseYear is blank';
return 3;
elif [ -z "$releaseMonth" ]; then
echo '! ! ! releaseMonth is blank';
return 3;
elif [ -z "$metaReleaseStr" ]; then
echo '! ! ! metaReleaseStr is blank';
return 3;
fi
releaseCode="$releaseYear.$releaseMonth";
scanForSupported='n';
while IFS= read -r line || [[ -n $line ]]; do
if [[ "$line" =~ $releaseCode ]]; then
scanForSupported='y';
fi
if [ "$scanForSupported" = 'y' ]; then
if [[ "$line" =~ Supported ]]; then
if [ "$(echo "$line" | cut -d':' -f2 | tail -c+2)" = '0' ]; then
return 1;
else
return 0;
fi
fi
fi
done < <(printf '%s' "$metaReleaseStr")
return 2;
}
if [ "$1" = 'pkgver' ]; then if [ "$1" = 'pkgver' ]; then
shift shift
while [ "$1" != '' ]; do while [ "$1" != '' ]; do
@ -29,66 +66,128 @@ elif [ "$1" = 'doupdate' ]; then
dpkg --configure -a dpkg --configure -a
# Run the real update # Run the real update
DEBIAN_FRONTEND='kde' apt-get -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' -o Apt::Color='0' -o Dpkg::Use-Pty='0' -y dist-upgrade |& tee /run/lubuntu-update-apt-log DEBIAN_FRONTEND='noninteractive' apt-get -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' -o Apt::Color='0' -o Dpkg::Use-Pty='0' -y dist-upgrade |& tee /run/lubuntu-update-apt-log
# Find all the conffiles # Find all the conffiles
doConffiles='y';
mapfile conffileRawList <<< "$(grep -P "^Configuration file \'.*\'$" '/run/lubuntu-update-apt-log')" mapfile conffileRawList <<< "$(grep -P "^Configuration file \'.*\'$" '/run/lubuntu-update-apt-log')"
if [ "$(echo "${conffileRawList[0]}" | head -c1)" != 'C' ]; then # Empty or invalid list, we're done if [ "$(echo "${conffileRawList[0]}" | head -c1)" != 'C' ]; then # Empty or invalid list, we're done
exit 0 doConffiles='n';
fi fi
conffileList=() if [ "$doConffiles" = 'y' ]; then
counter=0 conffileList=()
while [ "$counter" -lt "${#conffileRawList[@]}" ]; do counter=0
# Cut off "Configuration file '" from the start and "'" plus a couple trailing characters from the end while [ "$counter" -lt "${#conffileRawList[@]}" ]; do
conffileList[counter]="$(echo "${conffileRawList[$counter]}" | tail -c+21 | head -c-3)" # Cut off "Configuration file '" from the start and "'" plus a couple trailing characters from the end
counter=$((counter+1)) conffileList[counter]="$(echo "${conffileRawList[$counter]}" | tail -c+21 | head -c-3)"
done counter=$((counter+1))
done
echo "Lubuntu Update !!! CONFIGURATION FILE LIST START"; echo "Lubuntu Update !!! CONFIGURATION FILE LIST START";
counter=0 counter=0
while [ "$counter" -lt "${#conffileList[@]}" ]; do while [ "$counter" -lt "${#conffileList[@]}" ]; do
echo "${conffileList[$counter]}" echo "${conffileList[$counter]}"
counter=$((counter+1)) counter=$((counter+1))
done done
echo "Lubuntu Update !!! CONFIGURATION FILE LIST END"; echo "Lubuntu Update !!! CONFIGURATION FILE LIST END";
# If we make it this far, there were conffiles to deal with # If we make it this far, there were conffiles to deal with
breakLoop='no' breakLoop='no'
gotCommand='no' gotCommand='no'
commandName='' commandName=''
while [ "$breakLoop" = 'no' ]; do while [ "$breakLoop" = 'no' ]; do
read -r inputVal read -r inputVal
if [ "$gotCommand" = 'no' ]; then if [ "$gotCommand" = 'no' ]; then
if [ "$inputVal" = 'done' ]; then if [ "$inputVal" = 'done' ]; then
breakLoop='yes' breakLoop='yes'
else
commandName="$inputVal"
gotCommand='yes'
fi
else else
commandName="$inputVal" if [ "$commandName" = 'replace' ]; then # Replace an existing file
gotCommand='yes' counter=0
while [ "$counter" -lt "${#conffileList[@]}" ]; do
if [ "$inputVal" = "${conffileList[$counter]}" ]; then
mv "$inputVal.dpkg-dist" "$inputVal"
break
fi
counter=$((counter+1))
done
elif [ "$commandName" = 'keep' ]; then # Keep an existing file
counter=0
while [ "$counter" -lt "${#conffileList[@]}" ]; do
if [ "$inputVal" = "${conffileList[$counter]}" ]; then
rm "$inputVal.dpkg-dist"
break
fi
counter=$((counter+1))
done
fi
gotCommand='no'
fi fi
done
fi
echo 'Checking release status...'
releaseCode="$(cat /etc/lsb-release | grep "DISTRIB_RELEASE" | cut -d'=' -f2)";
releaseYear="$(cut -d'.' -f1 <<< "$releaseCode")";
releaseMonth="$(cut -d'.' -f2 <<< "$releaseCode")";
metaReleaseData="$(curl https://changelogs.ubuntu.com/meta-release)";
#nextReleaseMonth='';
#nextReleaseYear='';
#nextLTSReleaseMonth='';
#nextLTSReleaseYear='';
while true; do
if ((releaseMonth == 4)); then
releaseMonth='10';
else else
if [ "$commandName" = 'replace' ]; then # Replace an existing file releaseMonth='04';
counter=0 ((releaseYear++));
while [ "$counter" -lt "${#conffileList[@]}" ]; do fi
if [ "$inputVal" = "${conffileList[$counter]}" ]; then releaseSupportedResult="$(isReleaseSupported "$releaseYear" "$releaseMonth" "$metaReleaseData"; echo "$?")";
mv "$inputVal.dpkg-dist" "$inputVal" if [ "$releaseSupportedResult" = '0' ]; then
break echo 'Lubuntu Update !!! NEW RELEASE';
fi echo "$releaseYear.$releaseMonth";
counter=$((counter+1)) elif [ "$releaseSupportedResult" = '2' ]; then
done break;
elif [ "$commandName" = 'keep' ]; then # Keep an existing file
counter=0
while [ "$counter" -lt "${#conffileList[@]}" ]; do
if [ "$inputVal" = "${conffileList[$counter]}" ]; then
rm "$inputVal.dpkg-dist"
break
fi
counter=$((counter+1))
done
fi
gotCommand='no'
fi fi
done done
# if ((releaseMonth == 4)); then
# nextReleaseMonth=$((releaseMonth + 6));
# nextReleaseYear="$releaseYear";
# if (((releaseYear % 2) == 0)); then
# nextLTSReleaseMonth='04';
# nextLTSReleaseYear=$((releaseYear + 2));
# fi
# else
# nextReleaseMonth="$releaseMonth";
# nextReleaseYear=$((releaseYear + 1));
# fi
#
# if [ -n "$nextLTSReleaseYear" ]; then
# if isReleaseSupported "$nextLTSReleaseYear" "$nextLTSReleaseMonth" "$metaReleaseData"; then
# echo 'Lubuntu Update !!! NEW RELEASE';
# echo "$nextLTSReleaseYear.$nextLTSReleaseMonth";
# fi
# fi
#
# if ! (((nextReleaseYear == nextLTSReleaseYear) && (nextReleaseMonth == nextLTSReleaseMonth))); then
# if isReleaseSupported "$nextReleaseYear" "$nextReleaseMonth" "$metaReleaseData"; then
# echo 'Lubuntu Update !!! NEW RELEASE';
# echo "$nextReleaseYear.$nextReleaseMonth";
# else
# echo "Unsupported release: $nextReleaseYear.$nextReleaseMonth";
# fi
# fi
echo 'Update installation complete.' echo 'Update installation complete.'
elif [ "$1" = 'doReleaseUpgrade' ]; then
do-release-upgrade -m desktop -f DistUpgradeViewKDE;
elif [ "$1" = 'declineReleaseUpgrade' ]; then
sed -i -E 's/^Prompt=(never|lts|normal)$/Prompt=never/' /etc/update-manager/release-upgrades;
fi fi

View File

@ -1,14 +1,38 @@
#include "ipcfilewatcher.h" #include "windowshowwatcher.h"
#include "orchestrator.h" #include "orchestrator.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "conffilehandlerdialog.h" #include "conffilehandlerdialog.h"
#include <QApplication> #include <QApplication>
#include <QDBusConnection>
#include <QDBusError>
#include <QDBusInterface>
#include <QDebug>
#include <QDialog> #include <QDialog>
#include <QLocale> #include <QLocale>
#include <QProcess> #include <QProcess>
#include <QThread>
#include <QTranslator> #include <QTranslator>
/*
* Detects if at least `count` processes that match `procName` are running.
*/
bool detectProc(QString procName, int count)
{
QProcess procDetector;
procDetector.setProgram("/usr/bin/bash");
procDetector.setArguments(QStringList() << "-c" << "ps axo comm | grep " + procName);
procDetector.start();
procDetector.waitForFinished();
QString procDetectResult = procDetector.readAllStandardOutput();
procDetectResult = procDetectResult.trimmed();
QStringList procDetectResultList = procDetectResult.split('\n');
if (procDetectResultList.count() >= count) {
return true;
}
return false;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
@ -23,40 +47,53 @@ int main(int argc, char *argv[])
} }
} }
/* // Connect to D-Bus.
* If Lubuntu Update is already running, create auto dbusConnection = QDBusConnection::sessionBus();
* /dev/shm/lubuntu-update/lubuntu-update-show-win and exit. This will
* trigger the existing process to pop up a window.
*/
QProcess procDetector; /*
procDetector.setProgram("/usr/bin/bash"); * If Lubuntu Update is already running, instruct the running instance to
procDetector.setArguments(QStringList() << "-c" << "ps axo comm | grep lubuntu-update"); * display its window via the D-Bus connection.
procDetector.start(); */
procDetector.waitForFinished(); if (detectProc("lubuntu-update", 2)) {
QString procDetectResult = procDetector.readAllStandardOutput(); auto iface = new QDBusInterface("me.lubuntu.LubuntuUpdate.window", "/", "me.lubuntu.LubuntuUpdate.window", dbusConnection);
procDetectResult = procDetectResult.trimmed(); if (!iface->isValid()) {
QStringList procDetectResultList = procDetectResult.split('\n'); qWarning().noquote() << dbusConnection.lastError().message();
if (procDetectResultList.count() > 1) { return 1;
QFile flagFile("/dev/shm/lubuntu-update/lubuntu-update-show-win"); }
flagFile.open(QFile::WriteOnly); iface->call("showWindow");
flagFile.close();
return 0; return 0;
} }
/*
* Wait to run until lxqt-notificationd is running. This avoids a bug that
* causes notifications to show up in the entirely wrong spot. If it takes
* longer than about 30 seconds to show up, we continue on without it for
* the sake of getting security updates.
*/
for (int i = 0;i < 30;i++) {
// "lxqt-notificati" is intentionally truncated here since that's how it shows up in the output of `ps axo comm`.
if (detectProc("lxqt-notificati", 1)) {
// Wait for it to initialize fully - 3 seconds should be way more than enough
QThread::sleep(3);
break;
} else {
QThread::sleep(1);
}
}
// Don't want the updater to stop just because the user closed it :P // Don't want the updater to stop just because the user closed it :P
a.setQuitOnLastWindowClosed(false); a.setQuitOnLastWindowClosed(false);
/* /*
* IPCFileWatcher just watches the /dev/shm/lubuntu-update folder for the * WindowShowWatcher is a very simple D-Bus service that allow triggering
* creation of a lubuntu-update-show-win file. If it detects it, it * the Lubuntu Update window to be shown. If anything calls "showWindow"
* immediately deletes it and emits a signal. This is then used later to * on this service, Lubuntu Update's window will pop up.
* cause the updater window to pop up.
*/ */
QObject obj;
auto *wsw = new WindowShowWatcher(&obj);
dbusConnection.registerObject("/", &obj);
IPCFileWatcher *p = new IPCFileWatcher(); if (!dbusConnection.registerService("me.lubuntu.LubuntuUpdate.window")) {
if (p->didInitFail()) {
return 1; return 1;
} }
@ -71,10 +108,9 @@ int main(int argc, char *argv[])
* there's no need to do anything with this except create it and then * there's no need to do anything with this except create it and then
* start the event loop. * start the event loop.
*/ */
Orchestrator *o = new Orchestrator(); Orchestrator *o = new Orchestrator();
QObject::connect(p, &IPCFileWatcher::showWindowFlagDetected, o, &Orchestrator::displayUpdater); QObject::connect(wsw, &WindowShowWatcher::showWindowTriggered, o, &Orchestrator::displayUpdater);
/* /*
* This is an artifact from testing the conffile handler window. You can * This is an artifact from testing the conffile handler window. You can

View File

@ -25,6 +25,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(aptManager, &AptManager::progressUpdated, this, &MainWindow::onProgressUpdate); connect(aptManager, &AptManager::progressUpdated, this, &MainWindow::onProgressUpdate);
connect(aptManager, &AptManager::logLineReady, this, &MainWindow::onLogLineReady); connect(aptManager, &AptManager::logLineReady, this, &MainWindow::onLogLineReady);
connect(aptManager, &AptManager::conffileListReady, this, &MainWindow::onConffileListReady); connect(aptManager, &AptManager::conffileListReady, this, &MainWindow::onConffileListReady);
connect(aptManager, &AptManager::newRelease, this, &MainWindow::onNewRelease);
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -143,6 +144,9 @@ void MainWindow::onUpdateCompleted()
ui->progressBar->setVisible(false); ui->progressBar->setVisible(false);
ui->statLabel->setText(tr("Update installation complete.")); ui->statLabel->setText(tr("Update installation complete."));
emit updatesInstalled(); // this tells the orchestrator to hide the tray icon emit updatesInstalled(); // this tells the orchestrator to hide the tray icon
if (releaseCodes.count() > 0) {
handleNewReleases();
}
} }
void MainWindow::onCheckUpdatesCompleted() void MainWindow::onCheckUpdatesCompleted()
@ -175,3 +179,14 @@ void MainWindow::onConffileListReady(QStringList conffileList)
} }
aptManager->doneWithConffiles(); aptManager->doneWithConffiles();
} }
void MainWindow::onNewRelease(QString code)
{
releaseCodes.append(code);
}
void MainWindow::handleNewReleases()
{
emit newReleaseAvailable(releaseCodes);
releaseCodes.clear();
}

View File

@ -26,6 +26,7 @@ public:
signals: signals:
void updatesInstalled(); void updatesInstalled();
void updatesRefreshed(); void updatesRefreshed();
void newReleaseAvailable(QStringList releaseCodes);
protected slots: protected slots:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
@ -39,9 +40,13 @@ private slots:
void onProgressUpdate(int progress); void onProgressUpdate(int progress);
void onLogLineReady(QString logLine); void onLogLineReady(QString logLine);
void onConffileListReady(QStringList conffileList); void onConffileListReady(QStringList conffileList);
void onNewRelease(QString code);
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
AptManager *aptManager; AptManager *aptManager;
QStringList releaseCodes;
void handleNewReleases();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>462</width> <width>473</width>
<height>600</height> <height>600</height>
</rect> </rect>
</property> </property>
@ -37,6 +37,9 @@
</item> </item>
<item> <item>
<widget class="QProgressBar" name="progressBar"> <widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>100</number>
</property>
<property name="value"> <property name="value">
<number>0</number> <number>0</number>
</property> </property>

View File

@ -1,8 +1,13 @@
#include "orchestrator.h" #include "orchestrator.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "aptmanager.h" #include "aptmanager.h"
#include "releaseupgradewindow.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QIcon> #include <QIcon>
#include <QProcess>
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#include <QTimer> #include <QTimer>
@ -12,10 +17,38 @@ Orchestrator::Orchestrator(QObject *parent)
checkTimer = new QTimer(); // every time this triggers, the apt database is checked for new updates checkTimer = new QTimer(); // every time this triggers, the apt database is checked for new updates
trayIcon = new QSystemTrayIcon(); // this is shown to the user to offer updates trayIcon = new QSystemTrayIcon(); // this is shown to the user to offer updates
/*
* Parse the Lubuntu Update config file. It contains two critical pieces
* of info - when the system last offered the user a release upgrade,
* and whether the user has disabled release upgrade notifications.
*/
QFile configFile(QDir::homePath() + "/.config/lubuntu-update.conf");
bool success = configFile.open(QFile::ReadOnly);
if (success) {
char lineBuf[2048];
while (!configFile.atEnd()) {
configFile.readLine(lineBuf, 2048);
QString line(lineBuf);
line = line.trimmed();
QStringList lineParts = line.split("=");
if (lineParts.count() == 2) {
if (lineParts[0] == "nextDoReleaseUpgradeNotify") {
nextUpgradeCheck = QDateTime::fromSecsSinceEpoch(lineParts[1].toLongLong());
} else {
qWarning() << "Unrecognized config line: " << line;
}
} else {
qWarning() << "Wrong number of fields in line: " << line;
}
}
}
configFile.close();
connect(checkTimer, &QTimer::timeout, this, &Orchestrator::checkForUpdates); connect(checkTimer, &QTimer::timeout, this, &Orchestrator::checkForUpdates);
connect(trayIcon, &QSystemTrayIcon::activated, this, &Orchestrator::displayUpdater); connect(trayIcon, &QSystemTrayIcon::activated, this, &Orchestrator::displayUpdater);
connect(&updaterWindow, &MainWindow::updatesInstalled, this, &Orchestrator::handleUpdatesInstalled); connect(&updaterWindow, &MainWindow::updatesInstalled, this, &Orchestrator::handleUpdatesInstalled);
connect(&updaterWindow, &MainWindow::updatesRefreshed, this, &Orchestrator::handleUpdatesRefreshed); connect(&updaterWindow, &MainWindow::updatesRefreshed, this, &Orchestrator::handleUpdatesRefreshed);
connect(&updaterWindow, &MainWindow::newReleaseAvailable, this, &Orchestrator::onNewReleaseAvailable);
checkTimer->start(21600000); // check four times a day, at least one of those times unattended-upgrades should have refreshed the apt database checkTimer->start(21600000); // check four times a day, at least one of those times unattended-upgrades should have refreshed the apt database
@ -65,3 +98,91 @@ void Orchestrator::handleUpdatesRefreshed()
checkForUpdates(); checkForUpdates();
displayUpdater(); displayUpdater();
} }
void Orchestrator::onNewReleaseAvailable(QStringList releaseCodes)
{
// First, determine what kinds of releases the user wants to see.
QFile druTypeFile("/etc/update-manager/release-upgrades");
bool success = druTypeFile.open(QFile::ReadOnly);
QString druType;
if (success) {
char lineBuf[2048];
while (!druTypeFile.atEnd()) {
druTypeFile.readLine(lineBuf, 2048);
QString line(lineBuf);
line = line.trimmed();
if (line == "Prompt=lts") {
druType="lts";
druTypeFile.close();
break;
} else if (line == "Prompt=none") {
// The user has disabled all upgrade prompts.
druTypeFile.close();
return;
} else if (line == "Prompt=normal") {
druType="normal";
druTypeFile.close();
break;
}
}
} else {
druType="normal";
druTypeFile.close();
}
for (int i = 0;i < releaseCodes.count();i++) {
QStringList releaseCodeParts = releaseCodes[i].split('.');
if (releaseCodeParts.count() >= 2) {
int releaseYear = releaseCodeParts[0].toInt();
int releaseMonth = releaseCodeParts[1].toInt();
if (((releaseYear % 2 == 0) && (releaseMonth == 4)) || druType == "normal") {
QDateTime now = QDateTime::currentDateTime();
if (nextUpgradeCheck < now) {
ReleaseUpgradeWindow upgradeWindow(releaseCodes[i]);
upgradeWindow.exec();
if (upgradeWindow.getUpgradeAccepted()) {
doReleaseUpgrade();
} else if (upgradeWindow.getUpgradeDelayStamp() > 0) {
delayReleaseUpgrade(upgradeWindow.getUpgradeDelayStamp());
} else {
declineReleaseUpgrade();
}
break;
}
}
}
}
}
void Orchestrator::doReleaseUpgrade()
{
QProcess druProcess;
druProcess.setProgram("/usr/bin/lxqt-sudo");
druProcess.setArguments(QStringList() << "/usr/libexec/lubuntu-update-backend" << "doReleaseUpgrade");
druProcess.start();
druProcess.waitForFinished(-1);
}
void Orchestrator::delayReleaseUpgrade(qint64 timestamp)
{
QFile configFile(QDir::homePath() + "/.config/lubuntu-update.conf");
bool success = configFile.open(QFile::WriteOnly);
if (success) {
configFile.write("nextDoReleaseUpgradeNotify=");
configFile.write(QString::number(timestamp).toUtf8());
configFile.write("\n");
} else {
qWarning() << "Could not write to " + QDir::homePath() + "/.config/lubuntu-update.conf, check permissions";
}
configFile.close();
nextUpgradeCheck = QDateTime::fromSecsSinceEpoch(timestamp);
}
void Orchestrator::declineReleaseUpgrade()
{
QProcess druProcess;
druProcess.setProgram("/usr/bin/lxqt-sudo");
druProcess.setArguments(QStringList() << "/usr/libexec/lubuntu-update-backend" << "declineReleaseUpgrade");
druProcess.start();
druProcess.waitForFinished(-1);
}

View File

@ -3,11 +3,13 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QDateTime>
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
class QTimer; class QTimer;
class QSystemTrayIcon; class QSystemTrayIcon;
class ReleaseUpgradeWindow;
class Orchestrator : public QObject class Orchestrator : public QObject
{ {
@ -22,12 +24,17 @@ private slots:
void checkForUpdates(); void checkForUpdates();
void handleUpdatesInstalled(); void handleUpdatesInstalled();
void handleUpdatesRefreshed(); void handleUpdatesRefreshed();
void onNewReleaseAvailable(QStringList releaseCodes);
private: private:
QTimer *checkTimer; QTimer *checkTimer;
QSystemTrayIcon *trayIcon; QSystemTrayIcon *trayIcon;
QList<QStringList> updateInfo; QList<QStringList> updateInfo;
MainWindow updaterWindow; MainWindow updaterWindow;
QDateTime nextUpgradeCheck;
void doReleaseUpgrade();
void delayReleaseUpgrade(qint64 timestamp);
void declineReleaseUpgrade();
}; };
#endif // ORCHESTRATOR_H #endif // ORCHESTRATOR_H

View File

@ -0,0 +1,67 @@
#include "releaseupgradewindow.h"
#include "ui_releaseupgradewindow.h"
#include "upgradedelaywindow.h"
#include <QDateTime>
#include <QMessageBox>
ReleaseUpgradeWindow::ReleaseUpgradeWindow(QString releaseCode, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReleaseUpgradeWindow)
{
ui->setupUi(this);
ui->upgradeLabel->setText(tr("An upgrade to Lubuntu %1 is available! Would you like to install this upgrade now?").arg(releaseCode));
code=releaseCode;
connect(ui->upgradeButton, &QPushButton::clicked, this, &ReleaseUpgradeWindow::onUpgradeClicked);
connect(ui->remindButton, &QPushButton::clicked, this, &ReleaseUpgradeWindow::onRemindClicked);
connect(ui->declineButton, &QPushButton::clicked, this, &ReleaseUpgradeWindow::onDeclineClicked);
}
ReleaseUpgradeWindow::~ReleaseUpgradeWindow()
{
delete ui;
}
bool ReleaseUpgradeWindow::getUpgradeAccepted()
{
return upgradeAccepted;
}
qint64 ReleaseUpgradeWindow::getUpgradeDelayStamp()
{
return upgradeDelayStamp;
}
void ReleaseUpgradeWindow::onUpgradeClicked()
{
upgradeAccepted = true;
this->done(0);
}
void ReleaseUpgradeWindow::onRemindClicked()
{
UpgradeDelayWindow delayWindow;
delayWindow.exec();
if (delayWindow.getDelayDays() > 0) {
QDateTime delayDateTime = QDateTime::currentDateTime();
delayDateTime = delayDateTime.addDays(delayWindow.getDelayDays());
upgradeAccepted = false;
upgradeDelayStamp = delayDateTime.toSecsSinceEpoch();
this->done(0);
}
}
void ReleaseUpgradeWindow::onDeclineClicked()
{
QMessageBox confirmDialog;
confirmDialog.setWindowTitle(tr("Lubuntu Update"));
confirmDialog.setText(tr("You have declined the upgrade to Lubuntu %1.\nYou can upgrade manually by following the directions at https://manual.lubuntu.me/stable/D/upgrading.html.").arg(code));
confirmDialog.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
int result = confirmDialog.exec();
if (result == QMessageBox::Ok) {
upgradeDelayStamp = 0;
upgradeAccepted = false;
this->done(0);
}
}

View File

@ -0,0 +1,32 @@
#ifndef RELEASEUPGRADEWINDOW_H
#define RELEASEUPGRADEWINDOW_H
#include <QDialog>
namespace Ui {
class ReleaseUpgradeWindow;
}
class ReleaseUpgradeWindow : public QDialog
{
Q_OBJECT
public:
explicit ReleaseUpgradeWindow(QString releaseCode, QWidget *parent = nullptr);
~ReleaseUpgradeWindow();
bool getUpgradeAccepted();
qint64 getUpgradeDelayStamp();
private slots:
void onUpgradeClicked();
void onRemindClicked();
void onDeclineClicked();
private:
Ui::ReleaseUpgradeWindow *ui;
QString code;
bool upgradeAccepted = false;
qint64 upgradeDelayStamp = 0;
};
#endif // RELEASEUPGRADEWINDOW_H

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ReleaseUpgradeWindow</class>
<widget class="QDialog" name="ReleaseUpgradeWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>393</width>
<height>116</height>
</rect>
</property>
<property name="windowTitle">
<string>Lubuntu Update</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="upgradeLabel">
<property name="text">
<string>upgrade available</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="upgradeButton">
<property name="text">
<string>Upgrade Now</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remindButton">
<property name="text">
<string>Remind me later</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="declineButton">
<property name="text">
<string>Decline Upgrade</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,42 @@
#include "upgradedelaywindow.h"
#include "ui_upgradedelaywindow.h"
UpgradeDelayWindow::UpgradeDelayWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::UpgradeDelayWindow)
{
ui->setupUi(this);
connect(ui->okButton, &QPushButton::clicked, this, &UpgradeDelayWindow::onOkClicked);
connect(ui->cancelButton, &QPushButton::clicked, this, &UpgradeDelayWindow::onCancelClicked);
}
UpgradeDelayWindow::~UpgradeDelayWindow()
{
delete ui;
}
qint64 UpgradeDelayWindow::getDelayDays()
{
return delayDays;
}
void UpgradeDelayWindow::onOkClicked()
{
switch (ui->timeTypeComboBox->currentIndex()) {
case 0: // days
delayDays = ui->timeSpinBox->value();
break;
case 1: // weeks
delayDays = ui->timeSpinBox->value() * 7;
break;
case 2: // months
delayDays = ui->timeSpinBox->value() * 28;
break;
}
this->done(0);
}
void UpgradeDelayWindow::onCancelClicked()
{
this->done(0);
}

28
src/upgradedelaywindow.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef UPGRADEDELAYWINDOW_H
#define UPGRADEDELAYWINDOW_H
#include <QDialog>
namespace Ui {
class UpgradeDelayWindow;
}
class UpgradeDelayWindow : public QDialog
{
Q_OBJECT
public:
explicit UpgradeDelayWindow(QWidget *parent = nullptr);
~UpgradeDelayWindow();
qint64 getDelayDays();
private slots:
void onOkClicked();
void onCancelClicked();
private:
Ui::UpgradeDelayWindow *ui;
qint64 delayDays;
};
#endif // UPGRADEDELAYWINDOW_H

97
src/upgradedelaywindow.ui Normal file
View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UpgradeDelayWindow</class>
<widget class="QDialog" name="UpgradeDelayWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>242</width>
<height>137</height>
</rect>
</property>
<property name="windowTitle">
<string>Lubuntu Update</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;How long would you like to wait before being reminded of the upgrade again?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QSpinBox" name="timeSpinBox"/>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="timeTypeComboBox">
<item>
<property name="text">
<string>Days</string>
</property>
</item>
<item>
<property name="text">
<string>Weeks</string>
</property>
</item>
<item>
<property name="text">
<string>Months</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,6 @@
#include "windowshowwatcher.h"
void WindowShowWatcher::showWindow()
{
emit showWindowTriggered();
}

23
src/windowshowwatcher.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef WINDOWSHOWWATCHER_H
#define WINDOWSHOWWATCHER_H
#include <QObject>
#include <QDBusAbstractAdaptor>
#include <QDBusVariant>
class WindowShowWatcher : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "me.lubuntu.LubuntuUpdate.window")
public:
explicit WindowShowWatcher(QObject *obj) : QDBusAbstractAdaptor(obj) {}
public slots:
void showWindow();
signals:
void showWindowTriggered();
};
#endif // WINDOWSHOWWATCHER_H