-rw-r--r-- | libopie2/examples/opiecore/onotifydemo/onotifydemo.cpp | 43 | ||||
-rw-r--r-- | libopie2/opiecore/ofilenotify.cpp | 160 | ||||
-rw-r--r-- | libopie2/opiecore/ofilenotify.h | 36 |
3 files changed, 176 insertions, 63 deletions
diff --git a/libopie2/examples/opiecore/onotifydemo/onotifydemo.cpp b/libopie2/examples/opiecore/onotifydemo/onotifydemo.cpp index a8a5717..74a8158 100644 --- a/libopie2/examples/opiecore/onotifydemo/onotifydemo.cpp +++ b/libopie2/examples/opiecore/onotifydemo/onotifydemo.cpp @@ -5,18 +5,19 @@ #include <opie2/olistview.h> #include <opie2/ofilenotify.h> using namespace Opie::Core; using namespace Opie::Ui; /* QT */ +#include <qcheckbox.h> #include <qvbox.h> #include <qhbox.h> #include <qhbuttongroup.h> #include <qvbuttongroup.h> +#include <qmessagebox.h> #include <qpushbutton.h> -#include <qcheckbox.h> class DemoApp : public OApplication { Q_OBJECT public: DemoApp( int argc, char** argv ) : OApplication( argc, argv, "libopie2 notify demo" ) @@ -24,13 +25,16 @@ public: QVBox* vbox = new QVBox(); setMainWidget( vbox ); l = new OListView( vbox ); l->addColumn( "Notification Path" ); - l->addColumn( "Trigger" ); + l->addColumn( "Trigger Type" ); + l->addColumn( "Trigger Mask" ); + l->setColumnAlignment( 1, AlignCenter ); + l->setColumnAlignment( 2, AlignCenter ); QHBox* hbox = new QHBox( vbox ); g2 = new QVButtonGroup( "Specify Trigger Type", hbox ); //QCheckBox* c1 = new QCheckBox( "Multi", g2 ); QCheckBox* c2 = new QCheckBox( "Access", g2 ); @@ -42,12 +46,13 @@ public: g2->insert( c2, Access ); g2->insert( c3, Modify ); g2->insert( c4, Create ); g2->insert( c5, Delete ); g2->insert( c6, Rename ); g2->insert( c7, Attrib ); + connect( g2, SIGNAL( pressed(int) ), this, SLOT( modifierClicked(int) ) ); g1 = new QVButtonGroup( "Add/Remove", hbox ); QPushButton* plus1 = new QPushButton( "Add\n&Single", g1 ); QPushButton* plus2 = new QPushButton( "Add\n&Multi", g1 ); QPushButton* minus = new QPushButton( "&Remove\nIt!", g1 ); g1->insert( plus1, 0 ); @@ -65,49 +70,69 @@ public: showMainWidget( vbox ); } public: void addTrigger( bool multi = false ) { + if ( !m ) + { + QMessageBox::warning( 0, "Add Trigger", "<p>Can't add trigger without at least one selected trigger type</p>", "&Sorry", 0 ); + return; + } + QString filename = OFileDialog::getOpenFileName( OFileSelector::ExtendedAll ); if ( !filename.isEmpty() ) { odebug << "Filename = " << filename << oendl; - new OListViewItem( l, filename, "Modify" ); - + int fntype = m; + if ( multi ) fntype |=(int) Multi; - OFileNotifier::singleShot( filename, this, SLOT( trigger() ) ); + QString modifier = QString().sprintf( " = 0x%08x", fntype ); + new OListViewItem( l, filename, multi ? "MULTI" : "SINGLE", modifier ); + if ( !multi ) + OFileNotification::singleShot( filename, this, SLOT( trigger() ), (OFileNotificationType) fntype ); + else + OFileNotification::singleShot( filename, this, SLOT( trigger() ), (OFileNotificationType) fntype ); } else { odebug << "cancelled." << oendl; } } public slots: - + void modifierClicked( int modifier ) { (int)m ^= modifier; }; void addSingle() { addTrigger(); }; void addMulti() { addTrigger( true ); }; void delTrigger() { - QString filename( "bla" ); - odebug << "Filename = " << filename << oendl; + QListViewItem* item = l->selectedItem(); + if ( !item ) + { + QMessageBox::warning( 0, "Del Trigger", "<p>No trigger selected!</p>", "&Sorry", 0 ); + return; + } + else + { + QString filename( item->text( 0 ) ); + odebug << "Filename = " << filename << oendl; + } } void trigger() { owarn << "FIRE!" << oendl; } private: OListView* l; QButtonGroup* g1; QButtonGroup* g2; - int m; + OFileNotificationType m; }; int main( int argc, char** argv ) { DemoApp* app = new DemoApp( argc, argv ); app->exec(); diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp index 2242570..5e9f97b 100644 --- a/libopie2/opiecore/ofilenotify.cpp +++ b/libopie2/opiecore/ofilenotify.cpp @@ -29,131 +29,199 @@ _;:, .> :=|. This program is free software; you can #include "ofilenotify.h" using namespace Opie::Core; /* OPIE */ /* QT */ +#include <qobject.h> #include <qsignal.h> #include <qintdict.h> #include <qdir.h> /* STD */ #include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> +#ifndef _GNU_SOURCE + #define _GNU_SOURCE + #include <fcntl.h> + #undef _GNU_SOURCE +#else + #include <fcntl.h> +#endif #include <string.h> #include <errno.h> +#include <unistd.h> + +static QIntDict<OFileNotification> notification_list; namespace Opie { namespace Core { -class OFileNotification +OFileNotification::OFileNotification( QObject* parent, const char* name ) + :QObject( parent, name ), _active( false ) { - public: - OFileNotification( QObject* receiver, const char* member, OFileNotificationType type ) : _type( type ) - { - _signal.connect( receiver, member ); - } - ~OFileNotification() - { - } - - void activate() - { - _signal.activate(); - } + qDebug( "OFileNotification::OFileNotification()" ); +} - OFileNotificationType type() - { - return _type; - } - private: - OFileNotificationType _type; - QSignal _signal; -}; +OFileNotification::~OFileNotification() +{ + qDebug( "OFileNotification::~OFileNotification()" ); +} -static QIntDict<OFileNotification> notification_list; +bool OFileNotification::isActive() const +{ + return _active; +} -void OFileNotifier::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) +int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) { + _path = QString::null; + _fd = 0; + if ( _active ) stop(); + int fd = ::open( (const char*) path, O_RDONLY ); if ( fd != -1 ) { if ( notification_list.isEmpty() ) { - OFileNotifier::registerSignalHandler(); + OFileNotification::registerSignalHandler(); } int result = ::fcntl( fd, F_SETSIG, SIGRTMIN ); if ( result == -1 ) { - qWarning( "OFileNotifier::singleShot(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); - return; + qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); + return -1; } + if ( !sshot ) (int) type |= (int) Multi; result = ::fcntl( fd, F_NOTIFY, type ); if ( result == -1 ) { - qWarning( "OFileNotifier::singleShot(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); - return; + qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) path, strerror( errno ) ); + return -1; } - qDebug( "OFileNotifier::singleShot(): Subscribed for changes to %s (fd = %d)", (const char*) path, fd ); - notification_list.insert( fd, new OFileNotification( receiver, member, type ) ); + qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) path, fd, type ); + notification_list.insert( fd, this ); + _type = type; + _path = path; + _fd = fd; + return fd; } else { - qWarning( "OFileNotifier::singleShot(): Error with path '%s': %s.", (const char*) path, strerror( errno ) ); + qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) path, strerror( errno ) ); + return -1; } } -void OFileNotifier::__signalHandler( int sig, siginfo_t *si, void *data ) +void OFileNotification::stop() { - qWarning( "OFileNotifier::__signalHandler(): reached." ); + if ( !_active ) return; + + int result = ::fcntl( _fd, F_NOTIFY, 0 ); + if ( result == -1 ) + { + qWarning( "OFileNotification::stop(): Can't remove subscription to '%s': %s.", (const char*) _path, strerror( errno ) ); + } + else + { + ::close( _fd ); + _type = Single; + _path = QString::null; + _fd = 0; + _active = false; + } +} + + +OFileNotificationType OFileNotification::type() const +{ + return _type; +} + + +QString OFileNotification::path() const +{ + return _path; +} + +int OFileNotification::fileno() const +{ + return _fd; +} + +void OFileNotification::activate() +{ + emit triggered(); + _signal.activate(); +} + + +void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) +{ + OFileNotification* ofn = new OFileNotification(); + ofn->_signal.connect( receiver, member ); + ofn->start( path, true, type ); +} + + +void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) +{ + qWarning( "OFileNotification::__signalHandler(): reached." ); int fd = si->si_fd; OFileNotification* fn = notification_list[fd]; if ( fn ) { fn->activate(); #if 1 if ( !(fn->type() & Multi) ) { - qDebug( "OFileNotifier::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); + qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd ); notification_list.remove( fd ); if ( notification_list.isEmpty() ) { - OFileNotifier::unregisterSignalHandler(); + OFileNotification::unregisterSignalHandler(); } } #endif } else { - qWarning( "OFileNotifier::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); + qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); } } -void OFileNotifier::registerSignalHandler() +bool OFileNotification::registerSignalHandler() { struct sigaction act; - act.sa_sigaction = OFileNotifier::__signalHandler; + act.sa_sigaction = OFileNotification::__signalHandler; ::sigemptyset( &act.sa_mask ); act.sa_flags = SA_SIGINFO; - ::sigaction( SIGRTMIN, &act, NULL ); - qDebug( "OFileNotifier::registerSignalHandler(): done" ); + if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) + { + qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) ); + return false; + } + qDebug( "OFileNotification::registerSignalHandler(): done" ); } -void OFileNotifier::unregisterSignalHandler() +void OFileNotification::unregisterSignalHandler() { struct sigaction act; act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL; - sigemptyset( &act.sa_mask ); - ::sigaction( SIGRTMIN, &act, NULL ); - qDebug( "OFileNotifier::unregisterSignalHandler(): done" ); + ::sigemptyset( &act.sa_mask ); + if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) + if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 ) + { + qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) ); + } + qDebug( "OFileNotification::unregisterSignalHandler(): done" ); } } } diff --git a/libopie2/opiecore/ofilenotify.h b/libopie2/opiecore/ofilenotify.h index 638eb6c..a14842a 100644 --- a/libopie2/opiecore/ofilenotify.h +++ b/libopie2/opiecore/ofilenotify.h @@ -27,14 +27,15 @@ _;:, .> :=|. This program is free software; you can */ #ifndef OFILENOTIFY_H #define OFILENOTIFY_H /* QT */ -#include <qstring.h> #include <qobject.h> +#include <qsignal.h> +#include <qstring.h> /* STD */ #include <signal.h> #include <fcntl.h> namespace Opie { @@ -46,26 +47,45 @@ enum OFileNotificationType { Single = 0x0000000, Modify = DN_MODIFY, Create = DN_CREATE, Delete = DN_DELETE, Rename = DN_RENAME, Attrib = DN_ATTRIB }; -class OFileNotifier : public QObject +class OFileNotification : public QObject { + Q_OBJECT + public: - static void singleShot( const QString& path, - QObject *receiver, const char *member, - OFileNotificationType type = Modify ); + OFileNotification( QObject* parent = 0, const char* name = 0 ); + ~OFileNotification(); + + static void singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify ); + + int start( const QString& path, bool sshot = false, OFileNotificationType type = Modify ); + void stop(); + + OFileNotificationType type() const; + QString path() const; + int fileno() const; + bool isActive() const; + + signals: + void triggered(); + protected: - static void registerSignalHandler(); + void activate(); + static bool registerSignalHandler(); static void unregisterSignalHandler(); static void __signalHandler( int sig, siginfo_t *si, void *data ); private: - OFileNotifier(); - ~OFileNotifier(); + QString _path; + OFileNotificationType _type; + QSignal _signal; + int _fd; + bool _active; }; } } #endif |