You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
13 KiB
368 lines
13 KiB
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqtimer.h>
|
|
#include <tqfile.h>
|
|
|
|
#include <kaboutdata.h>
|
|
#include <kcmdlineargs.h>
|
|
#include <kdebug.h>
|
|
#include <kglobal.h>
|
|
#include <kglobalaccel.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kiconloader.h>
|
|
#include <kaboutapplication.h>
|
|
#include <kaction.h>
|
|
#include <kpopupmenu.h>
|
|
#include <kconfig.h>
|
|
#include <kpassivepopup.h>
|
|
#include <kiconloader.h>
|
|
|
|
#include <apt-front/init.h>
|
|
#include <apt-front/cache/cache.h>
|
|
#include <apt-front/cache/component/packages.h>
|
|
#include <apt-front/predicate/factory.h>
|
|
|
|
#include <adept/utils.h>
|
|
|
|
#include "app.h"
|
|
|
|
using namespace aptFront;
|
|
using namespace cache;
|
|
using namespace utils;
|
|
using namespace adept;
|
|
|
|
TrayWindow::TrayWindow(TQWidget *parent, const char *name)
|
|
: KSystemTray(parent, name), m_updates( 0 )
|
|
{
|
|
setAvailableUpdates( m_updates );
|
|
// actionCollection()->remove( actionCollection()->action( "quit" ) );
|
|
m_quit = KStdAction::quit( TQT_TQOBJECT(this), TQT_SIGNAL( quitSelected() ), actionCollection() );
|
|
m_about = KStdAction::aboutApp( TQT_TQOBJECT(this), TQT_SIGNAL( aboutSelected() ), actionCollection() );
|
|
// setPixmap( loadIcon( u8( "adept_notifier_warning" ) ) );
|
|
}
|
|
|
|
void TrayWindow::contextMenuAboutToShow( KPopupMenu *r ) {
|
|
kdDebug() << "TrayWindow::contextMenu()" << endl;
|
|
r->clear();
|
|
m_about->plug( r );
|
|
m_quit->plug( r );
|
|
}
|
|
|
|
void TrayWindow::resizeEvent ( TQResizeEvent * )
|
|
{
|
|
// Honor Free Desktop specifications that allow for arbitrary system tray icon sizes
|
|
setPixmap( m_updates == 0 ?
|
|
loadSizedIcon( u8( "adept_notifier_ok" ), width() ) :
|
|
loadSizedIcon( u8( "adept_notifier_warning" ), width() ) );
|
|
|
|
if ( m_updates == 0 )
|
|
hide();
|
|
else
|
|
show();
|
|
}
|
|
|
|
void TrayWindow::setAvailableUpdates( int n )
|
|
{
|
|
m_updates = n;
|
|
kdDebug() << "TrayWindow obtained " << n << endl;
|
|
|
|
setPixmap( m_updates == 0 ?
|
|
loadSizedIcon( u8( "adept_notifier_ok" ), width() ) :
|
|
loadSizedIcon( u8( "adept_notifier_warning" ), width() ) );
|
|
|
|
if ( m_updates == 0 )
|
|
hide();
|
|
else
|
|
show();
|
|
|
|
TQToolTip::remove(this);
|
|
TQToolTip::add(this, n == 0 ? i18n( "No updates needed." )
|
|
: i18n( "There is %n updated package available",
|
|
"There are %n updated packages available", n ) );
|
|
}
|
|
|
|
void TrayWindow::mouseReleaseEvent(TQMouseEvent *ev)
|
|
{
|
|
if (ev->button() == Qt::LeftButton)
|
|
emit clicked();
|
|
KSystemTray::mouseReleaseEvent(ev);
|
|
}
|
|
|
|
void ApportTrayWindow::mousePressEvent(TQMouseEvent *ev)
|
|
{
|
|
emit clicked();
|
|
hide();
|
|
}
|
|
|
|
void ApportTrayWindow::resizeEvent ( TQResizeEvent * )
|
|
{
|
|
// Honor Free Desktop specifications that allow for arbitrary system tray icon sizes
|
|
setPixmap( loadSizedIcon(u8("apport"), width()) );
|
|
}
|
|
|
|
void RebootTrayWindow::mousePressEvent(TQMouseEvent *ev)
|
|
{
|
|
emit clicked();
|
|
}
|
|
|
|
void RebootTrayWindow::resizeEvent ( TQResizeEvent * )
|
|
{
|
|
// Honor Free Desktop specifications that allow for arbitrary system tray icon sizes
|
|
setPixmap( loadSizedIcon(u8("reload"), width()) );
|
|
}
|
|
|
|
NotifierApp::NotifierApp(bool allowStyles, bool GUIenabled)
|
|
: KUniqueApplication(allowStyles, GUIenabled),
|
|
m_tray( 0 )
|
|
{
|
|
sharedConfig()->setGroup( "General" );
|
|
m_okAutostart = sharedConfig()->readBoolEntry( "Autostart", true );
|
|
m_timer = new TQTimer( this );
|
|
m_tray = new TrayWindow( 0, 0 );
|
|
m_tray->show();
|
|
m_rebootRequired = false;
|
|
m_rebootShown = false;
|
|
|
|
aptFront::init();
|
|
|
|
fileUpdated( "/var/cache/apt/pkglist.bin", m_updateStamp );
|
|
// fileUpdated( "/var/lib/apt/periodic/update-stamp", m_updateStamp );
|
|
fileUpdated( "/var/lib/dpkg/status", m_statusStamp );
|
|
|
|
m_tray->setAvailableUpdates( upgradable() );
|
|
|
|
connect( m_tray, TQT_SIGNAL( clicked() ), this, TQT_SLOT( clicked() ) );
|
|
// connect( m_tray, TQT_SIGNAL( quitSelected() ), this, TQT_SLOT( quit() ) );
|
|
connect( m_tray, TQT_SIGNAL( quitSelected() ), this, TQT_SLOT( askQuit() ) );
|
|
connect( m_tray, TQT_SIGNAL( aboutSelected() ), this, TQT_SLOT( about() ) );
|
|
connect( m_timer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( checkUpdates() ) );
|
|
m_timer->start( 1000*5 ); // 5 secs now, used to be 60
|
|
if ( !m_okAutostart ) {
|
|
int r = KMessageBox::questionYesNo(
|
|
m_tray, i18n( "You disabled automatic startup of Adept Notifier last time "
|
|
"you quit the application. "
|
|
"Do you want to start Adept Notifier next time you log in?" ),
|
|
i18n( "Automatic Startup" ),
|
|
KGuiItem( i18n( "Start" ) ), KGuiItem( i18n( "Don't Start" ) ),
|
|
u8( "enableAutostart" ) );
|
|
if ( r == KMessageBox::Yes ) {
|
|
sharedConfig()->setGroup( "General" );
|
|
sharedConfig()->writeEntry( "Autostart", true );
|
|
m_okAutostart = true;
|
|
}
|
|
}
|
|
|
|
// if apport crash handler it installed, watch for crash reports appearing and run
|
|
// the apport frontend when they do
|
|
bool runApport = sharedConfig()->readBoolEntry( "Apport", true );
|
|
if ( TQFile::exists(TQString("/usr/share/apport/apport-qt")) && runApport ) {
|
|
m_dirWatch = new KDirWatch(TQT_TQOBJECT(this));
|
|
m_dirWatch->addDir(TQString("/var/crash"));
|
|
connect( m_dirWatch, TQT_SIGNAL( dirty(const TQString&) ), this, TQT_SLOT( crashWatcher() ) );
|
|
|
|
KProcess *proc = new KProcess;
|
|
*proc << "/usr/share/apport/apport-checkreports";
|
|
connect( proc, TQT_SIGNAL(processExited(KProcess*)), this, TQT_SLOT(apportCheckExited(KProcess*)) );
|
|
proc->start(KProcess::Block);
|
|
|
|
if (m_crashes) {
|
|
ApportTrayWindow* crashApplet = new ApportTrayWindow;
|
|
crashApplet->setPixmap( crashApplet->loadSizedIcon(u8("apport"), crashApplet->width()) );
|
|
TQString crashMessage = i18n("An application has crashed on your "
|
|
"system (now or in the past).\n"
|
|
"Click to "
|
|
"display details. "
|
|
);
|
|
TQToolTip::add(crashApplet, crashMessage);
|
|
connect( crashApplet, TQT_SIGNAL(clicked()), this, TQT_SLOT(crashWatcher()) );
|
|
crashApplet->show();
|
|
TQPixmap icon = BarIcon(u8("apport"));
|
|
KPassivePopup::message(i18n("Crash Handler"), crashMessage, icon, crashApplet);
|
|
}
|
|
}
|
|
// if reboot-required is installed watch for reboot-required and dpkg-run-stamp
|
|
if ( TQFile::exists(TQString("/usr/share/update-notifier/notify-reboot-required")) ) {
|
|
m_rebootDirWatch = new KDirWatch(TQT_TQOBJECT(this));
|
|
m_rebootDirWatch->addFile(TQString("/var/run/reboot-required"));
|
|
m_rebootDirWatch->addFile(TQString("/var/lib/update-notifier/dpkg-run-stamp"));
|
|
connect( m_rebootDirWatch, TQT_SIGNAL( dirty(const TQString&) ), this, TQT_SLOT( rebootWatcher(const TQString&) ) );
|
|
|
|
}
|
|
}
|
|
|
|
void NotifierApp::crashWatcher() {
|
|
// find out if there are system crash reports first, if there are run it as root
|
|
KProcess *proc = new KProcess;
|
|
*proc << "/usr/share/apport/apport-checkreports";
|
|
*proc << "--system";
|
|
connect( proc, TQT_SIGNAL(processExited(KProcess*)), this, TQT_SLOT(apportCheckExited(KProcess*)) );
|
|
proc->start(KProcess::Block);
|
|
|
|
if (m_crashes) {
|
|
KProcess *proc2 = new KProcess;
|
|
*proc2 << "kdesu" << "/usr/share/apport/apport-qt";
|
|
proc2->start(KProcess::DontCare);
|
|
} else {
|
|
KShellProcess *proc2 = new KShellProcess;
|
|
*proc2 << "sleep 1; /usr/share/apport/apport-qt"; //needs a seconds delay else we're too fast for apport
|
|
proc2->start(KProcess::DontCare);
|
|
}
|
|
}
|
|
|
|
void NotifierApp::apportCheckExited(KProcess* proc) {
|
|
if (proc->exitStatus() == 0) {
|
|
m_crashes = true;
|
|
} else {
|
|
m_crashes = false;
|
|
}
|
|
}
|
|
|
|
void NotifierApp::rebootWatcher(const TQString& path) {
|
|
kdDebug() << "NotifierApp::rebootWatcher: " << path << endl;
|
|
|
|
if (path == TQString("/var/run/reboot-required")) {
|
|
m_rebootRequired = true;
|
|
}
|
|
|
|
if (path == TQString("/var/lib/update-notifier/dpkg-run-stamp") && m_rebootRequired && !m_rebootShown) {
|
|
|
|
RebootTrayWindow* rebootApplet = new RebootTrayWindow;
|
|
rebootApplet->setPixmap( rebootApplet->loadSizedIcon(u8("reload"), rebootApplet->width()) );
|
|
|
|
TQString rebootMessage = i18n("In order to complete the update your system needs to be restarted.");
|
|
TQToolTip::add(rebootApplet, rebootMessage);
|
|
connect( rebootApplet, TQT_SIGNAL(clicked()), this, TQT_SLOT(rebootClicked()) );
|
|
rebootApplet->show();
|
|
TQPixmap icon = BarIcon(u8("reload"));
|
|
KPassivePopup::message(i18n("Reboot Required"), rebootMessage, icon, rebootApplet);
|
|
m_rebootShown = true;
|
|
}
|
|
|
|
}
|
|
|
|
void NotifierApp::rebootClicked() {
|
|
kdDebug() << "NotifierApp::rebootClicked" << endl;
|
|
if (KMessageBox::questionYesNo(0, TQString("In order to complete the update your system needs to be restarted."), TQString("Restart Require")) == KMessageBox::Yes) {
|
|
kdDebug() << "NotifierApp::rebootClicked yes!" << endl;
|
|
KProcess *proc = new KProcess;
|
|
*proc << "/usr/bin/dcop";
|
|
*proc << "ksmserver" << "ksmserver" << "logout" << "0" << "1" << "2"; // 0 1 2 == ShutdownConfirmNo ShutdownTypeReboot ShutdownModeForceNow
|
|
proc->start();
|
|
}
|
|
}
|
|
|
|
void NotifierApp::askQuit() {
|
|
if ( m_okAutostart ) {
|
|
int r = KMessageBox::questionYesNoCancel(
|
|
m_tray, i18n( "Do you want to start Adept Notifier next time you log in?" ),
|
|
i18n( "Automatic Startup" ),
|
|
KGuiItem( i18n( "Start" ) ), KGuiItem( i18n( "Don't Start" ) ) );
|
|
if ( r == KMessageBox::Cancel )
|
|
return;
|
|
if ( r == KMessageBox::No ) {
|
|
sharedConfig()->setGroup( "General" );
|
|
sharedConfig()->writeEntry( "Autostart", false );
|
|
}
|
|
}
|
|
exit( 0 );
|
|
|
|
}
|
|
|
|
bool NotifierApp::fileUpdated( const char *f, time_t &stamp ) {
|
|
time_t old = stamp;
|
|
struct stat s;
|
|
::stat( f, &s );
|
|
stamp = s.st_mtime;
|
|
if ( stamp > old )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
int NotifierApp::upgradable() {
|
|
try {
|
|
kdDebug() << "checking cache for upgradable packages..." << endl;
|
|
cache::Cache &c = cache::Global::get();
|
|
c.open( Cache::OpenReadOnly
|
|
| Cache::OpenPackages
|
|
| Cache::OpenState );
|
|
|
|
kdDebug() << "cache opened, listing..." << endl;
|
|
Range< entity::Package > r = range( c.packages().packagesBegin(),
|
|
c.packages().packagesEnd() );
|
|
kdDebug() << "looking for upgradable packages..." << endl;
|
|
Range< entity::Package > fr = filteredRange(
|
|
r, predicate::Package::member( &entity::Package::isUpgradable ) );
|
|
VectorRange< entity::Package > vr = VectorRange< entity::Package >();
|
|
fr.output( vr );
|
|
kdDebug() << "found " << vr.size() << " upgradable package(s)" << endl;
|
|
int ret = vr.size();
|
|
c.close();
|
|
return ret;
|
|
} catch ( exception::Error e ) {
|
|
kdDebug() << "error checking cache for upgradable packages..." << endl;
|
|
kdDebug() << "what: " << e.message() << endl;
|
|
} catch ( std::exception e ) {
|
|
kdDebug() << "exception checking cache for upgradable packages..." << endl;
|
|
kdDebug() << "what: " << e.what() << endl;
|
|
// XXX error handling
|
|
}
|
|
return true; // we don't know, so assume true (safe)
|
|
}
|
|
|
|
void NotifierApp::checkUpdates() {
|
|
// kdDebug() << "checking updates status" << endl;
|
|
if ( // fileUpdated( "/var/lib/apt/periodic/update-stamp", m_updateStamp )
|
|
fileUpdated( "/var/cache/apt/pkgcache.bin", m_updateStamp )
|
|
|| fileUpdated( "/var/lib/dpkg/status", m_statusStamp ) )
|
|
m_tray->setAvailableUpdates( upgradable() );
|
|
}
|
|
|
|
void NotifierApp::about() {
|
|
KAboutApplication *a = new KAboutApplication( m_tray, "", true );
|
|
a->exec();
|
|
delete a;
|
|
}
|
|
|
|
NotifierApp::~NotifierApp()
|
|
{
|
|
delete m_tray;
|
|
}
|
|
|
|
void NotifierApp::clicked()
|
|
{
|
|
if ( m_tray->updates() == 0 )
|
|
return KMessageBox::information(
|
|
0, i18n( "There are no known updates available." ),
|
|
i18n( "Nothing to do" ) );
|
|
startServiceByDesktopName( u8( "adept_updater" ) );
|
|
}
|
|
|
|
/* void NotifierApp::menuActivated(int id)
|
|
{
|
|
// implement help
|
|
} */
|
|
|
|
const char * DESCRIPTION =
|
|
I18N_NOOP("Adept update notifier utility");
|
|
|
|
/* extern "C" KDE_EXPORT */
|
|
int main(int argc, char *argv[])
|
|
{
|
|
KAboutData about("adept_notifier", I18N_NOOP("Adept Notifier"),
|
|
"2.1 Cruiser",
|
|
DESCRIPTION, KAboutData::License_BSD,
|
|
"Copyright (C) 2005, 2006 Peter Rockai");
|
|
KCmdLineArgs::init(argc, argv, &about);
|
|
NotifierApp::addCmdLineOptions();
|
|
|
|
if (!NotifierApp::start())
|
|
return 0;
|
|
|
|
NotifierApp app;
|
|
app.disableSessionManagement();
|
|
app.exec();
|
|
return 0;
|
|
}
|