#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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( TDEPopupMenu *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() ) ); TDEProcess *proc = new TDEProcess; *proc << "/usr/share/apport/apport-checkreports"; connect( proc, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(apportCheckExited(TDEProcess*)) ); proc->start(TDEProcess::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 TDEProcess *proc = new TDEProcess; *proc << "/usr/share/apport/apport-checkreports"; *proc << "--system"; connect( proc, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(apportCheckExited(TDEProcess*)) ); proc->start(TDEProcess::Block); if (m_crashes) { TDEProcess *proc2 = new TDEProcess; *proc2 << "tdesu" << "/usr/share/apport/apport-qt"; proc2->start(TDEProcess::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(TDEProcess::DontCare); } } void NotifierApp::apportCheckExited(TDEProcess* 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; TDEProcess *proc = new TDEProcess; *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() { TDEAboutApplication *a = new TDEAboutApplication( 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[]) { TDEAboutData about("adept_notifier", I18N_NOOP("Adept Notifier"), "2.1 Cruiser", DESCRIPTION, TDEAboutData::License_BSD, "Copyright (C) 2005, 2006 Peter Rockai"); TDECmdLineArgs::init(argc, argv, &about); NotifierApp::addCmdLineOptions(); if (!NotifierApp::start()) return 0; NotifierApp app; app.disableSessionManagement(); app.exec(); return 0; }