// Purpose: kqueue-based wxFileSystemWatcher implementation
// Author: Bartosz Bekier
// Created: 2009-05-26
-// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include <sys/types.h>
#include <sys/event.h>
+
#include "wx/dynarray.h"
+#include "wx/evtloop.h"
+#include "wx/evtloopsrc.h"
+
#include "wx/private/fswatcher.h"
+// ============================================================================
+// wxFSWSourceHandler helper class
+// ============================================================================
+
+class wxFSWatcherImplKqueue;
+
+/**
+ * Handler for handling i/o from inotify descriptor
+ */
+class wxFSWSourceHandler : public wxEventLoopSourceHandler
+{
+public:
+ wxFSWSourceHandler(wxFSWatcherImplKqueue* service) :
+ m_service(service)
+ { }
+
+ virtual void OnReadWaiting();
+ virtual void OnWriteWaiting();
+ virtual void OnExceptionWaiting();
+
+protected:
+ wxFSWatcherImplKqueue* m_service;
+};
+
// ============================================================================
// wxFSWatcherImpl implementation & helper wxFSWSourceHandler implementation
// ============================================================================
public:
wxFSWatcherImplKqueue(wxFileSystemWatcherBase* watcher) :
wxFSWatcherImpl(watcher),
- m_loop(NULL),
m_source(NULL),
m_kfd(-1)
{
m_handler = new wxFSWSourceHandler(this);
}
- ~wxFSWatcherImplKqueue()
+ virtual ~wxFSWatcherImplKqueue()
{
// we close kqueue only if initialized before
if (IsOk())
{
wxCHECK_MSG( !IsOk(), false,
"Kqueue appears to be already initialized" );
- wxCHECK_MSG( m_loop == NULL, false, "Event loop != NULL");
- m_loop = (wxEventLoopBase::GetActive());
- wxCHECK_MSG( m_loop, false, "File system watcher needs an active loop" );
+ wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+ wxCHECK_MSG( loop, false, "File system watcher needs an active loop" );
// create kqueue
m_kfd = kqueue();
}
// create source
- int flags = wxEVENT_SOURCE_INPUT;
- m_source = m_loop->CreateSource(m_kfd, m_handler, flags);
- wxCHECK_MSG( m_source, false,
- "Active loop has no support for fd-based sources" );
+ m_source = loop->AddSourceForFD(m_kfd, m_handler, wxEVENT_SOURCE_INPUT);
- return RegisterSource();
+ return m_source != NULL;
}
- bool Close()
+ void Close()
{
- wxCHECK_MSG( IsOk(), false,
+ wxCHECK_RET( IsOk(),
"Kqueue not initialized or invalid kqueue descriptor" );
- wxCHECK_MSG( m_loop, false,
- "m_loop shouldn't be null if kqueue is initialized" );
-
- // ignore errors
- (void) UnregisterSource();
- int ret = close(m_kfd);
- if (ret == -1)
+ if ( close(m_kfd) != 0 )
{
- wxLogSysError(_("Unable to close kqueue instance"));
+ wxLogSysError(_("Error closing kqueue instance"));
}
- m_source->Invalidate();
- return ret != -1;
+ wxDELETE(m_source);
}
virtual bool DoAdd(wxSharedPtr<wxFSWatchEntryKq> watch)
// TODO more error conditions according to man
// XXX closing file descriptor removes the watch. The logic resides in
// the watch which is not nice, but effective and simple
- bool ret = watch->Close();
- if (ret == -1)
+ if ( !watch->Close() )
{
wxLogSysError(_("Unable to remove kqueue watch"));
return false;
return true;
}
- bool IsOk()
+ bool IsOk() const
{
- return m_source && m_source->IsOk();
+ return m_source != NULL;
}
-/*
- wxAbstractEventLoopSource* GetSource() const
- {
- return m_source;
- }*/
-
protected:
- bool RegisterSource()
- {
- wxCHECK_MSG( IsOk(), false,
- "Kqueue not initialized or invalid kqueue descriptor" );
-
- return m_loop->AddSource(m_source);
- }
-
- bool UnregisterSource()
- {
- wxCHECK_MSG( IsOk(), false,
- "Kqueue not initialized or invalid kqueue descriptor" );
- wxCHECK_MSG( m_loop, false,
- "m_loop shouldn't be null if kqueue is initialized" );
-
- bool ret = m_loop->RemoveSource(m_source);
- m_loop = NULL;
- return ret;
- }
-
// returns all new dirs/files present in the immediate level of the dir
// pointed by watch.GetPath(). "new" means created between the last time
// the state of watch was computed and now
- void FindChanges(wxFSWatchEntryKq& watch, wxArrayString& changedFiles,
- wxArrayInt& changedFlags)
+ void FindChanges(wxFSWatchEntryKq& watch,
+ wxArrayString& changedFiles,
+ wxArrayInt& changedFlags)
{
wxFSWatchEntryKq::wxDirState old = watch.GetLastState();
watch.RefreshState();
while ( nflags )
{
// when monitoring dir, this means create/delete
- if ( nflags & NOTE_WRITE && wxDirExists(w.GetPath()) )
+ const wxString basepath = w.GetPath();
+ if ( nflags & NOTE_WRITE && wxDirExists(basepath) )
{
// NOTE_LINK is set when the dir was created, but we
// don't care - we look for new names in directory
wxArrayString changedFiles;
wxArrayInt changedFlags;
FindChanges(w, changedFiles, changedFlags);
+
wxArrayString::iterator it = changedFiles.begin();
wxArrayInt::iterator changeType = changedFlags.begin();
for ( ; it != changedFiles.end(); ++it, ++changeType )
{
- wxFileName path;
- if ( wxDirExists(*it) )
- {
- path = wxFileName::DirName(w.GetPath() + *it);
- }
- else
- {
- path = wxFileName::FileName(w.GetPath() + *it);
- }
+ const wxString fullpath = w.GetPath() +
+ wxFileName::GetPathSeparator() +
+ *it;
+ const wxFileName path(wxDirExists(fullpath)
+ ? wxFileName::DirName(fullpath)
+ : wxFileName::FileName(fullpath));
wxFileSystemWatcherEvent event(*changeType, path, path);
SendEvent(event);
// still we couldn't be sure we have the right name...
nflags &= ~NOTE_RENAME;
wxFileSystemWatcherEvent event(wxFSW_EVENT_RENAME,
- w.GetPath(), wxFileName());
+ basepath, wxFileName());
SendEvent(event);
}
else if ( nflags & NOTE_WRITE || nflags & NOTE_EXTEND )
{
nflags &= ~(NOTE_WRITE | NOTE_EXTEND);
wxFileSystemWatcherEvent event(wxFSW_EVENT_MODIFY,
- w.GetPath(), w.GetPath());
+ basepath, basepath);
SendEvent(event);
}
else if ( nflags & NOTE_DELETE )
{
nflags &= ~(NOTE_DELETE);
wxFileSystemWatcherEvent event(wxFSW_EVENT_DELETE,
- w.GetPath(), w.GetPath());
+ basepath, basepath);
SendEvent(event);
}
else if ( nflags & NOTE_ATTRIB )
{
nflags &= ~(NOTE_ATTRIB);
wxFileSystemWatcherEvent event(wxFSW_EVENT_ACCESS,
- w.GetPath(), w.GetPath());
+ basepath, basepath);
SendEvent(event);
}
}
wxFSWSourceHandler* m_handler; // handler for kqueue event source
- wxEventLoopBase* m_loop; // event loop we have registered with
- wxAbstractEventLoopSource* m_source; // our event loop source
+ wxEventLoopSource* m_source; // our event loop source
+
+ // descriptor created by kqueue()
int m_kfd;
};
{
if (!Init())
{
- if (m_service)
- {
- delete m_service;
- m_service = NULL;
- }
+ wxDELETE(m_service);
return;
}