Merge SOC2009_FSWATCHER branch into trunk.

Merges everything from the branch with only some minor changes, mostly renamed
wxUSE_FSWATCHER_{INOTIFY,KQUEUE} to wxHAS_{INOTIFY,KQUEUE}.

Add wxFileSystemWatcher and related classes.

Also introduces wxEventLoopSource.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62474 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-10-22 11:35:43 +00:00
parent 40152925d5
commit 6b8ef0b35d
75 changed files with 69755 additions and 60720 deletions

View File

@@ -145,6 +145,14 @@
# endif
#endif /* !defined(wxUSE_FSVOLUME) */
#ifndef wxUSE_FSWATCHER
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_FSWATCHER must be defined, please read comment near the top of this file."
# else
# define wxUSE_FSWATCHER 0
# endif
#endif /* !defined(wxUSE_FSWATCHER) */
#ifndef wxUSE_DYNAMIC_LOADER
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DYNAMIC_LOADER must be defined, please read comment near the top of this file."

View File

@@ -14,6 +14,208 @@
#include "wx/event.h"
#include "wx/utils.h"
#include "wx/hashset.h"
// ----------------------------------------------------------------------------
// wxEventLoopSource: source of i/o for wxEventLoop
// ----------------------------------------------------------------------------
#define wxTRACE_EVT_SOURCE "EventSource"
#if defined(__UNIX__) && (wxUSE_CONSOLE_EVENTLOOP || defined(__WXGTK__) || \
defined(__WXOSX_COCOA__))
#define wxUSE_EVENTLOOP_SOURCE 1
#else
#define wxUSE_EVENTLOOP_SOURCE 0
#endif
#if wxUSE_EVENTLOOP_SOURCE
// handler used to process events on event loop sources
class WXDLLIMPEXP_BASE wxEventLoopSourceHandler
{
public:
// called when descriptor is available for non-blocking read
virtual void OnReadWaiting() = 0;
// called when descriptor is available for non-blocking write
virtual void OnWriteWaiting() = 0;
// called when there is exception on descriptor
virtual void OnExceptionWaiting() = 0;
// virtual dtor for the base class
virtual ~wxEventLoopSourceHandler() { }
};
// those flags describes what events should be reported
enum
{
wxEVENT_SOURCE_INPUT = 0x01,
wxEVENT_SOURCE_OUTPUT = 0x02,
wxEVENT_SOURCE_EXCEPTION = 0x04,
wxEVENT_SOURCE_ALL = wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_OUTPUT |
wxEVENT_SOURCE_EXCEPTION,
};
class wxAbstractEventLoopSource
{
public:
wxAbstractEventLoopSource() :
m_handler(NULL), m_flags(-1)
{}
wxAbstractEventLoopSource(wxEventLoopSourceHandler* handler, int flags) :
m_handler(handler), m_flags(flags)
{}
virtual ~wxAbstractEventLoopSource() { }
virtual bool IsOk() const = 0;
virtual void Invalidate() = 0;
void SetHandler(wxEventLoopSourceHandler* handler)
{
m_handler = handler;
}
wxEventLoopSourceHandler* GetHandler() const
{
return m_handler;
}
void SetFlags(int flags)
{
m_flags = flags;
}
int GetFlags() const
{
return m_flags;
}
protected:
wxEventLoopSourceHandler* m_handler;
int m_flags;
};
// This class is a simple wrapper for OS specific resources than can be a
// source of I/O. On Unix,for instance these are file descriptors.
//
// Instances of this class doesn't take resposibility of any resource you pass
// to them, I.E. you have to release them yourself.
template<class T>
class WXDLLIMPEXP_BASE wxEventLoopSourceBase : public wxAbstractEventLoopSource
{
public:
typedef T Resource;
// copy ctor
wxEventLoopSourceBase(const wxEventLoopSourceBase& source) :
wxAbstractEventLoopSource(source.GetHandler(), source.GetFlags()),
m_res(source.GetResource())
{
}
virtual const T InvalidResource() const
{
return (T)-1;
}
virtual void Invalidate()
{
SetResource(InvalidResource());
SetHandler(NULL);
}
// sets internal value to res
void SetResource(T res)
{
m_res = res;
}
// returns associated resource
T GetResource() const
{
return m_res;
}
virtual bool IsOk() const
{
// flags < 0 are invalid and flags == 0 mean monitoring for nothing
return m_res != InvalidResource() && m_handler && m_flags >=1;
}
protected:
// empty ctor, beacuse we often store event sources as values
wxEventLoopSourceBase() :
wxAbstractEventLoopSource(),
m_res(InvalidResource())
{
}
// ctor setting internal value to the os resource res
wxEventLoopSourceBase(T res, wxEventLoopSourceHandler* handler,
int flags) :
wxAbstractEventLoopSource(handler, flags),
m_res(res)
{ }
T m_res;
};
#if defined(__WXMAC__)
class wxMacEventLoopSource : public wxEventLoopSourceBase<CFRunLoopSourceRef>
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
int GetFileDescriptor() const
{
return m_fd;
}
#endif
protected:
wxMacEventLoopSource() : wxEventLoopSourceBase<CFRunLoopSourceRef>() { }
// ctor setting internal value to the os resource res
wxMacEventLoopSource(CFRunLoopSourceRef res,
wxEventLoopSourceHandler* handler, int flags) :
wxEventLoopSourceBase<CFRunLoopSourceRef>(res, handler, flags)
{
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
int m_fd;
#endif
friend class wxGUIEventLoop;
};
#endif
#if defined(__UNIX__)
class wxUnixEventLoopSource : public wxEventLoopSourceBase<int>
{
protected:
wxUnixEventLoopSource() : wxEventLoopSourceBase<int>() { }
// ctor setting internal value to the os resource res
wxUnixEventLoopSource(int res, wxEventLoopSourceHandler* handler,
int flags) :
wxEventLoopSourceBase<int>(res, handler, flags)
{
}
friend class wxConsoleEventLoop;
friend class wxGUIEventLoop;
};
#endif
// the list of watched sources
WX_DECLARE_HASH_SET(wxAbstractEventLoopSource*, wxPointerHash, wxPointerEqual,
wxEventLoopSourceHashSet);
#endif
/*
NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
@@ -64,6 +266,68 @@ public:
// returns true if this is the main loop
bool IsMain() const;
#if wxUSE_EVENTLOOP_SOURCE
virtual wxAbstractEventLoopSource* CreateSource() const = 0;
virtual wxAbstractEventLoopSource* CreateSource(int WXUNUSED(res),
wxEventLoopSourceHandler* WXUNUSED(handler),
int WXUNUSED(flags)) const
{
return NULL;
}
// adds source to be monitored for I/O events specified in flags. Upon an
// event the appropriate method of handler will be called. The handler is
// owned be the calling client and will not be freed in any case.
// Returns true if the source was successfully added, false if it failed
// (this may happen for example when this source is already monitored)
virtual bool AddSource(wxAbstractEventLoopSource* source)
{
wxCHECK_MSG( source && source->IsOk(), false, "Invalid source" );
wxEventLoopSourceHashSet::value_type val(source);
if (!m_sourceMap.insert(val).second)
{
return false;
}
bool ret = DoAddSource(source);
if (!ret)
{
(void) m_sourceMap.erase(source);
}
return ret;
}
// removes the source from the list of monitored sources.
// Returns true if the source was successfully removed, false otherwise
virtual bool RemoveSource(wxAbstractEventLoopSource* source)
{
wxCHECK_MSG( source && source->IsOk(), false, "Invalid source" );
if (m_sourceMap.find(source) == m_sourceMap.end())
{
return false;
}
bool ret = DoRemoveSource(source);
m_sourceMap.erase(source);
return ret;
}
bool RemoveAllSources()
{
wxEventLoopSourceHashSet::iterator it = m_sourceMap.begin();
while ( !m_sourceMap.empty() )
{
(void) RemoveSource(*it);
m_sourceMap.erase(it);
it = m_sourceMap.begin();
}
return true;
}
#endif
// dispatch&processing
// -------------------
@@ -114,25 +378,25 @@ public:
// Yield-related hooks
// -------------------
// process all currently pending events right now
//
// it is an error to call Yield() recursively unless the value of
// onlyIfNeeded is true
//
// WARNING: this function is dangerous as it can lead to unexpected
// reentrancies (i.e. when called from an event handler it
// may result in calling the same event handler again), use
// with _extreme_ care or, better, don't use at all!
// process all currently pending events right now
//
// it is an error to call Yield() recursively unless the value of
// onlyIfNeeded is true
//
// WARNING: this function is dangerous as it can lead to unexpected
// reentrancies (i.e. when called from an event handler it
// may result in calling the same event handler again), use
// with _extreme_ care or, better, don't use at all!
bool Yield(bool onlyIfNeeded = false);
virtual bool YieldFor(long eventsToProcess) = 0;
// returns true if the main thread is inside a Yield() call
// returns true if the main thread is inside a Yield() call
virtual bool IsYielding() const
{ return m_isInsideYield; }
// returns true if events of the given event category should be immediately
// processed inside a wxApp::Yield() call or rather should be queued for
// later processing by the main event loop
// returns true if events of the given event category should be immediately
// processed inside a wxApp::Yield() call or rather should be queued for
// later processing by the main event loop
virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
{ return (m_eventsToProcessInsideYield & cat) != 0; }
@@ -150,6 +414,13 @@ public:
protected:
#if wxUSE_EVENTLOOP_SOURCE
virtual bool DoAddSource(wxAbstractEventLoopSource* source) = 0;
virtual bool DoRemoveSource(wxAbstractEventLoopSource* source) = 0;
wxEventLoopSourceHashSet m_sourceMap;
#endif
// this function should be called before the event loop terminates, whether
// this happens normally (because of Exit() call) or abnormally (because of
// an exception thrown from inside the loop)
@@ -223,7 +494,7 @@ private:
#include "wx/cocoa/evtloop.h"
#elif defined(__WXDFB__)
#include "wx/dfb/evtloop.h"
#elif defined(__WXGTK20__)
#elif defined(__WXGTK__)
#include "wx/gtk/evtloop.h"
#else // other platform

333
include/wx/fswatcher.h Normal file
View File

@@ -0,0 +1,333 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/fswatcher.h
// Purpose: wxFileSystemWatcherBase
// Author: Bartosz Bekier
// Created: 2009-05-23
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_BASE_H_
#define _WX_FSWATCHER_BASE_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
#include "wx/log.h"
#include "wx/event.h"
#include "wx/evtloop.h"
#include "wx/filename.h"
#include "wx/dir.h"
#include "wx/hashmap.h"
#define wxTRACE_FSWATCHER "fswatcher"
// ----------------------------------------------------------------------------
// wxFileSystemWatcherEventType & wxFileSystemWatcherEvent
// ----------------------------------------------------------------------------
/**
* Possible types of file system events.
* This is a subset that will work fine an all platforms (actually, we will
* see how it works on Mac).
*
* We got 2 types of error events:
* - warning: these are not fatal and further events can still be generated
* - error: indicates fatal error and causes that no more events will happen
*/
enum
{
wxFSW_EVENT_CREATE = 0x01,
wxFSW_EVENT_DELETE = 0x02,
wxFSW_EVENT_RENAME = 0x04,
wxFSW_EVENT_MODIFY = 0x08,
wxFSW_EVENT_ACCESS = 0x10,
// error events
wxFSW_EVENT_WARNING = 0x20,
wxFSW_EVENT_ERROR = 0x40,
wxFSW_EVENT_ALL = wxFSW_EVENT_CREATE | wxFSW_EVENT_DELETE |
wxFSW_EVENT_RENAME | wxFSW_EVENT_MODIFY |
wxFSW_EVENT_ACCESS |
wxFSW_EVENT_WARNING | wxFSW_EVENT_ERROR
};
/**
* Event containing information about file system change.
*/
class WXDLLIMPEXP_FWD_BASE wxFileSystemWatcherEvent;
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_FSWATCHER,
wxFileSystemWatcherEvent);
class WXDLLIMPEXP_BASE wxFileSystemWatcherEvent: public wxEvent
{
public:
wxFileSystemWatcherEvent(int changeType, int watchid = wxID_ANY) :
wxEvent(watchid, wxEVT_FSWATCHER),
m_changeType(changeType)
{
}
wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg,
int watchid = wxID_ANY) :
wxEvent(watchid, wxEVT_FSWATCHER),
m_changeType(changeType), m_errorMsg(errorMsg)
{
}
wxFileSystemWatcherEvent(int changeType,
const wxFileName& path, const wxFileName& newPath,
int watchid = wxID_ANY) :
wxEvent(watchid, wxEVT_FSWATCHER),
m_changeType(changeType), m_path(path), m_newPath(newPath)
{
}
/**
* Returns the path at which the event occurred.
*/
const wxFileName& GetPath() const
{
return m_path;
}
/**
* Sets the path at which the event occurred
*/
void SetPath(const wxFileName& path)
{
m_path = path;
}
/**
* In case of rename(move?) events, returns the new path related to the
* event. The "new" means newer in the sense of time. In case of other
* events it returns the same path as GetPath().
*/
const wxFileName& GetNewPath() const
{
return m_newPath;
}
/**
* Sets the new path related to the event. See above.
*/
void SetNewPath(const wxFileName& path)
{
m_newPath = path;
}
/**
* Returns the type of file system event that occurred.
*/
int GetChangeType() const
{
return m_changeType;
}
virtual wxEvent* Clone() const
{
wxFileSystemWatcherEvent* evt = new wxFileSystemWatcherEvent(*this);
evt->m_errorMsg = m_errorMsg.Clone();
evt->m_path = wxFileName(m_path.GetFullPath().Clone());
evt->m_newPath = wxFileName(m_newPath.GetFullPath().Clone());
return evt;
}
virtual wxEventCategory GetEventCategory() const
{
// TODO this has to be merged with "similiar" categories and changed
return wxEVT_CATEGORY_UNKNOWN;
}
/**
* Returns if this error is an error event
*/
bool IsError() const
{
return (m_changeType & (wxFSW_EVENT_ERROR | wxFSW_EVENT_WARNING)) != 0;
}
wxString GetErrorDescription() const
{
return m_errorMsg;
}
/**
* Returns a wxString describing an event useful for debugging or testing
*/
wxString ToString() const;
protected:
int m_changeType;
wxFileName m_path;
wxFileName m_newPath;
wxString m_errorMsg;
};
typedef void (wxEvtHandler::*wxFileSystemWatcherEventFunction)
(wxFileSystemWatcherEvent&);
#define wxFileSystemWatcherEventHandler(func) \
wxEVENT_HANDLER_CAST(wxFileSystemWatcherEventFunction, func)
// ----------------------------------------------------------------------------
// wxFileSystemWatcherBase: interface for wxFileSystemWatcher
// ----------------------------------------------------------------------------
/**
* Simple container to store information about one watched file
*/
class wxFSWatchInfo
{
public:
wxFSWatchInfo() :
m_path(wxEmptyString), m_events(-1)
{
}
wxFSWatchInfo(const wxString& path, int events) :
m_path(path), m_events(events)
{
}
const wxString& GetPath() const
{
return m_path;
}
int GetFlags() const
{
return m_events;
}
protected:
wxString m_path;
int m_events;
};
WX_DECLARE_STRING_HASH_MAP(wxFSWatchInfo, wxFSWatchInfoMap);
/**
* Encapsulation of platform-specific file system event mechanism
*/
class wxFSWatcherImpl;
/**
* Main entry point for clients interested in file system events.
* Defines interface that can be used to receive that kind of events.
*/
class WXDLLIMPEXP_BASE wxFileSystemWatcherBase: public wxEvtHandler
{
public:
wxFileSystemWatcherBase();
virtual ~wxFileSystemWatcherBase();
/**
* Adds path to currently watched files. Any events concerning this
* particular path will be sent to handler. Optionally a filter can be
* specified to receive only events of particular type.
*
* Please note that when adding a dir, immediate children will be watched
* as well.
*/
virtual bool Add(const wxFileName& path, int events = wxFSW_EVENT_ALL);
/**
* Like above, but recursively adds every file/dir in the tree rooted in
* path. Additionally a file mask can be specified to include only files
* of particular type.
*/
virtual bool AddTree(const wxFileName& path, int events = wxFSW_EVENT_ALL,
const wxString& filter = wxEmptyString);
/**
* Removes path from the list of watched paths.
*/
virtual bool Remove(const wxFileName& path);
/**
* Same as above, but also removes every file belonging to the tree rooted
* at path.
*/
virtual bool RemoveTree(const wxFileName& path);
/**
* Clears the list of currently watched paths.
*/
virtual bool RemoveAll();
/**
* Returns the number of watched paths
*/
int GetWatchedPathsCount() const;
/**
* Retrevies all watched paths and places them in wxArrayString. Returns
* the number of paths.
*
* TODO think about API here: we need to return more information (like is
* the path watched recursively)
*/
int GetWatchedPaths(wxArrayString* paths) const;
wxEvtHandler* GetOwner() const
{
return m_owner;
}
void SetOwner(wxEvtHandler* handler)
{
if (!handler)
m_owner = this;
else
m_owner = handler;
}
protected:
static wxString GetCanonicalPath(const wxFileName& path)
{
wxFileName path_copy = wxFileName(path);
if ( !path_copy.Normalize() )
{
wxFAIL_MSG(wxString::Format("Unable to normalize path '%s'",
path.GetFullPath()));
return wxEmptyString;
}
return path_copy.GetFullPath();
}
wxFSWatchInfoMap m_watches; // path=>wxFSWatchInfo map
wxFSWatcherImpl* m_service; // file system events service
wxEvtHandler* m_owner; // handler for file system events
friend class wxFSWatcherImpl;
};
// include the platform specific file defining wxFileSystemWatcher
// inheriting from wxFileSystemWatcherBase
#ifdef wxHAS_INOTIFY
#include "wx/unix/fswatcher_inotify.h"
#define wxFileSystemWatcher wxInotifyFileSystemWatcher
#elif defined(wxHAS_KQUEUE)
#include "wx/unix/fswatcher_kqueue.h"
#define wxFileSystemWatcher wxKqueueFileSystemWatcher
#elif defined(__WXMSW__)
#include "wx/msw/fswatcher.h"
#define wxFileSystemWatcher wxMSWFileSystemWatcher
#else
#include "wx/generic/fswatcher.h"
#define wxFileSystemWatcher wxPollingFileSystemWatcher
#endif
#endif // wxUSE_FSWATCHER
#endif /* _WX_FSWATCHER_BASE_H_ */

View File

@@ -0,0 +1,26 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/generic/fswatcher.h
// Purpose: wxPollingFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_GENERIC_H_
#define _WX_FSWATCHER_GENERIC_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
class WXDLLIMPEXP_BASE wxPollingFileSystemWatcher : public wxFileSystemWatcherBase
{
public:
};
#endif // wxUSE_FSWATCHER
#endif /* _WX_FSWATCHER_GENERIC_H_ */

View File

@@ -17,9 +17,17 @@
typedef union _GdkEvent GdkEvent;
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
#if wxUSE_EVENTLOOP_SOURCE
// maps event loop sources to gtk source ids
WX_DECLARE_HASH_MAP(wxUnixEventLoopSource*, int, wxPointerHash, wxPointerEqual,
wxEventLoopSourceIdMap);
#endif
class WXDLLIMPEXP_BASE wxGUIEventLoop : public wxEventLoopBase
{
public:
typedef wxUnixEventLoopSource Source;
wxGUIEventLoop();
virtual int Run();
@@ -33,7 +41,29 @@ public:
void StoreGdkEventForLaterProcessing(GdkEvent* ev)
{ m_arrGdkEvents.Add(ev); }
#if wxUSE_EVENTLOOP_SOURCE
virtual wxUnixEventLoopSource* CreateSource() const
{
return new wxUnixEventLoopSource();
}
virtual wxUnixEventLoopSource* CreateSource(int res,
wxEventLoopSourceHandler* handler,
int flags) const
{
return new wxUnixEventLoopSource(res, handler, flags);
}
#endif
protected:
#if wxUSE_EVENTLOOP_SOURCE
// adding/removing sources
virtual bool DoAddSource(wxAbstractEventLoopSource* source);
virtual bool DoRemoveSource(wxAbstractEventLoopSource* source);
// map of event loop sources gtk ids
wxEventLoopSourceIdMap m_sourceIdMap;
#endif
// the exit code of this event loop
int m_exitcode;

View File

@@ -430,6 +430,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -0,0 +1,32 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/fswatcher.h
// Purpose: wxMSWFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_MSW_H_
#define _WX_FSWATCHER_MSW_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
class WXDLLIMPEXP_BASE wxMSWFileSystemWatcher : public wxFileSystemWatcherBase
{
public:
wxMSWFileSystemWatcher();
wxMSWFileSystemWatcher(const wxFileName& path,
int events = wxFSW_EVENT_ALL);
protected:
bool Init();
};
#endif // wxUSE_FSWATCHER
#endif /* _WX_FSWATCHER_MSW_H_ */

View File

@@ -0,0 +1,252 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/private/fswatcher.h
// Purpose: File system watcher impl classes
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef WX_MSW_PRIVATE_FSWATCHER_H_
#define WX_MSW_PRIVATE_FSWATCHER_H_
#include "wx/filename.h"
#include "wx/vector.h"
#include "wx/msw/private.h"
// ============================================================================
// wxFSWatcherEntry implementation & helper declarations
// ============================================================================
class wxFSWatcherImplMSW;
class wxFSWatchEntryMSW : public wxFSWatchInfo
{
public:
enum
{
BUFFER_SIZE = 4096 // TODO parametrize
};
wxFSWatchEntryMSW(const wxFSWatchInfo& winfo) :
wxFSWatchInfo(winfo)
{
// get handle for this path
m_handle = OpenDir(m_path);
m_overlapped = (OVERLAPPED*)calloc(1, sizeof(OVERLAPPED));
wxZeroMemory(m_buffer);
}
virtual ~wxFSWatchEntryMSW()
{
wxLogTrace(wxTRACE_FSWATCHER, "Deleting entry '%s'", m_path);
if (m_handle != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(m_handle))
{
wxLogSysError(_("Unable to close the handle for '%s'"),
m_path);
}
}
delete m_overlapped;
}
bool IsOk() const
{
return m_handle != INVALID_HANDLE_VALUE;
}
HANDLE GetHandle() const
{
return m_handle;
}
void* GetBuffer()
{
return m_buffer;
}
OVERLAPPED* GetOverlapped() const
{
return m_overlapped;
}
private:
// opens dir with all flags, attributes etc. necessary to be later
// asynchronous watched with ReadDirectoryChangesW
static HANDLE OpenDir(const wxString& path)
{
HANDLE handle = CreateFile(path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED,
NULL);
if (handle == INVALID_HANDLE_VALUE)
{
wxLogSysError(_("Failed to open directory \"%s\" for monitoring."),
path);
}
return handle;
}
HANDLE m_handle; // handle to opened directory
char m_buffer[BUFFER_SIZE]; // buffer for fs events
OVERLAPPED* m_overlapped;
wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryMSW);
};
// ============================================================================
// wxFSWatcherImplMSW helper classes implementations
// ============================================================================
class wxIOCPService
{
public:
wxIOCPService() :
m_iocp(INVALID_HANDLE_VALUE)
{
Init();
}
~wxIOCPService()
{
if (m_iocp != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(m_iocp))
{
wxLogSysError(_("Unable to close I/O completion port handle"));
}
}
m_watches.clear();
}
// associates a wxFSWatchEntryMSW with completion port
bool Add(wxSharedPtr<wxFSWatchEntryMSW> watch)
{
wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
wxCHECK_MSG( watch->IsOk(), false, "Invalid watch" );
// associate with IOCP
HANDLE ret = CreateIoCompletionPort(watch->GetHandle(), m_iocp,
(ULONG_PTR)watch.get(), 0);
if (ret == NULL)
{
wxLogSysError(_("Unable to associate handle with "
"I/O completion port"));
return false;
}
else if (ret != m_iocp)
{
wxFAIL_MSG(_("Unexpectedly new I/O completion port was created"));
return false;
}
// add to watch map
wxFSWatchEntries::value_type val(watch->GetPath(), watch);
return m_watches.insert(val).second;
}
// post completion packet
bool PostEmptyStatus()
{
wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
int ret = PostQueuedCompletionStatus(m_iocp, 0, NULL, NULL);
if (!ret)
{
wxLogSysError(_("Unable to post completion status"));
}
return ret != 0;
}
// Wait for completion status to arrive.
// This function can block forever in it's wait for completion status.
// Use PostEmptyStatus() to wake it up (and end the worker thread)
bool GetStatus(unsigned long* count, wxFSWatchEntryMSW** watch,
OVERLAPPED** overlapped)
{
wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
wxCHECK_MSG( count != NULL, false, "Null out parameter 'count'");
wxCHECK_MSG( watch != NULL, false, "Null out parameter 'watch'");
wxCHECK_MSG( overlapped != NULL, false,
"Null out parameter 'overlapped'");
int ret = GetQueuedCompletionStatus(m_iocp, count, (PULONG_PTR)watch,
overlapped, INFINITE);
if (!ret)
{
wxLogSysError(_("Unable to dequeue completion packet"));
}
return ret != 0;
}
protected:
bool Init()
{
m_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (m_iocp == NULL)
{
wxLogSysError(_("Unable to create I/O completion port"));
}
return m_iocp != NULL;
}
HANDLE m_iocp;
wxFSWatchEntries m_watches;
};
class wxIOCPThread : public wxThread
{
public:
wxIOCPThread(wxFSWatcherImplMSW* service, wxIOCPService* iocp);
// finishes this thread
bool Finish();
protected:
// structure to hold information needed to process one native event
// this is just a dummy holder, so it doesn't take ownership of it's data
struct wxEventProcessingData
{
wxEventProcessingData(const FILE_NOTIFY_INFORMATION* ne,
const wxFSWatchEntryMSW* watch) :
nativeEvent(ne), watch(watch)
{}
const FILE_NOTIFY_INFORMATION* nativeEvent;
const wxFSWatchEntryMSW* watch;
};
virtual ExitCode Entry();
// wait for events to occur, read them and send to interested parties
// returns false it empty status was read, which means we whould exit
// true otherwise
bool ReadEvents();
void ProcessNativeEvents(wxVector<wxEventProcessingData>& events);
void SendEvent(wxFileSystemWatcherEvent& evt);
static int Native2WatcherFlags(int flags);
static wxString FileNotifyInformationToString(
const FILE_NOTIFY_INFORMATION& e);
static wxFileName GetEventPath(const wxFSWatchEntryMSW& watch,
const FILE_NOTIFY_INFORMATION& e);
wxFSWatcherImplMSW* m_service;
wxIOCPService* m_iocp;
};
#endif /* WX_MSW_PRIVATE_FSWATCHER_H_ */

View File

@@ -430,6 +430,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -430,6 +430,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -430,6 +430,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -11,9 +11,11 @@
#ifndef _WX_OSX_COCOA_EVTLOOP_H_
#define _WX_OSX_COCOA_EVTLOOP_H_
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopManual
class WXDLLIMPEXP_BASE wxGUIEventLoop : public wxEventLoopManual
{
public:
typedef wxMacEventLoopSource Source;
wxGUIEventLoop();
// implement/override base class pure virtual
@@ -24,6 +26,31 @@ public:
virtual void WakeUp();
virtual bool YieldFor(long eventsToProcess);
#if wxUSE_EVENTLOOP_SOURCE
virtual wxMacEventLoopSource* CreateSource() const
{
return new wxMacEventLoopSource();
}
virtual wxMacEventLoopSource* CreateSource(int res,
wxEventLoopSourceHandler* handler,
int flags) const;
virtual wxMacEventLoopSource* CreateSource(CFRunLoopSourceRef res,
wxEventLoopSourceHandler* handler,
int flags) const
{
return new wxMacEventLoopSource(res, handler, flags);
}
#endif
protected:
#if wxUSE_EVENTLOOP_SOURCE
// adding/removing sources
virtual bool DoAddSource(wxAbstractEventLoopSource* source);
virtual bool DoRemoveSource(wxAbstractEventLoopSource* source);
#endif
private:
double m_sleepTime;
};

View File

@@ -431,6 +431,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -430,6 +430,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -0,0 +1,92 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/private/fswatcher.h
// Purpose: File system watcher impl classes
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef WX_PRIVATE_FSWATCHER_H_
#define WX_PRIVATE_FSWATCHER_H_
#include "wx/sharedptr.h"
#ifdef wxHAS_INOTIFY
class wxFSWatchEntryUnix;
#define wxFSWatchEntry wxFSWatchEntryUnix
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxFSWatchEntry>,wxFSWatchEntries);
#include "wx/unix/private/fswatcher_inotify.h"
#elif defined(wxHAS_KQUEUE)
class wxFSWatchEntryKq;
#define wxFSWatchEntry wxFSWatchEntryKq
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxFSWatchEntry>,wxFSWatchEntries);
#include "wx/unix/private/fswatcher_kqueue.h"
#elif defined(__WXMSW__)
class wxFSWatchEntryMSW;
#define wxFSWatchEntry wxFSWatchEntryMSW
WX_DECLARE_STRING_HASH_MAP(wxSharedPtr<wxFSWatchEntry>,wxFSWatchEntries);
#include "wx/msw/private/fswatcher.h"
#else
#define wxFSWatchEntry wxFSWatchEntryPolling
#endif
class wxFSWatcherImpl
{
public:
wxFSWatcherImpl(wxFileSystemWatcherBase* watcher) :
m_watcher(watcher)
{
}
virtual ~wxFSWatcherImpl()
{
(void) RemoveAll();
}
virtual bool Init() = 0;
virtual bool Add(const wxFSWatchInfo& winfo)
{
wxCHECK_MSG( m_watches.find(winfo.GetPath()) == m_watches.end(), false,
"Path '%s' is already watched");
// conctruct watch entry
wxSharedPtr<wxFSWatchEntry> watch(new wxFSWatchEntry(winfo));
if (!DoAdd(watch))
return false;
// add watch to our map (always succeedes, checked above)
wxFSWatchEntries::value_type val(watch->GetPath(), watch);
return m_watches.insert(val).second;
}
virtual bool Remove(const wxFSWatchInfo& winfo)
{
wxFSWatchEntries::iterator it = m_watches.find(winfo.GetPath());
wxCHECK_MSG( it != m_watches.end(), false, "Path '%s' is not watched");
wxSharedPtr<wxFSWatchEntry> watch = it->second;
m_watches.erase(it);
return DoRemove(watch);
}
virtual bool RemoveAll()
{
m_watches.clear();
return true;
}
protected:
virtual bool DoAdd(wxSharedPtr<wxFSWatchEntry> watch) = 0;
virtual bool DoRemove(wxSharedPtr<wxFSWatchEntry> watch) = 0;
wxFSWatchEntries m_watches;
wxFileSystemWatcherBase* m_watcher;
};
#endif /* WX_PRIVATE_FSWATCHER_H_ */

View File

@@ -426,6 +426,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -429,6 +429,13 @@
// Recommended setting: 1 (needed by wxSocket)
#define wxUSE_STOPWATCH 1
// Set wxUSE_FSWATCHER to 1 if you want to enable wxFileSystemWatcher
//
// Default is 1
//
// Recommended setting: 1
#define wxUSE_FSWATCHER 1
// Setting wxUSE_CONFIG to 1 enables the use of wxConfig and related classes
// which allow the application to store its settings in the persistent
// storage. Setting this to 1 will also enable on-demand creation of the

View File

@@ -1,4 +1,4 @@
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Name: wx/unix/evtloop.h
// Purpose: declares wxEventLoop class
// Author: Lukasz Michalski (lm@zork.pl)
@@ -27,6 +27,8 @@ namespace wxPrivate
class WXDLLIMPEXP_BASE wxConsoleEventLoop : public wxEventLoopManual
{
public:
typedef wxUnixEventLoopSource Source;
// initialize the event loop, use IsOk() to check if we were successful
wxConsoleEventLoop();
virtual ~wxConsoleEventLoop();
@@ -39,7 +41,27 @@ public:
virtual bool IsOk() const { return m_dispatcher != NULL; }
virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
#if wxUSE_EVENTLOOP_SOURCE
virtual wxUnixEventLoopSource* CreateSource() const
{
return new wxUnixEventLoopSource();
}
virtual wxUnixEventLoopSource* CreateSource(int res,
wxEventLoopSourceHandler* handler,
int flags) const
{
return new wxUnixEventLoopSource(res, handler, flags);
}
#endif
protected:
#if wxUSE_EVENTLOOP_SOURCE
// adding/removing sources
virtual bool DoAddSource(wxAbstractEventLoopSource* source);
virtual bool DoRemoveSource(wxAbstractEventLoopSource* source);
#endif
virtual void OnNextIteration();
private:

View File

@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/unix/fswatcher_inotify.h
// Purpose: wxInotifyFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_UNIX_H_
#define _WX_FSWATCHER_UNIX_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
class WXDLLIMPEXP_BASE wxInotifyFileSystemWatcher :
public wxFileSystemWatcherBase
{
public:
wxInotifyFileSystemWatcher();
wxInotifyFileSystemWatcher(const wxFileName& path,
int events = wxFSW_EVENT_ALL);
virtual ~wxInotifyFileSystemWatcher();
protected:
bool Init();
};
#endif
#endif /* _WX_FSWATCHER_UNIX_H_ */

View File

@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/unix/fswatcher_kqueue.h
// Purpose: wxKqueueFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_KQUEUE_H_
#define _WX_FSWATCHER_KQUEUE_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
class WXDLLIMPEXP_BASE wxKqueueFileSystemWatcher :
public wxFileSystemWatcherBase
{
public:
wxKqueueFileSystemWatcher();
wxKqueueFileSystemWatcher(const wxFileName& path,
int events = wxFSW_EVENT_ALL);
virtual ~wxKqueueFileSystemWatcher();
protected:
bool Init();
};
#endif
#endif /* _WX_FSWATCHER_OSX_H_ */

View File

@@ -0,0 +1,71 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/unix/private/fswatcher_inotify.h
// Purpose: File system watcher impl classes
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_
#define WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_
#include "wx/filename.h"
// ============================================================================
// wxFSWatcherEntry implementation & helper declarations
// ============================================================================
class wxFSWatcherImplUNIX;
class wxFSWatchEntry : public wxFSWatchInfo
{
public:
wxFSWatchEntry(const wxFSWatchInfo& winfo) :
wxFSWatchInfo(winfo)
{
}
int GetWatchDescriptor() const
{
return m_wd;
}
void SetWatchDescriptor(int wd)
{
m_wd = wd;
}
private:
int m_wd;
wxDECLARE_NO_COPY_CLASS(wxFSWatchEntry);
};
// ============================================================================
// wxFSWSourceHandler helper class
// ============================================================================
class wxFSWatcherImplUnix;
/**
* Handler for handling i/o from inotify descriptor
*/
class wxFSWSourceHandler : public wxEventLoopSourceHandler
{
public:
wxFSWSourceHandler(wxFSWatcherImplUnix* service) :
m_service(service)
{ }
virtual void OnReadWaiting();
virtual void OnWriteWaiting();
virtual void OnExceptionWaiting();
protected:
wxFSWatcherImplUnix* m_service;
};
#endif /* WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_ */

View File

@@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/unix/private/fswatcher_kqueue.h
// Purpose: File system watcher impl classes
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_
#define WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_
#include <fcntl.h>
#include <unistd.h>
#include "wx/dir.h"
#include "wx/debug.h"
#include "wx/arrstr.h"
// ============================================================================
// wxFSWatcherEntry implementation & helper declarations
// ============================================================================
class wxFSWatcherImplKqueue;
class wxFSWatchEntryKq : public wxFSWatchInfo
{
public:
struct wxDirState
{
wxDirState(const wxFSWatchInfo& winfo)
{
if (!wxDir::Exists(winfo.GetPath()))
return;
wxDir dir(winfo.GetPath());
wxCHECK_RET( dir.IsOpened(),
wxString::Format("Unable to open dir '%s'", winfo.GetPath()));
wxString filename;
bool ret = dir.GetFirst(&filename);
while (ret)
{
files.push_back(filename);
ret = dir.GetNext(&filename);
}
}
wxSortedArrayString files;
};
wxFSWatchEntryKq(const wxFSWatchInfo& winfo) :
wxFSWatchInfo(winfo), m_lastState(winfo)
{
m_fd = wxOpen(m_path, O_RDONLY, 0);
if (m_fd == -1)
{
wxLogSysError(_("Unable to open path '%s'"), m_path);
}
}
virtual ~wxFSWatchEntryKq()
{
(void) Close();
}
bool Close()
{
if (!IsOk())
return false;
int ret = close(m_fd);
if (ret == -1)
{
wxLogSysError(_("Unable to close path '%s'"), m_path);
}
m_fd = -1;
return ret != -1;
}
bool IsOk() const
{
return m_fd != -1;
}
int GetFileDescriptor() const
{
return m_fd;
}
void RefreshState()
{
m_lastState = wxDirState(*this);
}
const wxDirState& GetLastState() const
{
return m_lastState;
}
private:
int m_fd;
wxDirState m_lastState;
wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryKq);
};
// ============================================================================
// 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;
};
#endif /* WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_ */