Use FSEvents in wxFileSystemWatcher on OS X

The FSEvents API allows for creating watches in entire trees of
directories in an efficient manner.

Closes #16969.
This commit is contained in:
Roberto Perpuly 2015-06-06 01:28:30 +04:00 committed by Dimitri Schoolwerth
parent f0e098fa06
commit aa5dbad410
14 changed files with 700 additions and 36 deletions

View File

@ -2253,7 +2253,8 @@ COND_TOOLKIT_OSX_CARBON_BASE_OSX_SRC = \
src/unix/threadpsx.cpp \
src/unix/utilsunx.cpp \
src/unix/wakeuppipe.cpp \
src/unix/fswatcher_kqueue.cpp
src/unix/fswatcher_kqueue.cpp \
src/osx/fswatcher_fsevents.cpp
@COND_TOOLKIT_OSX_CARBON@BASE_OSX_SRC = $(COND_TOOLKIT_OSX_CARBON_BASE_OSX_SRC)
COND_TOOLKIT_OSX_COCOA_BASE_OSX_SRC = \
src/osx/core/mimetype.cpp \
@ -2277,7 +2278,8 @@ COND_TOOLKIT_OSX_COCOA_BASE_OSX_SRC = \
src/unix/threadpsx.cpp \
src/unix/utilsunx.cpp \
src/unix/wakeuppipe.cpp \
src/unix/fswatcher_kqueue.cpp
src/unix/fswatcher_kqueue.cpp \
src/osx/fswatcher_fsevents.cpp
@COND_TOOLKIT_OSX_COCOA@BASE_OSX_SRC = $(COND_TOOLKIT_OSX_COCOA_BASE_OSX_SRC)
COND_TOOLKIT_OSX_IPHONE_BASE_OSX_SRC = \
src/osx/core/mimetype.cpp \
@ -2301,7 +2303,8 @@ COND_TOOLKIT_OSX_IPHONE_BASE_OSX_SRC = \
src/unix/threadpsx.cpp \
src/unix/utilsunx.cpp \
src/unix/wakeuppipe.cpp \
src/unix/fswatcher_kqueue.cpp
src/unix/fswatcher_kqueue.cpp \
src/osx/fswatcher_fsevents.cpp
@COND_TOOLKIT_OSX_IPHONE@BASE_OSX_SRC = $(COND_TOOLKIT_OSX_IPHONE_BASE_OSX_SRC)
COND_TOOLKIT_COCOA_BASE_OSX_SRC = \
src/common/fdiodispatcher.cpp \
@ -2442,7 +2445,8 @@ COND_TOOLKIT_OSX_CARBON_BASE_OSX_HDR = \
wx/unix/stdpaths.h \
wx/unix/stackwalk.h \
wx/unix/tls.h \
wx/unix/fswatcher_kqueue.h
wx/unix/fswatcher_kqueue.h \
wx/osx/fswatcher_fsevents.h
@COND_TOOLKIT_OSX_CARBON@BASE_OSX_HDR = $(COND_TOOLKIT_OSX_CARBON_BASE_OSX_HDR)
COND_TOOLKIT_OSX_COCOA_BASE_OSX_HDR = \
wx/osx/core/cfdataref.h \
@ -2463,7 +2467,8 @@ COND_TOOLKIT_OSX_COCOA_BASE_OSX_HDR = \
wx/unix/stdpaths.h \
wx/unix/stackwalk.h \
wx/unix/tls.h \
wx/unix/fswatcher_kqueue.h
wx/unix/fswatcher_kqueue.h \
wx/osx/fswatcher_fsevents.h
@COND_TOOLKIT_OSX_COCOA@BASE_OSX_HDR = $(COND_TOOLKIT_OSX_COCOA_BASE_OSX_HDR)
COND_TOOLKIT_COCOA_BASE_OSX_HDR = \
wx/unix/app.h \
@ -4513,7 +4518,8 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS = \
monodll_threadpsx.o \
monodll_utilsunx.o \
monodll_wakeuppipe.o \
monodll_fswatcher_kqueue.o
monodll_fswatcher_kqueue.o \
monodll_fswatcher_fsevents.o
@COND_PLATFORM_MACOSX_1@__BASE_PLATFORM_SRC_OBJECTS = $(COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS)
@COND_PLATFORM_MSDOS_1@__BASE_PLATFORM_SRC_OBJECTS = \
@COND_PLATFORM_MSDOS_1@ monodll_msdos_dir.o monodll_msdos_mimetype.o \
@ -6888,7 +6894,8 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_1 = \
monolib_threadpsx.o \
monolib_utilsunx.o \
monolib_wakeuppipe.o \
monolib_fswatcher_kqueue.o
monolib_fswatcher_kqueue.o \
monolib_fswatcher_fsevents.o
@COND_PLATFORM_MACOSX_1@__BASE_PLATFORM_SRC_OBJECTS_1 = $(COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_1)
@COND_PLATFORM_MSDOS_1@__BASE_PLATFORM_SRC_OBJECTS_1 \
@COND_PLATFORM_MSDOS_1@ = monolib_msdos_dir.o monolib_msdos_mimetype.o \
@ -9316,7 +9323,8 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_2 = \
basedll_threadpsx.o \
basedll_utilsunx.o \
basedll_wakeuppipe.o \
basedll_fswatcher_kqueue.o
basedll_fswatcher_kqueue.o \
basedll_fswatcher_fsevents.o
@COND_PLATFORM_MACOSX_1@__BASE_PLATFORM_SRC_OBJECTS_2 = $(COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_2)
@COND_PLATFORM_MSDOS_1@__BASE_PLATFORM_SRC_OBJECTS_2 \
@COND_PLATFORM_MSDOS_1@ = basedll_msdos_dir.o basedll_msdos_mimetype.o \
@ -9404,7 +9412,8 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_3 = \
baselib_threadpsx.o \
baselib_utilsunx.o \
baselib_wakeuppipe.o \
baselib_fswatcher_kqueue.o
baselib_fswatcher_kqueue.o \
baselib_fswatcher_fsevents.o
@COND_PLATFORM_MACOSX_1@__BASE_PLATFORM_SRC_OBJECTS_3 = $(COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_3)
@COND_PLATFORM_MSDOS_1@__BASE_PLATFORM_SRC_OBJECTS_3 \
@COND_PLATFORM_MSDOS_1@ = baselib_msdos_dir.o baselib_msdos_mimetype.o \
@ -17740,6 +17749,9 @@ monodll_strconv_cf.o: $(srcdir)/src/osx/core/strconv_cf.cpp $(MONODLL_ODEP)
monodll_utilsexc_base.o: $(srcdir)/src/osx/core/utilsexc_base.cpp $(MONODLL_ODEP)
$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/utilsexc_base.cpp
monodll_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(MONODLL_ODEP)
$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp
monodll_msdos_dir.o: $(srcdir)/src/msdos/dir.cpp $(MONODLL_ODEP)
$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msdos/dir.cpp
@ -23662,6 +23674,9 @@ monolib_strconv_cf.o: $(srcdir)/src/osx/core/strconv_cf.cpp $(MONOLIB_ODEP)
monolib_utilsexc_base.o: $(srcdir)/src/osx/core/utilsexc_base.cpp $(MONOLIB_ODEP)
$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/utilsexc_base.cpp
monolib_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(MONOLIB_ODEP)
$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp
monolib_msdos_dir.o: $(srcdir)/src/msdos/dir.cpp $(MONOLIB_ODEP)
$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msdos/dir.cpp
@ -29584,6 +29599,9 @@ basedll_strconv_cf.o: $(srcdir)/src/osx/core/strconv_cf.cpp $(BASEDLL_ODEP)
basedll_utilsexc_base.o: $(srcdir)/src/osx/core/utilsexc_base.cpp $(BASEDLL_ODEP)
$(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/core/utilsexc_base.cpp
basedll_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(BASEDLL_ODEP)
$(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp
basedll_msdos_dir.o: $(srcdir)/src/msdos/dir.cpp $(BASEDLL_ODEP)
$(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/msdos/dir.cpp
@ -30064,6 +30082,9 @@ baselib_strconv_cf.o: $(srcdir)/src/osx/core/strconv_cf.cpp $(BASELIB_ODEP)
baselib_utilsexc_base.o: $(srcdir)/src/osx/core/utilsexc_base.cpp $(BASELIB_ODEP)
$(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/core/utilsexc_base.cpp
baselib_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(BASELIB_ODEP)
$(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp
baselib_msdos_dir.o: $(srcdir)/src/msdos/dir.cpp $(BASELIB_ODEP)
$(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/msdos/dir.cpp

View File

@ -210,10 +210,12 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
src/osx/core/mimetype.cpp
$(BASE_COREFOUNDATION_SRC)
$(BASE_UNIX_AND_DARWIN_SRC)
src/osx/fswatcher_fsevents.cpp
</set>
<set var="BASE_OSX_SHARED_HDR" hints="files">
$(BASE_COREFOUNDATION_HDR)
$(BASE_UNIX_AND_DARWIN_HDR)
wx/osx/fswatcher_fsevents.h
</set>
<!-- Base and GUI files used by OS X -->
<set var="BASE_AND_GUI_OSX_CARBON_SRC" hints="files">

View File

@ -151,10 +151,12 @@ BASE_COREFOUNDATION_HDR =
# Base files used by OS X ports (not Carbon)
BASE_OSX_SHARED_SRC =
src/osx/core/mimetype.cpp
src/osx/fswatcher_fsevents.cpp
$(BASE_COREFOUNDATION_SRC)
$(BASE_UNIX_AND_DARWIN_SRC)
BASE_OSX_SHARED_HDR =
wx/osx/fswatcher_fsevents.h
$(BASE_COREFOUNDATION_HDR)
$(BASE_UNIX_AND_DARWIN_HDR)

View File

@ -877,6 +877,8 @@
8292D346BFC33D6E8D3CDDC0 /* xh_sttxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3F1680BBE8331A7B745638C /* xh_sttxt.cpp */; };
82FA4AA043213728AC266700 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
82FA4AA043213728AC266701 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
830A61EA04FD367C9EB6A758 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
834F2ADD0520313FBAC4F927 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
834F2ADD0520313FBAC4F928 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
83616D33080E3F0F9FA5FBB4 /* xh_html.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 889FFA9573A835F280A21CB4 /* xh_html.cpp */; };
@ -2023,6 +2025,7 @@
5AACC1EC2E2A33B3ABF5EDCA /* xh_radbt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_radbt.cpp; path = ../../src/xrc/xh_radbt.cpp; sourceTree = "<group>"; };
5AFB85719CBC3D60BA2EDC2E /* CharClassify.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CharClassify.cxx; path = ../../src/stc/scintilla/src/CharClassify.cxx; sourceTree = "<group>"; };
5B32A13D5B3336098B1B9765 /* pngtrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = ../../src/png/pngtrans.c; sourceTree = "<group>"; };
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = fswatcher_fsevents.cpp; path = ../../src/osx/fswatcher_fsevents.cpp; sourceTree = "<group>"; };
5B9586328A1F3C4BA0390AA5 /* time.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = time.cpp; path = ../../src/common/time.cpp; sourceTree = "<group>"; };
5BD6231188AB329CAA5E1171 /* evtloop_cf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = evtloop_cf.cpp; path = ../../src/osx/core/evtloop_cf.cpp; sourceTree = "<group>"; };
5BEC6B3CAFB532CBB9F95D74 /* jutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jutils.c; path = ../../src/jpeg/jutils.c; sourceTree = "<group>"; };
@ -3555,6 +3558,7 @@
DC75C7251C1732B0B07C7BD3 /* utilsunx.cpp */,
B38F3D4DC6D139BA93401F7A /* wakeuppipe.cpp */,
C019CE87CF9931B0B77C0823 /* fswatcher_kqueue.cpp */,
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */,
7A34C5BBBA543DC0A50DE1B6 /* event.cpp */,
C9A305CEC03B3085B159B617 /* fs_mem.cpp */,
E968913A9A593B258BD8EACB /* msgout.cpp */,
@ -3908,6 +3912,7 @@
B5C7FD8C27F43F3289A77FCA /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BAF /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61E /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A758 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD82 /* event.cpp in Sources */,
131B879180AE3FB481F81CC8 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C5 /* msgout.cpp in Sources */,
@ -4776,6 +4781,7 @@
B5C7FD8C27F43F3289A77FC9 /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BAE /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61D /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD81 /* event.cpp in Sources */,
131B879180AE3FB481F81CC7 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C4 /* msgout.cpp in Sources */,

View File

@ -798,6 +798,10 @@
3D762A0BBF1B39B88A769632 /* helpwnd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DBD5DB511C53218B3EF1625 /* helpwnd.cpp */; };
3D762A0BBF1B39B88A769633 /* helpwnd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DBD5DB511C53218B3EF1625 /* helpwnd.cpp */; };
3D762A0BBF1B39B88A769634 /* helpwnd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DBD5DB511C53218B3EF1625 /* helpwnd.cpp */; };
3DE2CD678CEB39C2B1E09ACA /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 60DFD5962DE3379F801AF78F /* power.mm */; };
3DE2CD678CEB39C2B1E09ACB /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 60DFD5962DE3379F801AF78F /* power.mm */; };
3DE2CD678CEB39C2B1E09ACC /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 60DFD5962DE3379F801AF78F /* power.mm */; };
3DE2CD678CEB39C2B1E09ACD /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 60DFD5962DE3379F801AF78F /* power.mm */; };
3E6AA08E72A030D39D867D4B /* ScintillaWX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E6F9D4319F639BE89E5A82F /* ScintillaWX.cpp */; };
3E6AA08E72A030D39D867D4C /* ScintillaWX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E6F9D4319F639BE89E5A82F /* ScintillaWX.cpp */; };
3E6AA08E72A030D39D867D4D /* ScintillaWX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E6F9D4319F639BE89E5A82F /* ScintillaWX.cpp */; };
@ -1483,6 +1487,9 @@
82FA4AA043213728AC266700 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
82FA4AA043213728AC266701 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
82FA4AA043213728AC266702 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
830A61EA04FD367C9EB6A758 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
830A61EA04FD367C9EB6A759 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
834F2ADD0520313FBAC4F927 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
834F2ADD0520313FBAC4F928 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
834F2ADD0520313FBAC4F929 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
@ -1771,10 +1778,6 @@
A1A7B833061C35B4AABD093C /* preferencesg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8F06DEA1AA339ED819B3812 /* preferencesg.cpp */; };
A1A7B833061C35B4AABD093D /* preferencesg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8F06DEA1AA339ED819B3812 /* preferencesg.cpp */; };
A1A7B833061C35B4AABD093E /* preferencesg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8F06DEA1AA339ED819B3812 /* preferencesg.cpp */; };
A1A7C58E276F6F2B247F0813 /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0714536835B5227019E29D06 /* power.mm */; };
A1A7C58E276F6F2B247F0814 /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0714536835B5227019E29D06 /* power.mm */; };
A1A7C58E276F6F2B247F0815 /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0714536835B5227019E29D06 /* power.mm */; };
A1A7C58E276F6F2B247F0816 /* power.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0714536835B5227019E29D06 /* power.mm */; };
A1A7D793B034398B8696EF33 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 789F45D14FF23E248FCFB5FA /* utils.mm */; };
A1A7D793B034398B8696EF34 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 789F45D14FF23E248FCFB5FA /* utils.mm */; };
A1A7D793B034398B8696EF35 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 789F45D14FF23E248FCFB5FA /* utils.mm */; };
@ -4114,6 +4117,7 @@
5AACC1EC2E2A33B3ABF5EDCA /* xh_radbt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_radbt.cpp; path = ../../src/xrc/xh_radbt.cpp; sourceTree = "<group>"; };
5AFB85719CBC3D60BA2EDC2E /* CharClassify.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CharClassify.cxx; path = ../../src/stc/scintilla/src/CharClassify.cxx; sourceTree = "<group>"; };
5B32A13D5B3336098B1B9765 /* pngtrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = ../../src/png/pngtrans.c; sourceTree = "<group>"; };
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = fswatcher_fsevents.cpp; path = ../../src/osx/fswatcher_fsevents.cpp; sourceTree = "<group>"; };
5B9586328A1F3C4BA0390AA5 /* time.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = time.cpp; path = ../../src/common/time.cpp; sourceTree = "<group>"; };
5BD6231188AB329CAA5E1171 /* evtloop_cf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = evtloop_cf.cpp; path = ../../src/osx/core/evtloop_cf.cpp; sourceTree = "<group>"; };
5BEC6B3CAFB532CBB9F95D74 /* jutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jutils.c; path = ../../src/jpeg/jutils.c; sourceTree = "<group>"; };
@ -4145,6 +4149,7 @@
600740717F7E320F8CA78384 /* scrolbar_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scrolbar_osx.cpp; path = ../../src/osx/scrolbar_osx.cpp; sourceTree = "<group>"; };
604D9B79D41F32339AEC0EA0 /* libwx_osx_cocoau_xrc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libwx_osx_cocoau_xrc.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
607EF0043E723B7B9BE101EA /* wxprintf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = wxprintf.cpp; path = ../../src/common/wxprintf.cpp; sourceTree = "<group>"; };
60DFD5962DE3379F801AF78F /* power.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = power.mm; path = ../../src/osx/cocoa/power.mm; sourceTree = "<group>"; };
60EE4448A28D38F5ADE17B5A /* xh_filectrl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_filectrl.cpp; path = ../../src/xrc/xh_filectrl.cpp; sourceTree = "<group>"; };
61548D0FE1353D7C846DD721 /* menuitem.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = menuitem.mm; path = ../../src/osx/cocoa/menuitem.mm; sourceTree = "<group>"; };
61658C3EABB4341AA38C691E /* m_pre.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = m_pre.cpp; path = ../../src/html/m_pre.cpp; sourceTree = "<group>"; };
@ -4218,7 +4223,6 @@
777385D10CCC350C90F02824 /* textentry_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = textentry_osx.cpp; path = ../../src/osx/textentry_osx.cpp; sourceTree = "<group>"; };
77D6E66F72443765A2FBE263 /* aboutdlgg.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = aboutdlgg.cpp; path = ../../src/generic/aboutdlgg.cpp; sourceTree = "<group>"; };
77F5E7BCD9B2307D8DBCC052 /* font.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = font.cpp; path = ../../src/osx/carbon/font.cpp; sourceTree = "<group>"; };
0714536835B5227019E29D06 /* power.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = power.mm; path = ../../src/osx/cocoa/power.mm; sourceTree = "<group>"; };
789F45D14FF23E248FCFB5FA /* utils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = utils.mm; path = ../../src/osx/cocoa/utils.mm; sourceTree = "<group>"; };
78D7866F95C73A28BB540606 /* LexBash.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LexBash.cxx; path = ../../src/stc/scintilla/lexers/LexBash.cxx; sourceTree = "<group>"; };
7906BD74118A3B4DAC515BC2 /* odcombo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = odcombo.cpp; path = ../../src/generic/odcombo.cpp; sourceTree = "<group>"; };
@ -5964,12 +5968,13 @@
DC75C7251C1732B0B07C7BD3 /* utilsunx.cpp */,
B38F3D4DC6D139BA93401F7A /* wakeuppipe.cpp */,
C019CE87CF9931B0B77C0823 /* fswatcher_kqueue.cpp */,
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */,
7A34C5BBBA543DC0A50DE1B6 /* event.cpp */,
C9A305CEC03B3085B159B617 /* fs_mem.cpp */,
E968913A9A593B258BD8EACB /* msgout.cpp */,
4188821BBA833CCAA678B234 /* utilscmn.cpp */,
0714536835B5227019E29D06 /* power.mm */,
789F45D14FF23E248FCFB5FA /* utils.mm */,
60DFD5962DE3379F801AF78F /* power.mm */,
);
name = base;
sourceTree = "<group>";
@ -7365,12 +7370,13 @@
B5C7FD8C27F43F3289A77FCB /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BB0 /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61F /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A759 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD83 /* event.cpp in Sources */,
131B879180AE3FB481F81CC9 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C6 /* msgout.cpp in Sources */,
80665EEAE8613DF8A93A7986 /* utilscmn.cpp in Sources */,
A1A7C58E276F6F2B247F0815 /* power.mm in Sources */,
A1A7D793B034398B8696EF35 /* utils.mm in Sources */,
3DE2CD678CEB39C2B1E09ACC /* power.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -7402,8 +7408,8 @@
131B879180AE3FB481F81CCA /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C7 /* msgout.cpp in Sources */,
80665EEAE8613DF8A93A7987 /* utilscmn.cpp in Sources */,
A1A7C58E276F6F2B247F0816 /* power.mm in Sources */,
A1A7D793B034398B8696EF36 /* utils.mm in Sources */,
3DE2CD678CEB39C2B1E09ACD /* power.mm in Sources */,
F4C0CEADEDC23610BF6983D8 /* artmac.cpp in Sources */,
296692A7A3783E3A83D005C8 /* brush.cpp in Sources */,
86AED49CEAFC3637B1F10539 /* dialog_osx.cpp in Sources */,
@ -8068,12 +8074,13 @@
B5C7FD8C27F43F3289A77FCA /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BAF /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61E /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A758 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD82 /* event.cpp in Sources */,
131B879180AE3FB481F81CC8 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C5 /* msgout.cpp in Sources */,
80665EEAE8613DF8A93A7985 /* utilscmn.cpp in Sources */,
A1A7C58E276F6F2B247F0814 /* power.mm in Sources */,
A1A7D793B034398B8696EF34 /* utils.mm in Sources */,
3DE2CD678CEB39C2B1E09ACB /* power.mm in Sources */,
F4C0CEADEDC23610BF6983D7 /* artmac.cpp in Sources */,
296692A7A3783E3A83D005C7 /* brush.cpp in Sources */,
86AED49CEAFC3637B1F10538 /* dialog_osx.cpp in Sources */,
@ -9258,12 +9265,13 @@
B5C7FD8C27F43F3289A77FC9 /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BAE /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61D /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD81 /* event.cpp in Sources */,
131B879180AE3FB481F81CC7 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C4 /* msgout.cpp in Sources */,
80665EEAE8613DF8A93A7984 /* utilscmn.cpp in Sources */,
A1A7C58E276F6F2B247F0813 /* power.mm in Sources */,
A1A7D793B034398B8696EF33 /* utils.mm in Sources */,
3DE2CD678CEB39C2B1E09ACA /* power.mm in Sources */,
F4C0CEADEDC23610BF6983D6 /* artmac.cpp in Sources */,
296692A7A3783E3A83D005C6 /* brush.cpp in Sources */,
86AED49CEAFC3637B1F10537 /* dialog_osx.cpp in Sources */,

View File

@ -432,6 +432,7 @@
825EAD51920B387DB4F8C426 /* LexAsn1.cxx in Sources */ = {isa = PBXBuildFile; fileRef = A46D50BEBF523B3F88831086 /* LexAsn1.cxx */; };
8292D346BFC33D6E8D3CDDBF /* xh_sttxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3F1680BBE8331A7B745638C /* xh_sttxt.cpp */; };
82FA4AA043213728AC266700 /* wizard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F08F70E1EF239999A4D2AC4 /* wizard.cpp */; };
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */; };
834F2ADD0520313FBAC4F927 /* LexCsound.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 0A59A5C2305D3D1C8049BE71 /* LexCsound.cxx */; };
83616D33080E3F0F9FA5FBB4 /* xh_html.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 889FFA9573A835F280A21CB4 /* xh_html.cpp */; };
83C492B87F4A3A97930F227A /* ExternalLexer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = FD6D2664C05131C3A06E98B4 /* ExternalLexer.cxx */; };
@ -1126,6 +1127,7 @@
5AACC1EC2E2A33B3ABF5EDCA /* xh_radbt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_radbt.cpp; path = ../../src/xrc/xh_radbt.cpp; sourceTree = "<group>"; };
5AFB85719CBC3D60BA2EDC2E /* CharClassify.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CharClassify.cxx; path = ../../src/stc/scintilla/src/CharClassify.cxx; sourceTree = "<group>"; };
5B32A13D5B3336098B1B9765 /* pngtrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = ../../src/png/pngtrans.c; sourceTree = "<group>"; };
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = fswatcher_fsevents.cpp; path = ../../src/osx/fswatcher_fsevents.cpp; sourceTree = "<group>"; };
5B9586328A1F3C4BA0390AA5 /* time.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = time.cpp; path = ../../src/common/time.cpp; sourceTree = "<group>"; };
5BD6231188AB329CAA5E1171 /* evtloop_cf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = evtloop_cf.cpp; path = ../../src/osx/core/evtloop_cf.cpp; sourceTree = "<group>"; };
5BEC6B3CAFB532CBB9F95D74 /* jutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jutils.c; path = ../../src/jpeg/jutils.c; sourceTree = "<group>"; };
@ -2619,6 +2621,7 @@
DC75C7251C1732B0B07C7BD3 /* utilsunx.cpp */,
B38F3D4DC6D139BA93401F7A /* wakeuppipe.cpp */,
C019CE87CF9931B0B77C0823 /* fswatcher_kqueue.cpp */,
5B83407D156C3CC3A66F05A4 /* fswatcher_fsevents.cpp */,
7A34C5BBBA543DC0A50DE1B6 /* event.cpp */,
C9A305CEC03B3085B159B617 /* fs_mem.cpp */,
E968913A9A593B258BD8EACB /* msgout.cpp */,
@ -2930,6 +2933,7 @@
B5C7FD8C27F43F3289A77FC9 /* utilsunx.cpp in Sources */,
F9C5EAC42CCF3267B4100BAE /* wakeuppipe.cpp in Sources */,
FF7DB2884F6E3C5DB4BDF61D /* fswatcher_kqueue.cpp in Sources */,
830A61EA04FD367C9EB6A757 /* fswatcher_fsevents.cpp in Sources */,
55D893FDD00633FEA82ABD81 /* event.cpp in Sources */,
131B879180AE3FB481F81CC7 /* fs_mem.cpp in Sources */,
05814571E7A83F5DBFB6E4C4 /* msgout.cpp in Sources */,

View File

@ -161,6 +161,7 @@ wxMSW:
wxOSX/Cocoa:
- Use more efficient FSEvents (10.7+) in wxFileSystemWatcher (Roberto Perpuly).
- Implement wxWindow::Disable() for non-native controls too (Steve Browne).
- Fix wxEVT_CHAR for non-BMP Unicode characters (ARATA Mizuki).
- Add support for wxEVT_COMBOBOX_DROPDOWN and wxEVT_COMBOBOX_CLOSEUP

View File

@ -52,7 +52,7 @@ enum
wxFSW_EVENT_RENAME | wxFSW_EVENT_MODIFY |
wxFSW_EVENT_ACCESS | wxFSW_EVENT_ATTRIB |
wxFSW_EVENT_WARNING | wxFSW_EVENT_ERROR
#ifdef wxHAS_INOTIFY
#if defined(wxHAS_INOTIFY) || defined(wxHAVE_FSEVENTS_FILE_NOTIFICATIONS)
,wxFSW_EVENT_UNMOUNT = 0x2000
#endif
};
@ -395,6 +395,10 @@ protected:
#ifdef wxHAS_INOTIFY
#include "wx/unix/fswatcher_inotify.h"
#define wxFileSystemWatcher wxInotifyFileSystemWatcher
#elif defined(wxHAS_KQUEUE) && defined(wxHAVE_FSEVENTS_FILE_NOTIFICATIONS)
#include "wx/unix/fswatcher_kqueue.h"
#include "wx/osx/fswatcher_fsevents.h"
#define wxFileSystemWatcher wxFsEventsFileSystemWatcher
#elif defined(wxHAS_KQUEUE)
#include "wx/unix/fswatcher_kqueue.h"
#define wxFileSystemWatcher wxKqueueFileSystemWatcher

View File

@ -50,6 +50,16 @@
#define wxOSX_USE_QUICKTIME 0
#define wxOSX_USE_AUDIOTOOLBOX 1
/*
Use the more efficient FSEvents API instead of kqueue
events for file system watcher, but only on OS X >= 10.7 since
that version introduced a flag that allows watching files as
well as sub directories.
*/
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
#define wxHAVE_FSEVENTS_FILE_NOTIFICATIONS 1
#endif
/*
* turning off capabilities that don't work under cocoa yet
*/

View File

@ -0,0 +1,88 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/osx/fswatcher_fsevents.h
// Purpose: File System watcher that uses the FSEvents API
// of OS X to efficiently watch trees
// Author: Roberto Perpuly
// Created: 2015-04-24
// Copyright: (c) 2015 Roberto Perpuly <robertop2004@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_FSWATCHER_FSEVENTS_H_
#define _WX_FSWATCHER_FSEVENTS_H_
#include "wx/defs.h"
#if wxUSE_FSWATCHER
#include <CoreServices/CoreServices.h>
#include "wx/unix/fswatcher_kqueue.h"
WX_DECLARE_STRING_HASH_MAP(FSEventStreamRef, FSEventStreamRefMap);
/*
The FSEvents watcher uses the newer FSEvents service
that is available in OS X, the service allows for
efficient watching of entire directory hierarchies.
Note that adding a single file watch (or directory
watch) still use kqueue events.
We take care to only use this on OS X >= 10.7, as that
version introduced the ability to get file-level notifications.
See the following docs that outline the FSEvents API
https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html
*/
class WXDLLIMPEXP_BASE wxFsEventsFileSystemWatcher :
public wxKqueueFileSystemWatcher
{
public:
wxFsEventsFileSystemWatcher();
wxFsEventsFileSystemWatcher(const wxFileName& path,
int events = wxFSW_EVENT_ALL);
~wxFsEventsFileSystemWatcher();
// reimplement adding a tree so that it does not use
// kqueue at all
bool AddTree(const wxFileName& path, int events = wxFSW_EVENT_ALL,
const wxString& filespec = wxEmptyString) wxOVERRIDE;
// reimplement removing a tree so that we
// cleanup the opened fs streams
bool RemoveTree(const wxFileName& path) wxOVERRIDE;
// reimplement remove all so that we cleanup
// watches from kqeueue and from FSEvents
bool RemoveAll() wxOVERRIDE;
// post an file change event to the owner
void PostChange(const wxFileName& oldFileName,
const wxFileName& newFileName, int event);
// post a warning event to the owner
void PostWarning(wxFSWWarningType warning, const wxString& msg);
// post an error event to the owner
void PostError(const wxString& msg);
// reimplement count to include the FS stream watches
int GetWatchedPathsCount() const;
// reimplement to include paths from FS stream watches
int GetWatchedPaths(wxArrayString* paths) const;
private:
// map of path => FSEventStreamRef
FSEventStreamRefMap m_streams;
};
#endif /* wxUSE_FSWATCHER */
#endif /* _WX_FSWATCHER_FSEVENTS_H_ */

View File

@ -78,10 +78,11 @@ public:
Additionally a file mask can be specified to include only files
matching that particular mask.
This method is implemented efficiently on MSW, but should be used with
care on other platforms for directories with lots of children (e.g. the
root directory) as it calls Add() for each subdirectory, potentially
creating a lot of watches and taking a long time to execute.
This method is implemented efficiently on MSW and OS X >= 10.7, but
should be used with care on other platforms for directories with lots
of children (e.g. the root directory) as it calls Add() for each
subdirectory, potentially creating a lot of watches and taking a long
time to execute.
Note that on platforms that use symbolic links, you will probably want
to have called wxFileName::DontFollowLink on @a path. This is especially
@ -242,8 +243,9 @@ enum wxFSWFlags
Notice that under MSW this event is sometimes -- although not always --
followed by a ::wxFSW_EVENT_MODIFY for the new file.
Under OS X this event is currently not detected and instead separate
::wxFSW_EVENT_CREATE and ::wxFSW_EVENT_DELETE events are.
Under OS X this event is only detected when watching entire trees. When
watching directories, separate ::wxFSW_EVENT_CREATE and
::wxFSW_EVENT_DELETE events are detected instead.
*/
wxFSW_EVENT_RENAME = 0x04,
@ -253,7 +255,7 @@ enum wxFSWFlags
Depending on the program doing the file modification, multiple such
events can be reported for a single logical file update.
Under OS X this event is currently not detected.
Under OS X this event is only detected when watching entire trees.
*/
wxFSW_EVENT_MODIFY = 0x08,
@ -267,7 +269,8 @@ enum wxFSWFlags
/**
The item's metadata was changed, e.g.\ its permissions or timestamps.
This event is currently only detected under Linux.
This event is currently only detected under Linux and OS X.
Under OS X this event is only detected when watching entire trees.
@since 2.9.5
*/
@ -279,7 +282,8 @@ enum wxFSWFlags
wxFSW_EVENT_UNMOUNT cannot be set; unmount events are produced automatically. This flag
is therefore not included in wxFSW_EVENT_ALL.
This event is currently only detected under Linux.
This event is currently only detected under Linux and OS X.
Under OS X this event is only detected when watching entire trees.
@since 2.9.5
*/

View File

@ -0,0 +1,509 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/osx/fswatcher_fsevents.cpp
// Purpose: File System watcher that uses the FSEvents API
// of OS X to efficiently watch trees
// Author: Roberto Perpuly
// Created: 2015-04-24
// Copyright: (c) 2015 Roberto Perpuly <robertop2004@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_FSWATCHER && defined(wxHAVE_FSEVENTS_FILE_NOTIFICATIONS)
#include "wx/fswatcher.h"
#include "wx/osx/core/cfstring.h"
#include <CoreFoundation/CoreFoundation.h>
// A small class that we will give the FSEvents
// framework, which will be forwarded to the function
// that gets called when files change.
class wxFSEventWatcherContext
{
public:
// Watcher pointer will not be owned by this class.
wxFSEventWatcherContext(wxFsEventsFileSystemWatcher* watcher,
int watcherEventFlags,
const wxString& filespec)
: m_watcher(watcher)
, m_watcherEventFlags(watcherEventFlags)
, m_filespec(filespec)
{
}
// Will return true if the given event file and flags
// match the filespec and event flags given to the
// AddTree method.
bool IsDesiredEvent(const wxFileName& eventFileName, int eventFlags)
{
// warning and errors are always sent to the event handler
if ( eventFlags & wxFSW_EVENT_ERROR )
{
return true;
}
if ( eventFlags & wxFSW_EVENT_WARNING )
{
return true;
}
if ( (m_watcherEventFlags & eventFlags) == 0 )
{
// event handler does not want to see this event
return false;
}
return m_filespec.empty() ||
wxMatchWild(m_filespec, eventFileName.GetFullName());
}
wxFsEventsFileSystemWatcher* m_watcher;
// The event flags that the event handler
// desires to be notified of.
int m_watcherEventFlags;
// The filespec that the event handler
// desires to be notified of.
wxString m_filespec;
private:
wxDECLARE_NO_COPY_CLASS(wxFSEventWatcherContext);
};
// Translate kFSEventStreamEventFlag* flags
// to wxFSW_EVENT_* flags.
// warning and msg are out parameters, filled in when
// there is an error in the stream.
static int wxFSEventsToWatcherFlags(FSEventStreamEventFlags flags,
wxFSWWarningType& warning, wxString& msg)
{
msg = "";
warning = wxFSW_WARNING_NONE;
// see https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html
// for event flag meanings
int ret = 0;
int warnings =
kFSEventStreamEventFlagMustScanSubDirs
| kFSEventStreamEventFlagUserDropped
| kFSEventStreamEventFlagKernelDropped
| kFSEventStreamEventFlagMount
;
int errors = kFSEventStreamEventFlagRootChanged;
// The following flags are not handled:
// kFSEventStreamEventFlagHistoryDone (we never ask for old events)
// kFSEventStreamEventFlagEventIdsWrapped ( we don't keep track nor
// expose event IDs)
int created = kFSEventStreamEventFlagItemCreated;
int deleted = kFSEventStreamEventFlagItemRemoved;
int renamed = kFSEventStreamEventFlagItemRenamed;
int modified = kFSEventStreamEventFlagItemModified;
int attrib = kFSEventStreamEventFlagItemChangeOwner
| kFSEventStreamEventFlagItemFinderInfoMod
| kFSEventStreamEventFlagItemInodeMetaMod
| kFSEventStreamEventFlagItemXattrMod;
if ( created & flags )
{
ret |= wxFSW_EVENT_CREATE;
}
if ( deleted & flags )
{
ret |= wxFSW_EVENT_DELETE;
}
if ( renamed & flags )
{
ret |= wxFSW_EVENT_RENAME;
}
if ( modified & flags )
{
ret |= wxFSW_EVENT_MODIFY;
}
if ( attrib & flags )
{
ret |= wxFSW_EVENT_ATTRIB;
}
if ( kFSEventStreamEventFlagUnmount & flags )
{
ret |= wxFSW_EVENT_UNMOUNT;
}
if ( warnings & flags )
{
warning = wxFSW_WARNING_GENERAL;
ret |= wxFSW_EVENT_WARNING;
if (flags & kFSEventStreamEventFlagMustScanSubDirs)
{
msg += "Must re-scan sub directories.";
}
if (flags & kFSEventStreamEventFlagUserDropped)
{
msg += "User dropped events";
warning = wxFSW_WARNING_OVERFLOW;
}
if (flags & kFSEventStreamEventFlagKernelDropped)
{
msg += "Kernel dropped events";
warning = wxFSW_WARNING_OVERFLOW;
}
if (flags & kFSEventStreamEventFlagMount)
{
msg += "A volume was mounted underneath the watched directory.";
}
}
if ( errors & flags )
{
ret |= wxFSW_EVENT_ERROR;
msg = "Path being watched has been renamed";
}
// don't think that FSEvents tells us about wxFSW_EVENT_ACCESS
return ret;
}
// Fills in eventFileName appropriately based on whether the
// event was on a file or a directory.
static void FileNameFromEvent(wxFileName& eventFileName, char* path,
FSEventStreamEventFlags flags)
{
wxString strPath(path);
if ( flags & kFSEventStreamEventFlagItemIsFile )
{
eventFileName.Assign(strPath);
}
if ( flags & kFSEventStreamEventFlagItemIsDir )
{
eventFileName.AssignDir(strPath);
}
}
// This is the function that the FsEvents API
// will call to notify us that a file has been changed.
static void wxFSEventCallback(ConstFSEventStreamRef WXUNUSED(streamRef), void *clientCallBackInfo,
size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId WXUNUSED(eventIds)[])
{
wxFSEventWatcherContext* context =
(wxFSEventWatcherContext*) clientCallBackInfo;
char** paths = (char**) eventPaths;
int lastWxEventFlags = 0;
wxFileName lastEventFileName;
wxString msg;
wxFSWWarningType warning = wxFSW_WARNING_NONE;
wxFileName eventFileName;
for ( size_t i = 0; i < numEvents; i++ )
{
FSEventStreamEventFlags flags = eventFlags[i];
FileNameFromEvent(eventFileName, paths[i], flags);
int wxEventFlags = wxFSEventsToWatcherFlags(flags, warning, msg);
if ( context->IsDesiredEvent(eventFileName, wxEventFlags) )
{
// This is a naive way of looking for file renames
// wx presents a renames with a from and to paths
// but fs events events do not give us this (it only
// provides that a file was renamed, not what the new
// name is).
// We deduce the old and new paths by looking for consecutive
// renames. This is very naive and won't catch simulatenous
// renames inside the latency period, nor renames from/to
// a directory that is not inside the watched paths.
if (wxEventFlags == wxFSW_EVENT_RENAME && lastWxEventFlags == wxFSW_EVENT_RENAME)
{
context->m_watcher->PostChange(lastEventFileName, eventFileName, wxEventFlags);
}
else if (flags == kFSEventStreamEventFlagRootChanged)
{
// send two events: the delete event and the error event
context->m_watcher->PostChange(eventFileName, eventFileName, wxFSW_EVENT_DELETE);
context->m_watcher->PostError(msg);
}
else if (wxEventFlags != wxFSW_EVENT_RENAME)
{
context->m_watcher->PostChange(eventFileName, eventFileName, wxEventFlags);
}
else
{
// This is a "rename" event that we only saw once, meaning that
// a file was renamed to somewhere inside the watched tree
// OR a file was renamed to somewhere outside the watched tree.
if (!eventFileName.IsDir())
{
int fileEventType = eventFileName.FileExists() ? wxFSW_EVENT_CREATE : wxFSW_EVENT_DELETE;
context->m_watcher->PostChange(eventFileName, eventFileName, fileEventType);
}
if (eventFileName.IsDir())
{
int dirEventType = eventFileName.DirExists() ? wxFSW_EVENT_CREATE : wxFSW_EVENT_DELETE;
context->m_watcher->PostChange(eventFileName, eventFileName, dirEventType);
}
}
if (wxEventFlags & wxFSW_EVENT_WARNING)
{
context->m_watcher->PostWarning(warning, msg);
}
// A single rename (without the second rename) may be due
// to the file being renamed into a directory outside of the
// watch path.
lastWxEventFlags = wxEventFlags;
lastEventFileName = eventFileName;
}
}
}
static void wxDeleteContext(const void* context)
{
wxFSEventWatcherContext* watcherContext =
(wxFSEventWatcherContext*) context;
delete watcherContext;
}
wxFsEventsFileSystemWatcher::wxFsEventsFileSystemWatcher()
: wxKqueueFileSystemWatcher()
{
}
wxFsEventsFileSystemWatcher::wxFsEventsFileSystemWatcher(const wxFileName& path,
int events)
: wxKqueueFileSystemWatcher(path, events)
{
}
wxFsEventsFileSystemWatcher::~wxFsEventsFileSystemWatcher()
{
}
bool wxFsEventsFileSystemWatcher::AddTree(const wxFileName& path, int events,
const wxString& filespec)
{
if (!path.DirExists())
{
return false;
}
wxString canonical = GetCanonicalPath(path);
if ( canonical.empty() )
{
return false;
}
CFRunLoopRef cfLoop = CFRunLoopGetCurrent();
wxASSERT_MSG(
cfLoop,
"there must be a current event loop; this file watcher needs it."
);
if ( ! cfLoop )
{
return false;
}
if ( m_streams.find(canonical) != m_streams.end() )
{
// How to take into account filespec
// if client adds a watch for /home/*.cpp
// and then on another call wants to add a
// call to /home/*.h
// Ideally we should not create another watch
// however we would need to keep both filespecs
// around, which we don't do now.
return false;
}
// Will need to pass the desired event flags
// and filespec to our callback via the context
// we make sure to give the context a cleanup
// callback.
FSEventStreamContext ctx;
wxFSEventWatcherContext* watcherContext = new wxFSEventWatcherContext(
this, events, filespec.Clone()
);
ctx.version = 0;
ctx.info = watcherContext;
ctx.retain = NULL;
ctx.release = &wxDeleteContext;
ctx.copyDescription = NULL;
CFTimeInterval latency = 0.2;
wxMacUniCharBuffer pathChars(path.GetPath());
CFStringRef pathRef = CFStringCreateWithCharacters(
kCFAllocatorDefault,
pathChars.GetBuffer(),
pathChars.GetChars()
);
CFArrayRef pathRefs = CFArrayCreate(
kCFAllocatorDefault, (const void**)&pathRef, 1, NULL
);
FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagWatchRoot
| kFSEventStreamCreateFlagFileEvents;
FSEventStreamRef stream = FSEventStreamCreate(
kCFAllocatorDefault,
&wxFSEventCallback,
&ctx,
pathRefs, kFSEventStreamEventIdSinceNow,
latency, flags);
bool started = false;
if ( stream )
{
FSEventStreamScheduleWithRunLoop(stream, cfLoop, kCFRunLoopDefaultMode);
started = FSEventStreamStart(stream);
if ( started )
{
m_streams[canonical] = stream;
}
}
// cleanup the paths, as we own the pointers
CFRelease(pathRef);
CFRelease(pathRefs);
wxASSERT_MSG(stream, "could not create FS stream");
return started;
}
bool wxFsEventsFileSystemWatcher::RemoveTree(const wxFileName& path)
{
wxString canonical = GetCanonicalPath(path);
if ( canonical.empty() )
{
return false;
}
// Remove any kqueue watches created with Add()
// RemoveTree() should remove all watches no matter
// if they are tree watches or single directory watches.
wxArrayString dirsWatched;
wxKqueueFileSystemWatcher::GetWatchedPaths(&dirsWatched);
for ( size_t i = 0; i < dirsWatched.size(); i++ )
{
if (dirsWatched[i].Find(canonical) == 0)
{
wxKqueueFileSystemWatcher::Remove(dirsWatched[i]);
}
}
FSEventStreamRefMap::iterator it = m_streams.find(canonical);
bool removed = false;
if ( it != m_streams.end() )
{
FSEventStreamStop(it->second);
FSEventStreamInvalidate(it->second);
FSEventStreamRelease(it->second);
m_streams.erase(it);
removed = true;
}
return removed;
}
bool wxFsEventsFileSystemWatcher::RemoveAll()
{
// remove all watches created with Add()
bool ret = wxKqueueFileSystemWatcher::RemoveAll();
FSEventStreamRefMap::iterator it = m_streams.begin();
while ( it != m_streams.end() )
{
FSEventStreamStop(it->second);
FSEventStreamInvalidate(it->second);
FSEventStreamRelease(it->second);
it++;
ret |= true;
}
m_streams.clear();
return ret;
}
void wxFsEventsFileSystemWatcher::PostChange(const wxFileName& oldFileName,
const wxFileName& newFileName, int event)
{
wxASSERT_MSG(this->GetOwner(), "owner must exist");
if ( !this->GetOwner() )
{
return;
}
// FSEvents flags are a bit mask, but wx FSW events
// are not, meaning that FSEvent flag might be
// kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemInodeMetaMod
// this means we must send 2 events not 1.
int allEvents[6] = {
wxFSW_EVENT_CREATE,
wxFSW_EVENT_DELETE,
wxFSW_EVENT_RENAME,
wxFSW_EVENT_MODIFY,
wxFSW_EVENT_ACCESS,
wxFSW_EVENT_ATTRIB
};
for ( int i = 0; i < WXSIZEOF(allEvents); i++ )
{
if ( event & allEvents[i] )
{
wxFileSystemWatcherEvent* evt = new wxFileSystemWatcherEvent(
allEvents[i], oldFileName, newFileName
);
wxQueueEvent(this->GetOwner(), evt);
}
}
}
void wxFsEventsFileSystemWatcher::PostWarning(wxFSWWarningType warning,
const wxString& msg)
{
wxFileSystemWatcherEvent* evt = new wxFileSystemWatcherEvent(
wxFSW_EVENT_WARNING, warning, msg
);
wxASSERT_MSG(this->GetOwner(), "owner must exist");
if (this->GetOwner())
{
wxQueueEvent(this->GetOwner(), evt);
}
}
void wxFsEventsFileSystemWatcher::PostError(const wxString& msg)
{
wxFileSystemWatcherEvent* evt = new wxFileSystemWatcherEvent(
wxFSW_EVENT_ERROR, wxFSW_WARNING_NONE, msg
);
wxASSERT_MSG(this->GetOwner(), "owner must exist");
if (this->GetOwner())
{
wxQueueEvent(this->GetOwner(), evt);
}
}
int wxFsEventsFileSystemWatcher::GetWatchedPathsCount() const
{
return m_streams.size() + wxFileSystemWatcherBase::GetWatchedPathsCount();
}
int wxFsEventsFileSystemWatcher::GetWatchedPaths(wxArrayString* paths) const
{
wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
if ( !paths )
{
return 0;
}
wxFileSystemWatcherBase::GetWatchedPaths(paths);
FSEventStreamRefMap::const_iterator it = m_streams.begin();
for ( ; it != m_streams.end(); it++ )
{
paths->push_back(it->first);
}
return paths->size();
}
#endif // wxUSE_FSWATCHER

View File

@ -279,8 +279,8 @@ protected:
{
wxASSERT_MSG(e.udata, "Null user data associated with kevent!");
wxLogTrace(wxTRACE_FSWATCHER, "Event: ident=%d, filter=%d, flags=%u, "
"fflags=%u, data=%d, user_data=%p",
wxLogTrace(wxTRACE_FSWATCHER, "Event: ident=%llu, filter=%d, flags=%u, "
"fflags=%u, data=%lld, user_data=%lp",
e.ident, e.filter, e.flags, e.fflags, e.data, e.udata);
// for ease of use

View File

@ -831,12 +831,12 @@ void FileSystemWatcherTestCase::TestTrees()
CPPUNIT_ASSERT(m_watcher);
size_t treeitems = 1; // the trunk
#ifndef __WINDOWS__
// When there's no file mask, wxMSW sets a single watch
#if !defined(__WINDOWS__) && !defined(wxHAVE_FSEVENTS_FILE_NOTIFICATIONS)
// When there's no file mask, wxMSW and wxOSX set a single watch
// on the trunk which is implemented recursively.
// wxGTK always sets an additional watch for each subdir
treeitems += subdirs + 1; // +1 for 'child'
#endif // __WINDOWS__
#endif // !__WINDOWS__ && !wxHAVE_FSEVENTS_FILE_NOTIFICATIONS
// Store the initial count; there may already be some watches
const int initial = m_watcher->GetWatchedPathsCount();
@ -862,9 +862,9 @@ void FileSystemWatcherTestCase::TestTrees()
// Except that in wxMSW this isn't true: each watch will be a
// single, recursive dir; so fudge the count
size_t fudge = 0;
#ifdef __WINDOWS__
#if defined(__WINDOWS__) || defined(wxHAVE_FSEVENTS_FILE_NOTIFICATIONS)
fudge = 1;
#endif // __WINDOWS__
#endif // __WINDOWS__ || wxHAVE_FSEVENTS_FILE_NOTIFICATIONS
m_watcher->AddTree(dir);
CPPUNIT_ASSERT_EQUAL(plustree + fudge, m_watcher->GetWatchedPathsCount());
m_watcher->RemoveTree(child);
@ -900,7 +900,12 @@ void FileSystemWatcherTestCase::TestTrees()
// When we use a filter, both wxMSW and wxGTK implementations set
// an additional watch for each subdir (+1 for the root dir itself
// and another +1 for "child").
// On OS X, if we use FSEvents then we still only have 1 watch.
#ifdef wxHAVE_FSEVENTS_FILE_NOTIFICATIONS
const size_t treeitems = 1;
#else
const size_t treeitems = subdirs + 2;
#endif
m_watcher->AddTree(dir, wxFSW_EVENT_ALL, "*.txt");
const int plustree = m_watcher->GetWatchedPathsCount();