summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ChangeLog7
-rw-r--r--examples/opiecore/onotifydemo/onotifydemo.cpp42
-rw-r--r--libopie2/opiecore/ofilenotify.cpp272
-rw-r--r--libopie2/opiecore/ofilenotify.h93
4 files changed, 168 insertions, 246 deletions
diff --git a/ChangeLog b/ChangeLog
index 2d5c886..7e81b7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,47 +1,48 @@
1 2005-??-??Opie 1.2.1 1 2005-??-??Opie 1.2.1
2 2
3 3
4 New Features 4 New Features
5 ------------ 5 ------------
6 * OpieStumbler: Scans WiFi networks using the wireless extension scanning (skyhusker) 6 * OpieStumbler: Scans WiFi networks using the wireless extension scanning (skyhusker)
7 7
8 Fixed Bugs 8 Fixed Bugs
9 ---------- 9 ----------
10 * #1476 - Wrong order of application entries in the O-menu (skyhusker)
10 * #1535- Missing line break and unnecessary location shown with Today-Calendar plugin (deller) 11 * #1535- Missing line break and unnecessary location shown with Today-Calendar plugin (deller)
11 * #1565 - crash-fix in odevice.cpp while scanning the distribution table (deller) 12 * #1565 - crash-fix in odevice.cpp while scanning the distribution table (deller)
12 * #1614 - Make Opie-console start in $HOME instead of / (skyhusker) 13 * #1614 - Make Opie-console start in $HOME instead of / (skyhusker)
13 * n.a.- always show volume and wireless applet popups inside visible screen (deller) 14 * n.a.- always show volume and wireless applet popups inside visible screen (deller)
14 * n.a. - scale O-Menu-Applets appropriately (mickeyl) 15 * n.a. - scale O-Menu-Applets appropriately (mickeyl)
15 * n.a.- libopienet: fix bugs in wireless scanning and setting SSID (skyhusker) 16 * n.a.- libopienet: fix bugs in wireless scanning and setting SSID (skyhusker)
16 * n.a.- Wellenreiter: relax WE version matching test a bit (mickeyl) 17 * n.a.- Wellenreiter: relax WE version matching test a bit (mickeyl)
17 * n.a.- scale BluezApplet appropriately (mickeyl) 18 * n.a.- scale BluezApplet appropriately and use larger icons (mickeyl)
18 * n.a.- memoryapplet: fix crash in memoryapplet on kernels without swap support (seneca cunningham) 19 * n.a.- memoryapplet: fix crash in memoryapplet on kernels without swap support (seneca cunningham)
19 * #1476 - Wrong order of application entries in the O-menu (skyhusker)
20 20
21 Internal 21 Internal
22 -------- 22 --------
23 * make BluezApplet use OTaskbarApplet (mickeyl) 23 * Make BluezApplet use OTaskbarApplet (mickeyl)
24 * Rewrite OFileNotification to use the upcoming inotify interface instead of the deprecated dnotify (mickeyl)
24 25
25 2005-03-25Opie 1.2.0 26 2005-03-25Opie 1.2.0
26 27
27 Fixed Bugs 28 Fixed Bugs
28 ---------- 29 ----------
29 * #1613 - AdvancedFM - scale toolbar icons appropriately (drw) 30 * #1613 - AdvancedFM - scale toolbar icons appropriately (drw)
30 * #1620 - OFileSelector - show the button on press and not on press on hold (alwin) 31 * #1620 - OFileSelector - show the button on press and not on press on hold (alwin)
31 * #1473 - Opie-Eye - Same as #1620 but we lack a common FileSystem Button class (zecke) 32 * #1473 - Opie-Eye - Same as #1620 but we lack a common FileSystem Button class (zecke)
32 * n.a. - PackageManager - fix bug where messages show up multiple times in install dialog (drw) 33 * n.a. - PackageManager - fix bug where messages show up multiple times in install dialog (drw)
33 * n.a.- make qpeglobal.h include qglobal.h (zecke) 34 * n.a.- make qpeglobal.h include qglobal.h (zecke)
34 35
35 2005-03-20Opie 1.2.0-rc1 36 2005-03-20Opie 1.2.0-rc1
36 37
37 38
38 New Features 39 New Features
39 ------------ 40 ------------
40 * Launcher: Support a static background pixmap (mickeyl) 41 * Launcher: Support a static background pixmap (mickeyl)
41 * LauncherSettings: Choose whether to have a static background pixmap (mickeyl) 42 * LauncherSettings: Choose whether to have a static background pixmap (mickeyl)
42 * PackageManager supports the 'lists_dir' ipkg configuration option (drw) 43 * PackageManager supports the 'lists_dir' ipkg configuration option (drw)
43 * Added hi-res inline images for large resolution devices (drw) 44 * Added hi-res inline images for large resolution devices (drw)
44 * Improved launcher icons for consistency (ar) 45 * Improved launcher icons for consistency (ar)
45 * Datebook: Added plugin system to datebook so holidays and birthdays from contacts may displayed in datebook (alwin) 46 * Datebook: Added plugin system to datebook so holidays and birthdays from contacts may displayed in datebook (alwin)
46 47
47 Fixed Bugs 48 Fixed Bugs
diff --git a/examples/opiecore/onotifydemo/onotifydemo.cpp b/examples/opiecore/onotifydemo/onotifydemo.cpp
index a38ffee..0e84d80 100644
--- a/examples/opiecore/onotifydemo/onotifydemo.cpp
+++ b/examples/opiecore/onotifydemo/onotifydemo.cpp
@@ -11,106 +11,114 @@ using namespace Opie::Ui;
11 11
12/* QT */ 12/* QT */
13#include <qcheckbox.h> 13#include <qcheckbox.h>
14#include <qvbox.h> 14#include <qvbox.h>
15#include <qhbox.h> 15#include <qhbox.h>
16#include <qhbuttongroup.h> 16#include <qhbuttongroup.h>
17#include <qvbuttongroup.h> 17#include <qvbuttongroup.h>
18#include <qmessagebox.h> 18#include <qmessagebox.h>
19#include <qpushbutton.h> 19#include <qpushbutton.h>
20 20
21DemoApp::DemoApp( int argc, char** argv ) : OApplication( argc, argv, "libopie2 notify demo" ) 21DemoApp::DemoApp( int argc, char** argv ) : OApplication( argc, argv, "libopie2 notify demo" )
22 { 22 {
23 23
24 QVBox* vbox = new QVBox(); 24 QVBox* vbox = new QVBox();
25 setMainWidget( vbox ); 25 setMainWidget( vbox );
26 26
27 l = new OListView( vbox ); 27 l = new OListView( vbox );
28 l->addColumn( "Notification Path" ); 28 l->addColumn( "Notification Path" );
29 l->addColumn( "Trigger Type" ); 29 l->addColumn( "Trigger Type" );
30 l->addColumn( "Trigger Mask" ); 30 l->addColumn( "Trigger Mask" );
31 l->setColumnAlignment( 1, AlignCenter ); 31 l->setColumnAlignment( 1, AlignCenter );
32 l->setColumnAlignment( 2, AlignCenter ); 32 l->setColumnAlignment( 2, AlignCenter );
33 33
34 QHBox* hbox = new QHBox( vbox ); 34 QHBox* hbox = new QHBox( vbox );
35
36 g2 = new QVButtonGroup( "Specify Trigger Type", hbox ); 35 g2 = new QVButtonGroup( "Specify Trigger Type", hbox );
37 //QCheckBox* c1 = new QCheckBox( "Multi", g2 ); 36 QCheckBox* c1 = new QCheckBox( "Access", g2 );
38 QCheckBox* c2 = new QCheckBox( "Access", g2 ); 37 QCheckBox* c2 = new QCheckBox( "Modify", g2 );
39 QCheckBox* c3 = new QCheckBox( "Modify", g2 ); 38 QCheckBox* c3 = new QCheckBox( "Attrib", g2 );
40 QCheckBox* c4 = new QCheckBox( "Create", g2 ); 39 QCheckBox* c4 = new QCheckBox( "CloseWrite", g2 );
41 QCheckBox* c5 = new QCheckBox( "Delete", g2 ); 40 QCheckBox* c5 = new QCheckBox( "CloseNoWrite", g2 );
42 QCheckBox* c6 = new QCheckBox( "Rename", g2 ); 41 QCheckBox* c6 = new QCheckBox( "MovedFrom", g2 );
43 QCheckBox* c7 = new QCheckBox( "Attrib", g2 ); 42 QCheckBox* c7 = new QCheckBox( "MovedTo", g2 );
44 g2->insert( c2, Access ); 43 QCheckBox* c8 = new QCheckBox( "DeleteSubdir", g2 );
45 g2->insert( c3, Modify ); 44 QCheckBox* c9 = new QCheckBox( "DeleteFile", g2 );
46 g2->insert( c4, Create ); 45 QCheckBox* c10 = new QCheckBox( "CreateSubdir", g2 );
47 g2->insert( c5, Delete ); 46 QCheckBox* c11 = new QCheckBox( "CreateFile", g2 );
48 g2->insert( c6, Rename ); 47 QCheckBox* c12 = new QCheckBox( "Unmount", g2 );
49 g2->insert( c7, Attrib ); 48 g2->insert( c1, Access );
49 g2->insert( c2, Modify );
50 g2->insert( c3, Attrib );
51 g2->insert( c4, CloseWrite );
52 g2->insert( c5, CloseNoWrite );
53 g2->insert( c6, MovedFrom );
54 g2->insert( c7, MovedTo );
55 g2->insert( c8, DeleteSubdir );
56 g2->insert( c9, DeleteFile );
57 g2->insert( c10, CreateSubdir );
58 g2->insert( c11, CreateFile );
59 g2->insert( c12, Unmount );
50 connect( g2, SIGNAL( pressed(int) ), this, SLOT( modifierClicked(int) ) ); 60 connect( g2, SIGNAL( pressed(int) ), this, SLOT( modifierClicked(int) ) );
51 61
52 g1 = new QVButtonGroup( "Add/Remove", hbox ); 62 g1 = new QVButtonGroup( "Add/Remove", hbox );
53 QPushButton* plus1 = new QPushButton( "Add\n&Single", g1 ); 63 QPushButton* plus1 = new QPushButton( "Add\n&Single", g1 );
54 QPushButton* plus2 = new QPushButton( "Add\n&Multi", g1 ); 64 QPushButton* plus2 = new QPushButton( "Add\n&Multi", g1 );
55 QPushButton* minus = new QPushButton( "&Remove\nIt!", g1 ); 65 QPushButton* minus = new QPushButton( "&Remove\nIt!", g1 );
56 g1->insert( plus1, 0 ); 66 g1->insert( plus1, 0 );
57 g1->insert( plus2, 1 ); 67 g1->insert( plus2, 1 );
58 g1->insert( minus, 2 ); 68 g1->insert( minus, 2 );
59 connect( plus1, SIGNAL( clicked() ), this, SLOT( addSingle() ) ); 69 connect( plus1, SIGNAL( clicked() ), this, SLOT( addSingle() ) );
60 connect( plus2, SIGNAL( clicked() ), this, SLOT( addMulti() ) ); 70 connect( plus2, SIGNAL( clicked() ), this, SLOT( addMulti() ) );
61 connect( minus, SIGNAL( clicked() ), this, SLOT( delTrigger() ) ); 71 connect( minus, SIGNAL( clicked() ), this, SLOT( delTrigger() ) );
62 72
63 g1->show(); 73 g1->show();
64 g2->show(); 74 g2->show();
65 l->show(); 75 l->show();
66 hbox->show(); 76 hbox->show();
67 vbox->show(); 77 vbox->show();
68 showMainWidget( vbox ); 78 showMainWidget( vbox );
69 } 79 }
70 80
71 void DemoApp::addTrigger( bool multi ) 81 void DemoApp::addTrigger( bool multi )
72 { 82 {
73 if ( !m ) 83 if ( !m )
74 { 84 {
75 QMessageBox::warning( 0, "Add Trigger", "<p>Can't add trigger without at least one selected trigger type</p>", "&Sorry", 0 ); 85 QMessageBox::warning( 0, "Add Trigger", "<p>Can't add trigger without at least one selected trigger type</p>", "&Sorry", 0 );
76 return; 86 return;
77 } 87 }
78 88
79 QString filename = OFileDialog::getOpenFileName( OFileSelector::ExtendedAll ); 89 QString filename = OFileDialog::getOpenFileName( OFileSelector::ExtendedAll );
80 if ( !filename.isEmpty() ) 90 if ( !filename.isEmpty() )
81 { 91 {
82 odebug << "Filename = " << filename << oendl; 92 odebug << "Filename = " << filename << oendl;
83 93
84 int fntype = m; 94 int fntype = m;
85 if ( multi ) fntype |=(int) Multi;
86
87 QString modifier = QString().sprintf( " = 0x%08x", fntype ); 95 QString modifier = QString().sprintf( " = 0x%08x", fntype );
88 new OListViewItem( l, filename, multi ? "MULTI" : "SINGLE", modifier ); 96 new OListViewItem( l, filename, multi ? "MULTI" : "SINGLE", modifier );
89 if ( !multi ) 97 if ( !multi )
90 OFileNotification::singleShot( filename, this, SLOT( trigger() ), (OFileNotificationType) fntype ); 98 OFileNotification::singleShot( filename, this, SLOT( trigger() ), (OFileNotificationType) fntype );
91 else 99 else
92 OFileNotification::singleShot( filename, this, SLOT( trigger() ), (OFileNotificationType) fntype ); 100 odebug << "not yet implemented..." << oendl;
93 } 101 }
94 else 102 else
95 { 103 {
96 odebug << "cancelled." << oendl; 104 odebug << "cancelled." << oendl;
97 } 105 }
98 } 106 }
99 107
100 void DemoApp::modifierClicked( int modifier ) { m = static_cast<OFileNotificationType>( (int)m ^ int(modifier) ); }; 108 void DemoApp::modifierClicked( int modifier ) { m = static_cast<OFileNotificationType>( (int)m ^ int(modifier) ); };
101 void DemoApp::addSingle() { addTrigger(); }; 109 void DemoApp::addSingle() { addTrigger(); };
102 void DemoApp::addMulti() { addTrigger( true ); }; 110 void DemoApp::addMulti() { addTrigger( true ); };
103 111
104 void DemoApp::delTrigger() 112 void DemoApp::delTrigger()
105 { 113 {
106 QListViewItem* item = l->selectedItem(); 114 QListViewItem* item = l->selectedItem();
107 if ( !item ) 115 if ( !item )
108 { 116 {
109 QMessageBox::warning( 0, "Del Trigger", "<p>No trigger selected!</p>", "&Sorry", 0 ); 117 QMessageBox::warning( 0, "Del Trigger", "<p>No trigger selected!</p>", "&Sorry", 0 );
110 return; 118 return;
111 } 119 }
112 else 120 else
113 { 121 {
114 QString filename( item->text( 0 ) ); 122 QString filename( item->text( 0 ) );
115 odebug << "Filename = " << filename << oendl; 123 odebug << "Filename = " << filename << oendl;
116 } 124 }
diff --git a/libopie2/opiecore/ofilenotify.cpp b/libopie2/opiecore/ofilenotify.cpp
index 2a9bb8c..c221e58 100644
--- a/libopie2/opiecore/ofilenotify.cpp
+++ b/libopie2/opiecore/ofilenotify.cpp
@@ -1,322 +1,228 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3 =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de> 3 =. Copyright (C) 2004-2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org> 4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org>
5          .>+-= 5          .>+-=
6_;:,     .>    :=|. This program is free software; you can 6_;:,     .>    :=|. This program is free software; you can
7.> <`_,   >  .   <= redistribute it and/or modify it under 7.> <`_,   >  .   <= redistribute it and/or modify it under
8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public 8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
9.="- .-=="i,     .._ License as published by the Free Software 9.="- .-=="i,     .._ License as published by the Free Software
10- .   .-<_>     .<> Foundation; either version 2 of the License, 10- .   .-<_>     .<> Foundation; version 2 of the License.
11    ._= =}       : or (at your option) any later version. 11    ._= =}       :
12   .%`+i>       _;_. 12   .%`+i>       _;_.
13   .i_,=:_.      -<s. This program is distributed in the hope that 13   .i_,=:_.      -<s. This program is distributed in the hope that
14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY; 14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
15   : ..    .:,     . . . without even the implied warranty of 15   : ..    .:,     . . . without even the implied warranty of
16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A 16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU 17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
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#include "ofilenotify.h" 29#include "ofilenotify.h"
30using namespace Opie::Core; 30using namespace Opie::Core;
31 31
32/* OPIE */ 32/* OPIE */
33 33
34/* QT */ 34/* QT */
35#include <qobject.h> 35#include <qobject.h>
36#include <qsocketnotifier.h>
36#include <qsignal.h> 37#include <qsignal.h>
37#include <qintdict.h> 38#include <qintdict.h>
38#include <qdir.h> 39#include <qdir.h>
39 40
40/* STD */ 41/* STD */
41#include <sys/types.h> 42#include <sys/types.h>
42#include <sys/stat.h> 43#include <sys/stat.h>
43#include <assert.h> 44#include <sys/ioctl.h>
44#include <fcntl.h> 45#include <fcntl.h>
46#include <assert.h>
45#include <string.h> 47#include <string.h>
46#include <errno.h> 48#include <errno.h>
47#include <unistd.h> 49#include <unistd.h>
48 50
49static QIntDict<OFileNotification> notification_list; 51static QIntDict<OFileNotification> notification_list;
50 52
53QSocketNotifier* OFileNotification::_sn;
54int OFileNotification::_fd = -1;
55
56#define INOTIFY_DEVICE "/dev/inotify"
57
51namespace Opie { 58namespace Opie {
52namespace Core { 59namespace Core {
53 60
54OFileNotification::OFileNotification( QObject* parent, const char* name ) 61OFileNotification::OFileNotification( QObject* parent, const char* name )
55 :QObject( parent, name ), _active( false ) 62 :QObject( parent, name ), _active( false ), _multi( true )
56{ 63{
57 qDebug( "OFileNotification::OFileNotification()" ); 64 qDebug( "OFileNotification::OFileNotification()" );
58} 65}
59 66
60 67
61OFileNotification::~OFileNotification() 68OFileNotification::~OFileNotification()
62{ 69{
70 stop();
63 qDebug( "OFileNotification::~OFileNotification()" ); 71 qDebug( "OFileNotification::~OFileNotification()" );
64} 72}
65 73
66 74
67bool OFileNotification::isActive() const 75bool OFileNotification::isActive() const
68{ 76{
69 return _active; 77 return _active;
70} 78}
71 79
72 80
73int OFileNotification::start( const QString& path, bool sshot, OFileNotificationType type ) 81int OFileNotification::watch( const QString& path, bool sshot, OFileNotificationType type )
74{ 82{
75 _path = QString::null; 83 if ( QFile::exists( path ) )
76 _fd = 0;
77 if ( _active ) stop();
78 QString dirpath;
79
80 // check if path exists and whether it is a file or a directory, if it exists at all
81 int result = ::stat( (const char*) path, &_stat );
82 if ( !(type & Create) && result == -1 )
83 {
84 qWarning( "OFileNotification::start(): Can't stat '%s': %s.", (const char*) path, strerror( errno ) );
85 return -1;
86 }
87
88 // if it is not a directory, we need to find out in which directory the file is
89 bool isDirectory = S_ISDIR( _stat.st_mode );
90 if ( !isDirectory )
91 {
92 int slashpos;
93 slashpos = path.findRev( '/' );
94 if ( slashpos > 0 )
95 {
96 _path = path;
97 dirpath = path.left( slashpos );
98 }
99 }
100 else /* isDirectory */
101 {
102 qWarning( "FIXME FIXME FIXME = Directory Notification Not Yet Implemented!" );
103 _path = path;
104 dirpath = path;
105 assert( 0 );
106 }
107
108 int fd = ::open( (const char*) dirpath, O_RDONLY );
109 if ( fd != -1 )
110 { 84 {
111 if ( notification_list.isEmpty() ) 85 if ( notification_list.isEmpty() )
112 { 86 {
113 OFileNotification::registerSignalHandler(); 87 OFileNotification::registerEventHandler();
114 } 88 }
115 89
116 result = ::fcntl( fd, F_SETSIG, SIGRTMIN ); 90 struct inotify_watch_request iwr;
117 if ( result == -1 ) 91 ::memset( &iwr, 0, sizeof iwr );
118 { 92 iwr.name = const_cast<char*>( (const char*) path );
119 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) ); 93 iwr.mask = type;
120 return -1; 94
121 } 95 _wd = ::ioctl( OFileNotification::_fd, INOTIFY_WATCH, &iwr );
122 if ( !sshot ) type = static_cast<OFileNotificationType>( (int) type | (int) Multi ); 96
123 result = ::fcntl( fd, F_NOTIFY, type ); 97 if ( _wd < 0 )
124 if ( result == -1 )
125 { 98 {
126 qWarning( "OFileNotification::start(): Can't subscribe to '%s': %s.", (const char*) dirpath, strerror( errno ) ); 99 qWarning( "OFileNotification::watch(): inotify can't watch '%s': %s.", (const char*) path, strerror( errno ) );
127 return -1; 100 return -1;
128 } 101 }
129 qDebug( "OFileNotification::start(): Subscribed for changes to %s (fd = %d, mask = 0x%0x)", (const char*) dirpath, fd, type ); 102
130 notification_list.insert( fd, this ); 103 notification_list.insert( _wd, this );
104 _multi = !sshot;
131 _type = type; 105 _type = type;
132 _fd = fd;
133 _active = true; 106 _active = true;
134 ::memset( &_stat, 0, sizeof _stat ); 107 qDebug( "OFileNotification::watch(): watching '%s' [wd=%d].", (const char*) path, _wd );
135 ::stat( _path, &_stat ); 108 return _wd;
136 return fd;
137 } 109 }
138 else 110 else
139 { 111 {
140 qWarning( "OFileNotification::start(): Error with path '%s': %s.", (const char*) dirpath, strerror( errno ) ); 112 qWarning( "OFileNotification::watch(): Can't watch '%s': %s.", (const char*) path, strerror( errno ) );
141 return -1; 113 return -1;
142 } 114 }
143} 115}
144 116
145 117
146void OFileNotification::stop() 118void OFileNotification::stop()
147{ 119{
148 if ( !_active ) return; 120 notification_list.remove( _wd );
149 121 _path = QString::null;
150 int result = ::fcntl( _fd, F_NOTIFY, 0 ); 122 _wd = 0;
151 if ( result == -1 ) 123 _active = false;
152 { 124 if ( notification_list.isEmpty() )
153 qWarning( "OFileNotification::stop(): Can't remove subscription to '%s': %s.", (const char*) _path, strerror( errno ) );
154 }
155 else
156 { 125 {
157 ::close( _fd ); 126 OFileNotification::unregisterEventHandler();
158 _type = Single;
159 _path = QString::null;
160 _fd = 0;
161 _active = false;
162 } 127 }
163} 128}
164 129
165 130
166OFileNotificationType OFileNotification::type() const 131OFileNotificationType OFileNotification::type() const
167{ 132{
168 return _type; 133 return _type;
169} 134}
170 135
171 136
172QString OFileNotification::path() const 137QString OFileNotification::path() const
173{ 138{
174 return _path; 139 return _path;
175} 140}
176 141
177 142
178int OFileNotification::fileno() const 143bool OFileNotification::activate()
179{ 144{
180 return _fd; 145 emit triggered();
146 _signal.activate();
147 if ( !_multi ) stop();
148 return true;
181} 149}
182 150
183 151
184bool OFileNotification::activate() 152void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type )
185{ 153{
186 if ( hasChanged() ) 154 OFileNotification* ofn = new OFileNotification();
187 { 155 ofn->_signal.connect( receiver, member );
188 emit triggered(); 156 ofn->watch( path, true, type );
189 _signal.activate();
190 return true;
191 }
192 else
193 return false;
194} 157}
195 158
196 159
197bool OFileNotification::hasChanged() 160void OFileNotification::inotifyEventHandler()
198{ 161{
199 bool c = false; 162 qWarning( "OFileNotification::__eventHandler(): reached." );
200 163
201 struct stat newstat; 164 char buffer[16384];
202 ::memset( &newstat, 0, sizeof newstat ); 165 size_t buffer_i;
203 int result = ::stat( _path, &newstat ); // may fail if file has been renamed or deleted. that doesn't matter :) 166 struct inotify_event *pevent, *event;
167 ssize_t r;
168 size_t event_size;
169 int count = 0;
204 170
205 qDebug( "result of newstat call is %d (%s=%d)", result, result == -1 ? strerror( errno ) : "success", errno ); 171 r = ::read(_fd, buffer, 16384);
206 qDebug( "stat.atime = %0lx, newstat.atime = %0lx", (long)_stat.st_atime, (long)newstat.st_atime );
207 qDebug( "stat.mtime = %0lx, newstat.mtime = %0lx", (long)_stat.st_mtime, (long)newstat.st_mtime );
208 qDebug( "stat.ctime = %0lx, newstat.ctime = %0lx", (long)_stat.st_ctime, (long)newstat.st_ctime );
209 172
210 if ( !c && (_type & Create) && 173 if ( r <= 0 )
211 (long)_stat.st_atime == 0 && (long)_stat.st_mtime == 0 && (long)_stat.st_ctime == 0 && 174 return;
212 (long)newstat.st_atime > 0 && (long)newstat.st_mtime > 0 && (long)newstat.st_ctime > 0) 175
213 { 176 buffer_i = 0;
214 qDebug( "OFileNotification::hasChanged(): file has been created" ); 177 while ( buffer_i < r )
215 c = true;
216 }
217 if ( !c && (_type & (Delete|Rename)) && (long)newstat.st_atime == 0 && (long)newstat.st_mtime == 0 && (long)newstat.st_ctime == 0)
218 {
219 qDebug( "OFileNotification::hasChanged(): file has been deleted or renamed" );
220 c = true;
221 }
222 if ( !c && (_type & Access) && (long)_stat.st_atime < (long)newstat.st_atime )
223 {
224 qDebug( "OFileNotification::hasChanged(): atime changed" );
225 c = true;
226 }
227 if ( !c && (_type & Modify) && (long)_stat.st_mtime < (long)newstat.st_mtime )
228 {
229 qDebug( "OFileNotification::hasChanged(): mtime changed" );
230 c = true;
231 }
232 if ( !c && (_type & Attrib) && (long)_stat.st_ctime < (long)newstat.st_ctime )
233 { 178 {
234 qDebug( "OFileNotification::hasChanged(): ctime changed" ); 179 /* Parse events and queue them ! */
235 c = true; 180 pevent = (struct inotify_event *)&buffer[buffer_i];
236 } 181 event_size = sizeof(struct inotify_event) + pevent->len;
182 qDebug( "pevent->len = %d\n", pevent->len);
237 183
238 return c; 184 OFileNotification* fn = notification_list[ pevent->wd ];
239} 185 if ( fn )
186 fn->activate();
187 else
188 assert( false );
240 189
190 //event = malloc(event_size);
191 //memmove(event, pevent, event_size);
192 //queue_enqueue(event, q);
193 buffer_i += event_size;
194 count++;
195 }
241 196
242void OFileNotification::singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type ) 197 qDebug( "received %d events...", count );
243{ 198 return;
244 OFileNotification* ofn = new OFileNotification();
245 ofn->_signal.connect( receiver, member );
246 ofn->start( path, true, type );
247} 199}
248 200
249 201
250void OFileNotification::__signalHandler( int sig, siginfo_t *si, void *data ) 202bool OFileNotification::registerEventHandler()
251{ 203{
252 Q_UNUSED( sig ) 204 OFileNotification::_fd = ::open( INOTIFY_DEVICE, O_RDONLY );
253 Q_UNUSED( data ) 205 if ( OFileNotification::_fd < 0 )
254 qWarning( "OFileNotification::__signalHandler(): reached." );
255 int fd = si->si_fd;
256 OFileNotification* fn = notification_list[fd];
257 if ( fn )
258 {
259 // check if it really was the file (dnotify triggers on directory granularity, not file granularity)
260 if ( !fn->activate() )
261 {
262 qDebug( "OFileNotification::__signalHandler(): false alarm ;) Restarting the trigger (if it was single)..." );
263 if ( !(fn->type() & Multi ) )
264 {
265 int result = ::fcntl( fn->fileno(), F_NOTIFY, fn->type() );
266 if ( result == -1 )
267 {
268 qWarning( "OFileNotification::__signalHandler(): Can't restart the trigger: %s.", strerror( errno ) );
269 }
270 }
271 return;
272 }
273 #if 1
274 if ( !(fn->type() & Multi) )
275 {
276 qDebug( "OFileNotification::__signalHandler(): '%d' was singleShot. Removing from list.", fd );
277 notification_list.remove( fd );
278 if ( notification_list.isEmpty() )
279 {
280 OFileNotification::unregisterSignalHandler();
281 }
282 }
283 #endif
284 }
285 else
286 { 206 {
287 qWarning( "OFileNotification::__signalHandler(): D'oh! Called without fd in notification_list. Race condition?" ); 207 qWarning( "OFileNotification::registerEventHandler(): couldn't register event handler: %s", strerror( errno ) );
208 return false;
288 } 209 }
289}
290 210
211 OFileNotification::_sn = new QSocketNotifier( _fd, QSocketNotifier::Read, this, "inotify event" );
212 connect( OFileNotification::_sn, SIGNAL( activated(int) ), this, SLOT( inotifyEventHandler() ) );
291 213
292bool OFileNotification::registerSignalHandler() 214 qDebug( "OFileNotification::registerEventHandler(): done" );
293{
294 struct sigaction act;
295 act.sa_sigaction = OFileNotification::__signalHandler;
296 ::sigemptyset( &act.sa_mask );
297 act.sa_flags = SA_SIGINFO;
298 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
299 {
300 qWarning( "OFileNotification::registerSignalHandler(): couldn't register signal handler: %s", strerror( errno ) );
301 return false;
302 }
303 qDebug( "OFileNotification::registerSignalHandler(): done" );
304 return true; 215 return true;
305} 216}
306 217
307 218
308void OFileNotification::unregisterSignalHandler() 219void OFileNotification::unregisterEventHandler()
309{ 220{
310 struct sigaction act; 221 if ( OFileNotification::_fd )
311 act.sa_sigaction = ( void (*)(int, siginfo_t*, void*) ) SIG_DFL; 222 ::close( OFileNotification::_fd );
312 ::sigemptyset( &act.sa_mask ); 223 qDebug( "OFileNotification::unregisterEventHandler(): done" );
313 if ( ::sigaction( SIGRTMIN, &act, NULL ) == -1 )
314 {
315 qWarning( "OFileNotification::unregisterSignalHandler(): couldn't deregister signal handler: %s", strerror( errno ) );
316 }
317 qDebug( "OFileNotification::unregisterSignalHandler(): done" );
318} 224}
319 225
320 226
321} 227}
322} 228}
diff --git a/libopie2/opiecore/ofilenotify.h b/libopie2/opiecore/ofilenotify.h
index d820f7c..e3621cf 100644
--- a/libopie2/opiecore/ofilenotify.h
+++ b/libopie2/opiecore/ofilenotify.h
@@ -1,190 +1,197 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3 =. Copyright (C) 2004 Michael 'Mickey' Lauer <mickey@Vanille.de> 3 =. Copyright (C) 2004-2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org> 4 .=l. Copyright (C) The Opie Team <opie-devel@handhelds.org>
5          .>+-= 5          .>+-=
6_;:,     .>    :=|. This program is free software; you can 6_;:,     .>    :=|. This program is free software; you can
7.> <`_,   >  .   <= redistribute it and/or modify it under 7.> <`_,   >  .   <= redistribute it and/or modify it under
8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public 8:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
9.="- .-=="i,     .._ License as published by the Free Software 9.="- .-=="i,     .._ License as published by the Free Software
10- .   .-<_>     .<> Foundation; either version 2 of the License, 10- .   .-<_>     .<> Foundation; version 2 of the License.
11    ._= =}       : or (at your option) any later version. 11    ._= =}       :
12   .%`+i>       _;_. 12   .%`+i>       _;_.
13   .i_,=:_.      -<s. This program is distributed in the hope that 13   .i_,=:_.      -<s. This program is distributed in the hope that
14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY; 14    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
15   : ..    .:,     . . . without even the implied warranty of 15   : ..    .:,     . . . without even the implied warranty of
16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A 16   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU 17 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
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/* QT */ 35/* QT */
36#include <qobject.h> 36#include <qsocketnotifier.h>
37#include <qsignal.h> 37#include <qsignal.h>
38#include <qstring.h> 38#include <qstring.h>
39 39
40/* STD */ 40/* STD */
41#include <signal.h> 41#include "inotify.h"
42#include <fcntl.h>
43 42
44namespace Opie { 43namespace Opie {
45namespace Core { 44namespace Core {
46 45
47/*====================================================================================== 46/*======================================================================================
48 * OFileNotificationType 47 * OFileNotificationType
49 *======================================================================================*/ 48 *======================================================================================*/
50 49
51/** 50/**
52 * @brief An enumerate for the different types of file notifications 51 * @brief An enumerate for the different types of file notifications
53 * 52 *
54 * This enumerate provides a means to specify the type of events that you are interest in. 53 * This enumerate provides a means to specify the type of events that you are interest in.
55 * Valid values are: 54 * Valid values are:
56 * <ul> 55 * <ul>
57 * <li>Access: The file was accessed (read) 56 * <li>Access: The file was accessed (read)
58 * <li>Modify The file was modified (write,truncate) 57 * <li>Modify The file was modified (write,truncate)
59 * <li>Create = The file was created in the directory
60 * <li>Delete = The file was unlinked from directory
61 * <li>Rename = The file was renamed
62 * <li>Attrib = The file had its attributes changed (chmod,chown,chgrp) 58 * <li>Attrib = The file had its attributes changed (chmod,chown,chgrp)
59 * <li>CloseWrite = Writable file was closed
60 * <li>CloseNoWrite = Unwritable file was closed
61 * <li>Open = File was opened
62 * <li>MovedFrom = File was moved from X
63 * <li>MovedTo = File was moved to Y
64 * <li>DeleteSubdir = Subdir was deleted
65 * <li>DeleteFile = Subfile was deleted
66 * <li>CreateSubdir = Subdir was created
67 * <li>CreateFile = Subfile was created
68 * <li>DeleteSelf = Self was deleted
69 * <li>Unmount = The backing filesystem was unmounted
63 * </ul> 70 * </ul>
64 * 71 *
65 **/ 72 **/
66 73
67enum OFileNotificationType { Single = 0x0000000, 74enum OFileNotificationType
68 Multi = DN_MULTISHOT, 75{
69 Access = DN_ACCESS, 76 Access = IN_ACCESS,
70 Modify = DN_MODIFY, 77 Modify = IN_MODIFY,
71 Create = DN_CREATE, 78 Attrib = IN_ATTRIB,
72 Delete = DN_DELETE, 79 CloseWrite = IN_CLOSE_WRITE,
73 Rename = DN_RENAME, 80 CloseNoWrite = IN_CLOSE_NOWRITE,
74 Attrib = DN_ATTRIB }; 81 Open = IN_OPEN,
82 MovedFrom = IN_MOVED_FROM,
83 MovedTo = IN_MOVED_TO,
84 DeleteSubdir = IN_DELETE_SUBDIR,
85 DeleteFile = IN_DELETE_FILE,
86 CreateSubdir = IN_CREATE_SUBDIR,
87 CreateFile = IN_CREATE_FILE,
88 DeleteSelf = IN_DELETE_SELF,
89 Unmount = IN_UNMOUNT,
90 _QueueOverflow = IN_Q_OVERFLOW, /* Internal, don't use this in client code */
91 _Ignored = IN_IGNORED, /* Internal, don't use this in client code */
92};
75 93
76/*====================================================================================== 94/*======================================================================================
77 * OFileNotification 95 * OFileNotification
78 *======================================================================================*/ 96 *======================================================================================*/
79 97
80/** 98/**
81 * @brief Represents a file notification 99 * @brief Represents a file notification
82 * 100 *
83 * This class allows to watch for events happening to files. 101 * This class allows to watch for events happening to files.
84 * It uses the dnotify kernel interface which is a very efficient signalling interface. 102 * It uses the inotify kernel interface
85 * 103 *
86 * @see <file:///usr/src/linux/Documentation/dnotify.txt> 104 * @see http://www.kernel.org/pub/linux/kernel/people/rml/inotify/
87 * 105 *
88 * @author Michael 'Mickey' Lauer <mickey@vanille.de> 106 * @author Michael 'Mickey' Lauer <mickey@vanille.de>
89 * 107 *
90 **/ 108 **/
91 109
92class OFileNotification : public QObject 110class OFileNotification : public QObject
93{ 111{
94 Q_OBJECT 112 Q_OBJECT
95 113
96 public: 114 public:
97 OFileNotification( QObject* parent = 0, const char* name = 0 ); 115 OFileNotification( QObject* parent = 0, const char* name = 0 );
98 ~OFileNotification(); 116 ~OFileNotification();
99 /** 117 /**
100 * This static function calls a slot when an event with @a type happens to file @a path. 118 * This static function calls a slot when an event with @a type happens to file @a path.
101 * 119 *
102 * It is very convenient to use this function because you do not need to 120 * It is very convenient to use this function because you do not need to
103 * bother with a timerEvent or to create a local QTimer object. 121 * bother with a timerEvent or to create a local QTimer object.
104 * 122 *
105 * Example: 123 * Example:
106 * <pre> 124 * <pre>
107 * 125 *
108 * #include <opie2/oapplication.h> 126 * #include <opie2/oapplication.h>
109 * #include <opie2/onitify.h> 127 * #include <opie2/ofilenotify.h>
110 * using namespace Opie::Core; 128 * using namespace Opie::Core;
111 * 129 *
112 * int main( int argc, char **argv ) 130 * int main( int argc, char **argv )
113 * { 131 * {
114 * OApplication a( argc, argv, "File Notification Example" ); 132 * OApplication a( argc, argv, "File Notification Example" );
115 * OFileNotification::singleShot( "/tmp/quit", &a, SLOT(quit()), Create ); 133 * OFileNotification::singleShot( "/tmp/quit", &a, SLOT(quit()), Create );
116 * ... // create and show your widgets 134 * ... // create and show your widgets
117 * return a.exec(); 135 * return a.exec();
118 * } 136 * }
119 * </pre> 137 * </pre>
120 * 138 *
121 * This sample program automatically terminates when the file "/tmp/quite" has been created. 139 * This sample program automatically terminates when the file "/tmp/quit" has been created.
122 * 140 *
123 * 141 *
124 * The @a receiver is the receiving object and the @a member is the slot. 142 * The @a receiver is the receiving object and the @a member is the slot.
125 **/ 143 **/
126 static void singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify ); 144 static void singleShot( const QString& path, QObject* receiver, const char* member, OFileNotificationType type = Modify );
127 /** 145 /**
128 * Starts to watch for @a type changes to @a path. Set @a sshot to True if you want to be notified only once. 146 * Starts to watch for @a type changes to @a path. Set @a sshot to True if you want to be notified only once.
129 * Note that in that case it may be more convenient to use @ref OFileNotification::singleShot() then. 147 * Note that in that case it may be more convenient to use @ref OFileNotification::singleShot() then.
130 **/ 148 **/
131 int start( const QString& path, bool sshot = false, OFileNotificationType type = Modify ); 149 int watch( const QString& path, bool sshot = false, OFileNotificationType type = Modify );
132 /** 150 /**
133 * Stop watching for file events. 151 * Stop watching for file events.
134 **/ 152 **/
135 void stop(); 153 void stop();
136 /** 154 /**
137 * @returns the notification type as set by @ref start(). 155 * @returns the notification type as set by @ref start().
138 **/ 156 **/
139 OFileNotificationType type() const; 157 OFileNotificationType type() const;
140 /** 158 /**
141 * @returns the path to the file being watched by this instance. 159 * @returns the path to the file being watched by this instance.
142 **/ 160 **/
143 QString path() const; 161 QString path() const;
144 /** 162 /**
145 * @returns the UNIX file descriptor for the file being watched.
146 **/
147 int fileno() const;
148 /**
149 * @returns if a file is currently being watched. 163 * @returns if a file is currently being watched.
150 **/ 164 **/
151 bool isActive() const; 165 bool isActive() const;
152 166
153 signals: 167 signals:
154 /** 168 /**
155 * This signal is emitted if an event happens of the specified type happens to the file being watched. 169 * This signal is emitted if an event happens of the specified type happens to the file being watched.
156 **/ 170 **/
157 void triggered(); 171 void triggered();
158 172
159 protected: 173 protected:
160 bool activate(); 174 bool activate();
161 virtual bool hasChanged(); 175
162 static bool registerSignalHandler(); 176 private slots:
163 static void unregisterSignalHandler(); 177 void inotifyEventHandler();
164 static void __signalHandler( int sig, siginfo_t *si, void *data );
165 178
166 private: 179 private:
180 bool registerEventHandler();
181 void unregisterEventHandler();
182
167 QString _path; 183 QString _path;
168 OFileNotificationType _type; 184 OFileNotificationType _type;
169 QSignal _signal; 185 QSignal _signal;
170 int _fd;
171 bool _active; 186 bool _active;
172 struct stat _stat; 187 bool _multi;
173}; 188 static QSocketNotifier* _sn;
174 189 int _wd; // inotify watch descriptor
175#if 0 190 static int _fd; // inotify device descriptor
176
177class ODirectoryNotification : public OFileNotification
178{
179
180 public:
181 virtual bool hasChanged() { return true; };
182}; 191};
183 192
184#endif
185
186} 193}
187} 194}
188 195
189#endif 196#endif
190 197