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.
adept/adept/notifier/app.cpp

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 << "tdesu" << "/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;
}