summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--examples/opiecore/onotifytest/main.cpp2
-rw-r--r--libopie2/opiecore/linux/ofilenotify.cpp79
-rw-r--r--libopie2/opiecore/linux/ofilenotify.h13
3 files changed, 67 insertions, 27 deletions
diff --git a/examples/opiecore/onotifytest/main.cpp b/examples/opiecore/onotifytest/main.cpp
index 8374c59..b773da9 100644
--- a/examples/opiecore/onotifytest/main.cpp
+++ b/examples/opiecore/onotifytest/main.cpp
@@ -1,66 +1,66 @@
1// (C) Michael 'Mickey' Lauer <mickey@Vanille.de> 1// (C) Michael 'Mickey' Lauer <mickey@Vanille.de>
2// LICENSE = "GPLv2" 2// LICENSE = "GPLv2"
3 3
4#include "main.h" 4#include "main.h"
5 5
6/* OPIE */ 6/* OPIE */
7#include <opie2/odebug.h> 7#include <opie2/odebug.h>
8#include <opie2/oapplication.h> 8#include <opie2/oapplication.h>
9#include <opie2/ofilenotify.h> 9#include <opie2/ofilenotify.h>
10using namespace Opie::Core; 10using namespace Opie::Core;
11 11
12/* QT */ 12/* QT */
13#include <qdir.h> 13#include <qdir.h>
14#include <qpushbutton.h> 14#include <qpushbutton.h>
15#include <qstringlist.h> 15#include <qstringlist.h>
16#include <qtextstream.h> 16#include <qtextstream.h>
17#include <qmessagebox.h> 17#include <qmessagebox.h>
18 18
19App::App( int argc, char** argv ) : QApplication( argc, argv ) 19App::App( int argc, char** argv ) : QApplication( argc, argv )
20{ 20{
21 odebug << "App()" << oendl; 21 odebug << "App()" << oendl;
22#if 0 22#if 0
23 tmpfoo = new OFile( "/tmp/foo" ); 23 tmpfoo = new OFile( "/tmp/foo" );
24 if ( tmpfoo->open( IO_ReadWrite ) ) 24 if ( tmpfoo->open( IO_ReadWrite ) )
25 { 25 {
26 QTextStream stream( tmpfoo ); 26 QTextStream stream( tmpfoo );
27 stream << "This is my content"; 27 stream << "This is my content";
28 } 28 }
29 29
30 QObject::connect( tmpfoo, SIGNAL(accessed(const QString&)), this, SLOT(quit()) ); 30 QObject::connect( tmpfoo, SIGNAL(accessed(const QString&)), this, SLOT(quit()) );
31 QObject::connect( tmpfoo, SIGNAL(closed(const QString&,bool)), this, SLOT(quit()) ); 31 QObject::connect( tmpfoo, SIGNAL(closed(const QString&,bool)), this, SLOT(quit()) );
32#endif 32#endif
33 33
34 ODirNotification* tmpfoo = new ODirNotification( 0, 0 ); 34 ODirNotification* tmpfoo = new ODirNotification( 0, 0 );
35 35
36 int result = tmpfoo->watch( "/tmp/foo", false, CreateFile, 1 ); 36 int result = tmpfoo->watch( "/tmp/foo", false, CreateFile, 2 );
37 QObject::connect( tmpfoo, SIGNAL(triggered(const QString&,unsigned int,const QString&)), 37 QObject::connect( tmpfoo, SIGNAL(triggered(const QString&,unsigned int,const QString&)),
38 this, SLOT(triggered(const QString&,unsigned int,const QString&)) ); 38 this, SLOT(triggered(const QString&,unsigned int,const QString&)) );
39} 39}
40 40
41App::~App() 41App::~App()
42{ 42{
43 odebug << "~App()" << oendl; 43 odebug << "~App()" << oendl;
44} 44}
45 45
46void App::triggered( const QString& str1, unsigned int id, const QString& str2 ) 46void App::triggered( const QString& str1, unsigned int id, const QString& str2 )
47{ 47{
48 QMessageBox::information( qApp->desktop(), "info", QString( "%1\n%2\n%3" ).arg( str1 ).arg( id ).arg( str2 ) ); 48 QMessageBox::information( qApp->desktop(), "info", QString( "%1\n%2\n%3" ).arg( str1 ).arg( id ).arg( str2 ) );
49} 49}
50 50
51int main( int argc, char** argv ) 51int main( int argc, char** argv )
52{ 52{
53 App* app = new App( argc, argv ); 53 App* app = new App( argc, argv );
54 QPushButton* b = new QPushButton( "Click me to close", 0 ); 54 QPushButton* b = new QPushButton( "Click me to close", 0 );
55 QObject::connect( b, SIGNAL(clicked()), qApp, SLOT(quit()) ); 55 QObject::connect( b, SIGNAL(clicked()), qApp, SLOT(quit()) );
56 b->resize( 200, 200 ); 56 b->resize( 200, 200 );
57 b->move( 150, 150 ); 57 b->move( 150, 150 );
58 b->show(); 58 b->show();
59 app->setMainWidget( b ); 59 app->setMainWidget( b );
60 app->exec(); 60 app->exec();
61 delete app; 61 delete app;
62 62
63 return 0; 63 return 0;
64 64
65} 65}
66 66
diff --git a/libopie2/opiecore/linux/ofilenotify.cpp b/libopie2/opiecore/linux/ofilenotify.cpp
index 3096f7e..a7820ee 100644
--- a/libopie2/opiecore/linux/ofilenotify.cpp
+++ b/libopie2/opiecore/linux/ofilenotify.cpp
@@ -133,285 +133,312 @@ OFileNotificationEvent::~OFileNotificationEvent()
133// OFileNotification 133// OFileNotification
134//================================================================================================= 134//=================================================================================================
135OFileNotification::OFileNotification( QObject* parent, const char* name ) 135OFileNotification::OFileNotification( QObject* parent, const char* name )
136 :QObject( parent, name ), _active( false ), _multi( true ) 136 :QObject( parent, name ), _active( false ), _multi( true )
137{ 137{
138 qDebug( "OFileNotification::OFileNotification()" ); 138 qDebug( "OFileNotification::OFileNotification()" );
139} 139}
140 140
141 141
142OFileNotification::~OFileNotification() 142OFileNotification::~OFileNotification()
143{ 143{
144 stop(); 144 stop();
145 qDebug( "OFileNotification::~OFileNotification()" ); 145 qDebug( "OFileNotification::~OFileNotification()" );
146} 146}
147 147
148 148
149bool OFileNotification::isActive() const 149bool OFileNotification::isActive() const
150{ 150{
151 return _active; 151 return _active;
152} 152}
153 153
154 154
155int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type ) 155int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type )
156{ 156{
157 // check if path exists and is a regular file 157 // check if path exists and is a regular file
158 struct stat s; 158 struct stat s;
159 if ( ::stat( (const char*) path, &s ) == -1 ) 159 if ( ::stat( (const char*) path, &s ) == -1 )
160 { 160 {
161 qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, strerror( errno ) ); 161 qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, strerror( errno ) );
162 return -1; 162 return -1;
163 } 163 }
164 if ( !S_ISREG( s.st_mode ) ) 164 if ( !S_ISREG( s.st_mode ) )
165 { 165 {
166 qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, "not a regular file" ); 166 qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, "not a regular file" );
167 return -1; 167 return -1;
168 } 168 }
169 169
170 return startWatching( path, sshot, type ); 170 return startWatching( path, sshot, type );
171} 171}
172 172
173 173
174int OFileNotification::startWatching( const QString& path, bool sshot, OFileNotificationType type ) 174int OFileNotification::startWatching( const QString& path, bool sshot, OFileNotificationType type )
175{ 175{
176 if ( notification_list.isEmpty() ) 176 if ( notification_list.isEmpty() )
177 { 177 {
178 OFileNotification::registerEventHandler(); 178 OFileNotification::registerEventHandler();
179 } 179 }
180 180
181 struct inotify_watch_request iwr; 181 struct inotify_watch_request iwr;
182 ::memset( &iwr, 0, sizeof iwr ); 182 ::memset( &iwr, 0, sizeof iwr );
183 iwr.name = const_cast<char*>( (const char*) path ); 183 iwr.name = const_cast<char*>( (const char*) path );
184 iwr.mask = type; 184 iwr.mask = type;
185 185
186 _wd = ::ioctl( OFileNotification::_fd, INOTIFY_WATCH, &iwr ); 186 _wd = ::ioctl( OFileNotification::_fd, INOTIFY_WATCH, &iwr );
187 187
188 if ( _wd < 0 ) 188 if ( _wd < 0 )
189 { 189 {
190 qWarning( "OFileNotification::watch(): inotify can't watch '%s': %s.", (const char*) path, strerror( errno ) ); 190 qWarning( "OFileNotification::watch(): inotify can't watch '%s': %s.", (const char*) path, strerror( errno ) );
191 return -1; 191 return -1;
192 } 192 }
193 193
194 notification_list.insert( _wd, this ); 194 notification_list.insert( _wd, this );
195 _path = path; 195 _path = path;
196 _multi = !sshot; 196 _multi = !sshot;
197 _type = type; 197 _type = type;
198 _active = true; 198 _active = true;
199 qDebug( "OFileNotification::watch(): watching '%s' [wd=%d].", (const char*) path, _wd ); 199 qDebug( "OFileNotification::watch(): watching '%s' [wd=%d].", (const char*) path, _wd );
200 return _wd; 200 return _wd;
201} 201}
202 202
203 203
204void OFileNotification::stop() 204void OFileNotification::stop()
205{ 205{
206 notification_list.remove( _wd ); 206 notification_list.remove( _wd );
207 _path = QString::null; 207 _path = QString::null;
208 _wd = 0; 208 _wd = 0;
209 _active = false; 209 _active = false;
210 if ( notification_list.isEmpty() ) 210 if ( notification_list.isEmpty() )
211 { 211 {
212 OFileNotification::unregisterEventHandler(); 212 OFileNotification::unregisterEventHandler();
213 } 213 }
214} 214}
215 215
216 216
217OFileNotificationType OFileNotification::type() const 217OFileNotificationType OFileNotification::type() const
218{ 218{
219 return _type; 219 return _type;
220} 220}
221 221
222 222
223QString OFileNotification::path() const 223QString OFileNotification::path() const
224{ 224{
225 return _path; 225 return _path;
226} 226}
227 227
228 228
229bool OFileNotification::isSingleShot() const
230{
231 return !_multi;
232}
233
234
229bool OFileNotification::activate( const OFileNotificationEvent* e ) 235bool OFileNotification::activate( const OFileNotificationEvent* e )
230{ 236{
231 qDebug( "OFileNotification::activate(): e = ( %s, %d, 0x%08x, %d, %s )", (const char*) _path, e->descriptor(), e->mask(), e->cookie(), (const char*) e->name() ); 237 qDebug( "OFileNotification::activate(): e = ( %s, %d, 0x%08x, %d, %s )", (const char*) _path, e->descriptor(), e->mask(), e->cookie(), (const char*) e->name() );
232 238
233 // dumb signal 239 // dumb signal
234 _signal.activate(); 240 _signal.activate();
235 241
236 // generic signal 242 // generic signal
237 emit triggered( _path, e->mask(), e->name() ); 243 emit triggered( _path, e->mask(), e->name() );
238 244
239 // specialized signals 245 // specialized signals
240 switch ( e->mask() ) 246 switch ( e->mask() )
241 { 247 {
242 case Access: emit accessed( _path ); break; 248 case Access: emit accessed( _path ); break;
243 case Modify: emit modified( _path ); break; 249 case Modify: emit modified( _path ); break;
244 case Attrib: emit attributed( _path); break; 250 case Attrib: emit attributed( _path); break;
245 case CloseWrite: emit closed( _path, true ); break; 251 case CloseWrite: emit closed( _path, true ); break;
246 case CloseNoWrite: emit closed( _path, false ); break; 252 case CloseNoWrite: emit closed( _path, false ); break;
247 case Open: emit opened( _path ); break; 253 case Open: emit opened( _path ); break;
248 case MovedFrom: emit movedFrom( _path, e->name() ); break; 254 case MovedFrom: emit movedFrom( _path, e->name() ); break;
249 case MovedTo: emit movedTo( _path, e->name() ); break; 255 case MovedTo: emit movedTo( _path, e->name() ); break;
250 case DeleteSubdir: emit deletedSubdir( _path, e->name() ); break; 256 case DeleteSubdir: emit deletedSubdir( _path, e->name() ); break;
251 case DeleteFile: emit deletedFile( _path, e->name() ); break; 257 case DeleteFile: emit deletedFile( _path, e->name() ); break;
252 case CreateSubdir: emit createdSubdir( _path, e->name() ); break; 258 case CreateSubdir: emit createdSubdir( _path, e->name() ); break;
253 case CreateFile: emit createdFile( _path, e->name() ); break; 259 case CreateFile: emit createdFile( _path, e->name() ); break;
254 case DeleteSelf: emit deleted( _path ); break; 260 case DeleteSelf: emit deleted( _path ); break;
255 case Unmount: emit unmounted( _path ); break; 261 case Unmount: emit unmounted( _path ); break;
256 default: assert( 0 ); 262 default: assert( 0 );
257 } 263 }
258 264
259 if ( !_multi ) stop(); 265 if ( !_multi ) stop();
260 266
261 return true; 267 return true;
262} 268}
263 269
264 270
265bool OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 271bool OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
266{ 272{
267 OFileNotification* ofn = new OFileNotification(); 273 OFileNotification* ofn = new OFileNotification();
268 ofn->_signal.connect( receiver, member ); 274 ofn->_signal.connect( receiver, member );
269 return ofn->watch( path, true, type ) != -1; 275 return ofn->watch( path, true, type ) != -1;
270} 276}
271 277
272 278
273void OFileNotification::inotifyEventHandler() 279void OFileNotification::inotifyEventHandler()
274{ 280{
275 qDebug( "OFileNotification::inotifyEventHandler(): reached." ); 281 qDebug( "OFileNotification::inotifyEventHandler(): reached." );
276 282
277 char buffer[16384]; 283 char buffer[16384];
278 ssize_t buffer_i; 284 ssize_t buffer_i;
279 struct inotify_event *pevent, *event; 285 struct inotify_event *pevent, *event;
280 ssize_t r; 286 ssize_t r;
281 size_t event_size; 287 size_t event_size;
282 int count = 0; 288 int count = 0;
283 289
284 r = ::read(_fd, buffer, 16384); 290 r = ::read(_fd, buffer, 16384);
285 291
286 if ( r <= 0 ) 292 if ( r <= 0 )
287 return; 293 return;
288 294
289 buffer_i = 0; 295 buffer_i = 0;
290 while ( buffer_i < r ) 296 while ( buffer_i < r )
291 { 297 {
292 pevent = (struct inotify_event *)&buffer[buffer_i]; 298 pevent = (struct inotify_event *)&buffer[buffer_i];
293 event_size = sizeof(struct inotify_event) + pevent->len; 299 event_size = sizeof(struct inotify_event) + pevent->len;
294 OFileNotificationEvent* e = new OFileNotificationEvent( notification_list[ pevent->wd ], pevent->wd, pevent->mask, 300 OFileNotificationEvent* e = new OFileNotificationEvent( notification_list[ pevent->wd ], pevent->wd, pevent->mask,
295 pevent->cookie, pevent->len ? pevent->name : 0 ); 301 pevent->cookie, pevent->len ? pevent->name : 0 );
296 e->activate(); 302 e->activate();
297 buffer_i += event_size; 303 buffer_i += event_size;
298 count++; 304 count++;
299 } 305 }
300 306
301 qDebug( "OFileNotification::inotifyEventHandler(): processed %d events", count ); 307 qDebug( "OFileNotification::inotifyEventHandler(): processed %d events", count );
302} 308}
303 309
304 310
305bool OFileNotification::registerEventHandler() 311bool OFileNotification::registerEventHandler()
306{ 312{
307 OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY ); 313 OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY );
308 if ( OFileNotification::_fd < 0 ) 314 if ( OFileNotification::_fd < 0 )
309 { 315 {
310 qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) ); 316 qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) );
311 return false; 317 return false;
312 } 318 }
313 319
314 OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" ); 320 OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" );
315 connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) ); 321 connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) );
316 322
317 qDebug( "OFileNotification::registerEventHandler(): done" ); 323 qDebug( "OFileNotification::registerEventHandler(): done" );
318 return true; 324 return true;
319} 325}
320 326
321 327
322void OFileNotification::unregisterEventHandler() 328void OFileNotification::unregisterEventHandler()
323{ 329{
324 if ( _sn ) delete _sn; 330 if ( _sn ) delete _sn;
325 if ( OFileNotification::_fd ) 331 if ( OFileNotification::_fd )
326 ::close( OFileNotification::_fd ); 332 ::close( OFileNotification::_fd );
327 qDebug( "OFileNotification::unregisterEventHandler(): done" ); 333 qDebug( "OFileNotification::unregisterEventHandler(): done" );
328} 334}
329 335
330//================================================================================================= 336//=================================================================================================
331// ODirNotification 337// ODirNotification
332//================================================================================================= 338//=================================================================================================
333ODirNotification::ODirNotification( QObject* parent, const char* name ) 339ODirNotification::ODirNotification( QObject* parent, const char* name )
334 :QObject( parent, name ) 340 :QObject( parent, name ), _topfilenotification( 0 ), _type( Nothing ), _depth( -123 )
335{ 341{
336 qDebug( "ODirNotification::ODirNotification()" ); 342 qDebug( "ODirNotification::ODirNotification()" );
337} 343}
338 344
339 345
340ODirNotification::~ODirNotification() 346ODirNotification::~ODirNotification()
341{ 347{
342 qDebug( "ODirNotification::~ODirNotification()" ); 348 qDebug( "ODirNotification::~ODirNotification()" );
343} 349}
344 350
351/*
352 Love-Trowbridge recursive directory scanning algorithm:
353
354 Step 1. Start at initial directory foo. Add watch.
355
356 Step 2. Setup handlers for watch created in Step 1.
357 Specifically, ensure that a directory created
358 in foo will result in a handled CREATE_SUBDIR
359 event.
360
361 Step 3. Read the contents of foo.
362
363 Step 4. For each subdirectory of foo read in step 3, repeat
364 step 1.
365
366 Step 5. For any CREATE_SUBDIR event on bar, if a watch is
367 not yet created on bar, repeat step 1 on bar.
368*/
345 369
346int ODirNotification::watch( const QString& path, bool sshot, OFileNotificationType type, int recurse ) 370int ODirNotification::watch( const QString& path, bool sshot, OFileNotificationType type, int recurse )
347{ 371{
348 qDebug( "ODirNotification::watch( %s, %d, 0x%08x, %d )", (const char*) path, sshot, type, recurse ); 372 if ( _type == Nothing ) _type = type; // only set it once - for the top level call
349 373 OFileNotificationType subtype = ( recurse != 0 ) ? (OFileNotificationType) int( _type | CreateSubdir ) : _type;
374 qDebug( "ODirNotification::watch( %s, %d, 0x%08x, %d )", (const char*) path, sshot, subtype, recurse );
350 OFileNotification* fn = new OFileNotification( this, "ODirNotification delegate" ); 375 OFileNotification* fn = new OFileNotification( this, "ODirNotification delegate" );
351 int result = fn->startWatching( path, sshot, type ); 376
377 int result = fn->startWatching( path, sshot, subtype );
352 if ( result != -1 ) 378 if ( result != -1 )
353 { 379 {
380
381 if ( !_topfilenotification ) _topfilenotification = fn; // only set it once - for the top level call
382 if ( _depth == -123 ) _depth = recurse; // only set it once - for the top level call
383
354 connect( fn, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ), this, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ) ); 384 connect( fn, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ), this, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ) );
355 connect( fn, SIGNAL( accessed( const QString& ) ), this, SIGNAL( accessed( const QString& ) ) ); 385 connect( fn, SIGNAL( accessed( const QString& ) ), this, SIGNAL( accessed( const QString& ) ) );
356 connect( fn, SIGNAL( modified( const QString& ) ), this, SIGNAL( modified( const QString& ) ) ); 386 connect( fn, SIGNAL( modified( const QString& ) ), this, SIGNAL( modified( const QString& ) ) );
357 connect( fn, SIGNAL( attributed( const QString& ) ), this, SIGNAL( attributed( const QString& ) ) ); 387 connect( fn, SIGNAL( attributed( const QString& ) ), this, SIGNAL( attributed( const QString& ) ) );
358 connect( fn, SIGNAL( closed( const QString&, bool ) ), this, SIGNAL( closed( const QString&, bool ) ) ); 388 connect( fn, SIGNAL( closed( const QString&, bool ) ), this, SIGNAL( closed( const QString&, bool ) ) );
359 connect( fn, SIGNAL( opened( const QString& ) ), this, SIGNAL( opened( const QString& ) ) ); 389 connect( fn, SIGNAL( opened( const QString& ) ), this, SIGNAL( opened( const QString& ) ) );
360 connect( fn, SIGNAL( movedTo( const QString&, const QString& ) ), this, SIGNAL( movedTo( const QString&, const QString& ) ) ); 390 connect( fn, SIGNAL( movedTo( const QString&, const QString& ) ), this, SIGNAL( movedTo( const QString&, const QString& ) ) );
361 connect( fn, SIGNAL( movedFrom( const QString&, const QString& ) ), this, SIGNAL( movedFrom( const QString&, const QString& ) ) ); 391 connect( fn, SIGNAL( movedFrom( const QString&, const QString& ) ), this, SIGNAL( movedFrom( const QString&, const QString& ) ) );
362 connect( fn, SIGNAL( deletedSubdir( const QString&, const QString& ) ), this, SIGNAL( deletedSubdir( const QString&, const QString& ) ) ); 392 connect( fn, SIGNAL( deletedSubdir( const QString&, const QString& ) ), this, SIGNAL( deletedSubdir( const QString&, const QString& ) ) );
363 connect( fn, SIGNAL( deletedFile( const QString&, const QString& ) ), this, SIGNAL( deletedFile( const QString&, const QString& ) ) );; 393 connect( fn, SIGNAL( deletedFile( const QString&, const QString& ) ), this, SIGNAL( deletedFile( const QString&, const QString& ) ) );;
364 connect( fn, SIGNAL( createdSubdir( const QString&, const QString& ) ), this, SIGNAL( createdSubdir( const QString&, const QString& ) ) ); 394 connect( fn, SIGNAL( createdSubdir( const QString&, const QString& ) ), this, SIGNAL( createdSubdir( const QString&, const QString& ) ) );
365 connect( fn, SIGNAL( createdFile( const QString&, const QString& ) ), this, SIGNAL( createdFile( const QString&, const QString& ) ) ); 395 connect( fn, SIGNAL( createdFile( const QString&, const QString& ) ), this, SIGNAL( createdFile( const QString&, const QString& ) ) );
366 connect( fn, SIGNAL( deleted( const QString& ) ), this, SIGNAL( deleted( const QString& ) ) ); 396 connect( fn, SIGNAL( deleted( const QString& ) ), this, SIGNAL( deleted( const QString& ) ) );
367 connect( fn, SIGNAL( unmounted( const QString& ) ), this, SIGNAL( unmounted( const QString& ) ) ); 397 connect( fn, SIGNAL( unmounted( const QString& ) ), this, SIGNAL( unmounted( const QString& ) ) );
368 398
369 if ( recurse ) 399 if ( recurse != 0 )
370 { 400 {
401 connect( fn, SIGNAL( createdSubdir( const QString&, const QString& ) ), this, SLOT( subdirCreated( const QString&, const QString& ) ) );
402
371 QDir directory( path ); 403 QDir directory( path );
372 QStringList subdirs = directory.entryList( QDir::Dirs ); 404 QStringList subdirs = directory.entryList( QDir::Dirs );
373 405
374 for ( QStringList::Iterator it = subdirs.begin(); it != subdirs.end(); ++it ) 406 for ( QStringList::Iterator it = subdirs.begin(); it != subdirs.end(); ++it )
375 { 407 {
376 if ( (*it) == "." || (*it) == ".." ) continue; 408 if ( (*it) == "." || (*it) == ".." ) continue;
377 QString subpath = QString( "%1/%2" ).arg( path ).arg( *it ); 409 QString subpath = QString( "%1/%2" ).arg( path ).arg( *it );
378 int subresult = watch( subpath, sshot, type, recurse-1 ); 410 int subresult = watch( subpath, sshot, subtype, recurse-1 );
379 if ( subresult == -1 ) 411 if ( subresult == -1 )
380 { 412 {
381 qDebug( "ODirNotification::watch(): subresult for '%s' was -1. Interrupting", (const char*) (*it) ); 413 qDebug( "ODirNotification::watch(): subresult for '%s' was -1. Interrupting", (const char*) (*it) );
382 return -1; 414 return -1;
383 } 415 }
384 } 416 }
385 } 417 }
386//connect( fn, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ), this, SIGNAL( triggered( const QString&, unsigned int, const QString& ) ) );
387 } 418 }
388 else return -1; 419 else return -1;
389} 420}
390 421
391 422
392// void ODirNotification::subdirCreated( const QString& name ) 423void ODirNotification::subdirCreated( const QString& dir, const QString& subdir )
393 424{
394 425 qDebug( "*** ODirNotification::subdirCreated '%s/%s'", (const char*) dir, (const char*) subdir );
395/* 426 QString newdir = dir;
396 Love-Trowbridge recursive directory scanning algorithm: 427 if ( newdir.startsWith( _topfilenotification->path() ) )
397 428 {
398 Step 1. Start at initial directory foo. Add watch. 429 newdir.replace( _topfilenotification->path(), "" );
399 430 int level = newdir.contains( '/' );
400 Step 2. Setup handlers for watch created in Step 1. 431 qDebug( "*** dirpart = '%s' ==> level = %d", (const char*) newdir, level );
401 Specifically, ensure that a directory created
402 in foo will result in a handled CREATE_SUBDIR
403 event.
404
405 Step 3. Read the contents of foo.
406 432
407 Step 4. For each subdirectory of foo read in step 3, repeat 433 if ( _depth == -1 || _depth > level )
408 step 1. 434 {
435 watch( QString( "%1/%2" ).arg( dir ).arg( subdir ), _topfilenotification->isSingleShot(), _topfilenotification->type(), _depth == -1 ? -1 : _depth-level-1 );
436 }
409 437
410 Step 5. For any CREATE_SUBDIR event on bar, if a watch is 438 }
411 not yet created on bar, repeat step 1 on bar. 439}
412*/
413 440
414 441
415} // namespace Ui 442} // namespace Ui
416 443
417} // namespace Opie 444} // namespace Opie
diff --git a/libopie2/opiecore/linux/ofilenotify.h b/libopie2/opiecore/linux/ofilenotify.h
index 05343b9..17e6b5d 100644
--- a/libopie2/opiecore/linux/ofilenotify.h
+++ b/libopie2/opiecore/linux/ofilenotify.h
@@ -18,309 +18,322 @@ _;:,     .>    :=|. This program is free software; you can
18..}^=.=       =       ; Library General Public License for more 18..}^=.=       =       ; Library General Public License for more
19++=   -.     .`     .: details. 19++=   -.     .`     .: details.
20:     =  ...= . :.=- 20:     =  ...= . :.=-
21-.   .:....=;==+<; You should have received a copy of the GNU 21-.   .:....=;==+<; You should have received a copy of the GNU
22 -_. . .   )=.  = Library General Public License along with 22 -_. . .   )=.  = Library General Public License along with
23   --        :-=` this library; see the file COPYING.LIB. 23   --        :-=` this library; see the file COPYING.LIB.
24 If not, write to the Free Software Foundation, 24 If not, write to the Free Software Foundation,
25 Inc., 59 Temple Place - Suite 330, 25 Inc., 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA. 26 Boston, MA 02111-1307, USA.
27*/ 27*/
28 28
29#ifndef OFILENOTIFY_H 29#ifndef OFILENOTIFY_H
30#define OFILENOTIFY_H 30#define OFILENOTIFY_H
31#if defined (__GNUC__) && (__GNUC__ < 3) 31#if defined (__GNUC__) && (__GNUC__ < 3)
32#define _GNU_SOURCE 32#define _GNU_SOURCE
33#endif 33#endif
34 34
35#include "linux_inotify.h" 35#include "linux_inotify.h"
36 36
37/* QT */ 37/* QT */
38#include <qsocketnotifier.h> 38#include <qsocketnotifier.h>
39#include <qsignal.h> 39#include <qsignal.h>
40#include <qstring.h> 40#include <qstring.h>
41#include <qobject.h> 41#include <qobject.h>
42#include <qfile.h> 42#include <qfile.h>
43 43
44namespace Opie { 44namespace Opie {
45namespace Core { 45namespace Core {
46 46
47class OFile : public QObject, public QFile 47class OFile : public QObject, public QFile
48{ 48{
49 Q_OBJECT 49 Q_OBJECT
50 50
51 public: 51 public:
52 OFile(); 52 OFile();
53 OFile( const QString & name ); 53 OFile( const QString & name );
54 virtual ~OFile(); 54 virtual ~OFile();
55 55
56 protected: 56 protected:
57 virtual void connectNotify( const char* signal ); 57 virtual void connectNotify( const char* signal );
58 virtual void disconnectNotify( const char* signal ); 58 virtual void disconnectNotify( const char* signal );
59 59
60 private: 60 private:
61 int startWatch( int mode ); 61 int startWatch( int mode );
62 62
63 signals: 63 signals:
64 void accessed( const QString& ); 64 void accessed( const QString& );
65 void modified( const QString& ); 65 void modified( const QString& );
66 void attributed( const QString& ); 66 void attributed( const QString& );
67 void closed( const QString&, bool ); 67 void closed( const QString&, bool );
68 void opened( const QString& ); 68 void opened( const QString& );
69 void deleted( const QString& ); 69 void deleted( const QString& );
70 void unmounted( const QString& ); 70 void unmounted( const QString& );
71}; 71};
72 72
73/* 73/*
74 void movedTo( const QString&, const QString& ); 74 void movedTo( const QString&, const QString& );
75 void movedFrom( const QString&, const QString& ); 75 void movedFrom( const QString&, const QString& );
76 void deletedSubdir( const QString&, const QString& ); 76 void deletedSubdir( const QString&, const QString& );
77 void deletedFile( const QString&, const QString& ); 77 void deletedFile( const QString&, const QString& );
78 void createdSubdir( const QString&, const QString& ); 78 void createdSubdir( const QString&, const QString& );
79 void createdFile( const QString&, const QString& ); 79 void createdFile( const QString&, const QString& );
80*/ 80*/
81 81
82class OFileNotificationEvent; 82class OFileNotificationEvent;
83 83
84/*====================================================================================== 84/*======================================================================================
85 * OFileNotificationType 85 * OFileNotificationType
86 *======================================================================================*/ 86 *======================================================================================*/
87 87
88/** 88/**
89 * @brief An enumerate for the different types of file notifications 89 * @brief An enumerate for the different types of file notifications
90 * 90 *
91 * This enumerate provides a means to specify the type of events that you are interest in. 91 * This enumerate provides a means to specify the type of events that you are interest in.
92 * Valid values are: 92 * Valid values are:
93 * <ul> 93 * <ul>
94 * <li>Access: The file was accessed (read) 94 * <li>Access: The file was accessed (read)
95 * <li>Modify The file was modified (write,truncate) 95 * <li>Modify The file was modified (write,truncate)
96 * <li>Attrib = The file had its attributes changed (chmod,chown,chgrp) 96 * <li>Attrib = The file had its attributes changed (chmod,chown,chgrp)
97 * <li>CloseWrite = Writable file was closed 97 * <li>CloseWrite = Writable file was closed
98 * <li>CloseNoWrite = Unwritable file was closed 98 * <li>CloseNoWrite = Unwritable file was closed
99 * <li>Open = File was opened 99 * <li>Open = File was opened
100 * <li>MovedFrom = File was moved from X 100 * <li>MovedFrom = File was moved from X
101 * <li>MovedTo = File was moved to Y 101 * <li>MovedTo = File was moved to Y
102 * <li>DeleteSubdir = Subdir was deleted 102 * <li>DeleteSubdir = Subdir was deleted
103 * <li>DeleteFile = Subfile was deleted 103 * <li>DeleteFile = Subfile was deleted
104 * <li>CreateSubdir = Subdir was created 104 * <li>CreateSubdir = Subdir was created
105 * <li>CreateFile = Subfile was created 105 * <li>CreateFile = Subfile was created
106 * <li>DeleteSelf = Self was deleted 106 * <li>DeleteSelf = Self was deleted
107 * <li>Unmount = The backing filesystem was unmounted 107 * <li>Unmount = The backing filesystem was unmounted
108 * </ul> 108 * </ul>
109 * 109 *
110 **/ 110 **/
111 111
112enum OFileNotificationType 112enum OFileNotificationType
113{ 113{
114 Nothing = 0,
114 Access = IN_ACCESS, 115 Access = IN_ACCESS,
115 Modify = IN_MODIFY, 116 Modify = IN_MODIFY,
116 Attrib = IN_ATTRIB, 117 Attrib = IN_ATTRIB,
117 CloseWrite = IN_CLOSE_WRITE, 118 CloseWrite = IN_CLOSE_WRITE,
118 CloseNoWrite = IN_CLOSE_NOWRITE, 119 CloseNoWrite = IN_CLOSE_NOWRITE,
119 Open = IN_OPEN, 120 Open = IN_OPEN,
120 MovedFrom = IN_MOVED_FROM, 121 MovedFrom = IN_MOVED_FROM,
121 MovedTo = IN_MOVED_TO, 122 MovedTo = IN_MOVED_TO,
122 DeleteSubdir = IN_DELETE_SUBDIR, 123 DeleteSubdir = IN_DELETE_SUBDIR,
123 DeleteFile = IN_DELETE_FILE, 124 DeleteFile = IN_DELETE_FILE,
124 CreateSubdir = IN_CREATE_SUBDIR, 125 CreateSubdir = IN_CREATE_SUBDIR,
125 CreateFile = IN_CREATE_FILE, 126 CreateFile = IN_CREATE_FILE,
126 DeleteSelf = IN_DELETE_SELF, 127 DeleteSelf = IN_DELETE_SELF,
127 Unmount = IN_UNMOUNT, 128 Unmount = IN_UNMOUNT,
128 _QueueOverflow = IN_Q_OVERFLOW, /* Internal, don't use this in client code */ 129 _QueueOverflow = IN_Q_OVERFLOW, /* Internal, don't use this in client code */
129 _Ignored = IN_IGNORED, /* Internal, don't use this in client code */ 130 _Ignored = IN_IGNORED, /* Internal, don't use this in client code */
130}; 131};
131 132
132/*====================================================================================== 133/*======================================================================================
133 * OFileNotification 134 * OFileNotification
134 *======================================================================================*/ 135 *======================================================================================*/
135 136
136/** 137/**
137 * @brief Represents a file notification 138 * @brief Represents a file notification
138 * 139 *
139 * This class allows to watch for events happening to files. 140 * This class allows to watch for events happening to files.
140 * It uses the inotify linux (2.6.x) kernel interface. 141 * It uses the inotify linux (2.6.x) kernel interface.
141 * 142 *
142 * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/ 143 * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/
143 * 144 *
144 * @author Michael 'Mickey' Lauer <mickey@vanille.de> 145 * @author Michael 'Mickey' Lauer <mickey@vanille.de>
145 * 146 *
146 **/ 147 **/
147 148
148class OFileNotification : public QObject 149class OFileNotification : public QObject
149{ 150{
150 Q_OBJECT 151 Q_OBJECT
151 152
152 public: 153 public:
153 OFileNotification( QObject* parent = 0, const char* name = 0 ); 154 OFileNotification( QObject* parent = 0, const char* name = 0 );
154 ~OFileNotification(); 155 ~OFileNotification();
155 /** 156 /**
156 * This static function calls a slot when an event with @a type happens to file @a path. 157 * This static function calls a slot when an event with @a type happens to file @a path.
157 * 158 *
158 * It is very convenient to use this function because you do not need to 159 * It is very convenient to use this function because you do not need to
159 * bother with a timerEvent or to create a local QTimer object. 160 * bother with a timerEvent or to create a local QTimer object.
160 * 161 *
161 * Example: 162 * Example:
162 * <pre> 163 * <pre>
163 * 164 *
164 * #include <opie2/oapplication.h> 165 * #include <opie2/oapplication.h>
165 * #include <opie2/ofilenotify.h> 166 * #include <opie2/ofilenotify.h>
166 * using namespace Opie::Core; 167 * using namespace Opie::Core;
167 * 168 *
168 * int main( int argc, char **argv ) 169 * int main( int argc, char **argv )
169 * { 170 * {
170 * OApplication a( argc, argv, "File Notification Example" ); 171 * OApplication a( argc, argv, "File Notification Example" );
171 * OFileNotification::singleShot( "/tmp/quit", &a, SLOT(quit()), Access ); 172 * OFileNotification::singleShot( "/tmp/quit", &a, SLOT(quit()), Access );
172 * ... // create and show your widgets 173 * ... // create and show your widgets
173 * return a.exec(); 174 * return a.exec();
174 * } 175 * }
175 * </pre> 176 * </pre>
176 * 177 *
177 * This sample program automatically terminates when the file "/tmp/quit" has been accessed. 178 * This sample program automatically terminates when the file "/tmp/quit" has been accessed.
178 * 179 *
179 * 180 *
180 * The @a receiver is the receiving object and the @a member is the slot. 181 * The @a receiver is the receiving object and the @a member is the slot.
181 **/ 182 **/
182 static bool singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify ); 183 static bool singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify );
183 /** 184 /**
184 * Starts to watch for @a type changes to @a path. Set @a sshot to True if you want to be notified only once. 185 * Starts to watch for @a type changes to @a path. Set @a sshot to True if you want to be notified only once.
185 * Note that in that case it may be more convenient to use @ref OFileNotification::singleShot() then. 186 * Note that in that case it may be more convenient to use @ref OFileNotification::singleShot() then.
186 **/ 187 **/
187 int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify ); 188 int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
188 /** 189 /**
189 * Stop watching for file events. 190 * Stop watching for file events.
190 **/ 191 **/
191 void stop(); 192 void stop();
192 /** 193 /**
193 * @returns the notification type as set by @ref start(). 194 * @returns the notification type as set by @ref start().
194 **/ 195 **/
195 OFileNotificationType type() const; 196 OFileNotificationType type() const;
196 /** 197 /**
197 * @returns the path to the file being watched by this instance. 198 * @returns the path to the file being watched by this instance.
198 **/ 199 **/
199 QString path() const; 200 QString path() const;
200 /** 201 /**
202 * @returns if the notification is single-shot
203 */
204 bool isSingleShot() const;
205 /**
201 * @returns if a file is currently being watched. 206 * @returns if a file is currently being watched.
202 **/ 207 **/
203 bool isActive() const; 208 bool isActive() const;
204 /** 209 /**
205 * @internal 210 * @internal
206 */ 211 */
207 int startWatching( const QString& path, bool sshot = false, OFileNotificationType type = Modify ); 212 int startWatching( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
208 213
209 signals: 214 signals:
210 void triggered( const QString&, unsigned int, const QString& ); 215 void triggered( const QString&, unsigned int, const QString& );
211 void accessed( const QString& ); 216 void accessed( const QString& );
212 void modified( const QString& ); 217 void modified( const QString& );
213 void attributed( const QString& ); 218 void attributed( const QString& );
214 void closed( const QString&, bool ); 219 void closed( const QString&, bool );
215 void opened( const QString& ); 220 void opened( const QString& );
216 void movedTo( const QString&, const QString& ); 221 void movedTo( const QString&, const QString& );
217 void movedFrom( const QString&, const QString& ); 222 void movedFrom( const QString&, const QString& );
218 void deletedSubdir( const QString&, const QString& ); 223 void deletedSubdir( const QString&, const QString& );
219 void deletedFile( const QString&, const QString& ); 224 void deletedFile( const QString&, const QString& );
220 void createdSubdir( const QString&, const QString& ); 225 void createdSubdir( const QString&, const QString& );
221 void createdFile( const QString&, const QString& ); 226 void createdFile( const QString&, const QString& );
222 void deleted( const QString& ); 227 void deleted( const QString& );
223 void unmounted( const QString& ); 228 void unmounted( const QString& );
224 229
225 protected: 230 protected:
226 bool activate( const OFileNotificationEvent* e ); 231 bool activate( const OFileNotificationEvent* e );
227 232
228 private slots: 233 private slots:
229 void inotifyEventHandler(); 234 void inotifyEventHandler();
230 235
231 private: 236 private:
232 bool registerEventHandler(); 237 bool registerEventHandler();
233 void unregisterEventHandler(); 238 void unregisterEventHandler();
234 239
235 QString _path; 240 QString _path;
236 OFileNotificationType _type; 241 OFileNotificationType _type;
237 QSignal _signal; 242 QSignal _signal;
238 bool _active; 243 bool _active;
239 bool _multi; 244 bool _multi;
240 static QSocketNotifier* _sn; 245 static QSocketNotifier* _sn;
241 int _wd; // inotify watch descriptor 246 int _wd; // inotify watch descriptor
242 static int _fd; // inotify device descriptor 247 static int _fd; // inotify device descriptor
243 248
244 friend class OFileNotificationEvent; 249 friend class OFileNotificationEvent;
245}; 250};
246 251
247/*====================================================================================== 252/*======================================================================================
248 * ODirNotification 253 * ODirNotification
249 *======================================================================================*/ 254 *======================================================================================*/
250 255
251/** 256/**
252 * @brief Represents a directory notification 257 * @brief Represents a directory notification
253 * 258 *
254 * This class allows to watch for events happening to directories 259 * This class allows to watch for events happening to directories
255 * It uses the OFileNotification class 260 * It uses the OFileNotification class
256 * 261 *
257 * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/ 262 * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/
258 * 263 *
259 * @author Michael 'Mickey' Lauer <mickey@vanille.de> 264 * @author Michael 'Mickey' Lauer <mickey@vanille.de>
260 * 265 *
261 **/ 266 **/
262 267
263class ODirNotification : public QObject 268class ODirNotification : public QObject
264{ 269{
265 Q_OBJECT 270 Q_OBJECT
266 271
267 public: 272 public:
268 ODirNotification( QObject* parent = 0, const char* name = 0 ); 273 ODirNotification( QObject* parent = 0, const char* name = 0 );
269 ~ODirNotification(); 274 ~ODirNotification();
270 /** 275 /**
271 * Starts to watch for @a type changes to @a path. Recurse @a recurse levels down the filesystem tree, 276 * Starts to watch for @a type changes to @a path. Recurse @a recurse levels down the filesystem tree,
272 * use 0 for no recursion and -1 for unlimited recursion. 277 * use 0 for no recursion and -1 for unlimited recursion.
273 * Set @a sshot to True if you want to be notified only once. 278 * Set @a sshot to True if you want to be notified only once.
274 **/ 279 **/
275 int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify, int recurse = 0 ); 280 int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify, int recurse = 0 );
276 281
277 signals: 282 signals:
278 /** 283 /**
279 * This signal is emitted if an event happens of the specified type happens to the directory being watched. 284 * This signal is emitted if an event happens of the specified type happens to the directory being watched.
280 **/ 285 **/
281 void triggered( const QString&, unsigned int, const QString& ); 286 void triggered( const QString&, unsigned int, const QString& );
282 void accessed( const QString& ); 287 void accessed( const QString& );
283 void modified( const QString& ); 288 void modified( const QString& );
284 void attributed( const QString& ); 289 void attributed( const QString& );
285 void closed( const QString&, bool ); 290 void closed( const QString&, bool );
286 void opened( const QString& ); 291 void opened( const QString& );
287 void movedTo( const QString&, const QString& ); 292 void movedTo( const QString&, const QString& );
288 void movedFrom( const QString&, const QString& ); 293 void movedFrom( const QString&, const QString& );
289 void deletedSubdir( const QString&, const QString& ); 294 void deletedSubdir( const QString&, const QString& );
290 void deletedFile( const QString&, const QString& ); 295 void deletedFile( const QString&, const QString& );
291 void createdSubdir( const QString&, const QString& ); 296 void createdSubdir( const QString&, const QString& );
292 void createdFile( const QString&, const QString& ); 297 void createdFile( const QString&, const QString& );
293 void deleted( const QString& ); 298 void deleted( const QString& );
294 void unmounted( const QString& ); 299 void unmounted( const QString& );
300
301 private slots:
302 void subdirCreated( const QString&, const QString& );
303
304 private:
305 OFileNotification* _topfilenotification;
306 OFileNotificationType _type;
307 int _depth;
295}; 308};
296 309
297/*====================================================================================== 310/*======================================================================================
298 * OFileNotificationEvent 311 * OFileNotificationEvent
299 *======================================================================================*/ 312 *======================================================================================*/
300 313
301class OFileNotificationEvent 314class OFileNotificationEvent
302{ 315{
303 public: 316 public:
304 OFileNotificationEvent( OFileNotification* parent, int wd, unsigned int mask, unsigned int cookie, const QString& name ); 317 OFileNotificationEvent( OFileNotification* parent, int wd, unsigned int mask, unsigned int cookie, const QString& name );
305 ~OFileNotificationEvent(); 318 ~OFileNotificationEvent();
306 OFileNotification* parent() const { return _parent; }; 319 OFileNotification* parent() const { return _parent; };
307 int descriptor() const { return _wd; }; 320 int descriptor() const { return _wd; };
308 unsigned int mask() const { return _mask; }; 321 unsigned int mask() const { return _mask; };
309 unsigned int cookie() const { return _cookie; }; 322 unsigned int cookie() const { return _cookie; };
310 QString name() const { return _name; }; 323 QString name() const { return _name; };
311 void activate() { _parent->activate( this ); }; 324 void activate() { _parent->activate( this ); };
312 325
313 private: 326 private:
314 OFileNotification* _parent; 327 OFileNotification* _parent;
315 int _wd; 328 int _wd;
316 unsigned int _mask; 329 unsigned int _mask;
317 unsigned int _cookie; 330 unsigned int _cookie;
318 QString _name; 331 QString _name;
319}; 332};
320 333
321 334
322} 335}
323} 336}
324 337
325#endif 338#endif
326 339