]> git.saurik.com Git - wxWidgets.git/blame - include/wx/msw/private/fswatcher.h
Refactor wxEventLoopSource-related code.
[wxWidgets.git] / include / wx / msw / private / fswatcher.h
CommitLineData
6b8ef0b3
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: wx/msw/private/fswatcher.h
3// Purpose: File system watcher impl classes
4// Author: Bartosz Bekier
5// Created: 2009-05-26
6// RCS-ID: $Id$
7// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#ifndef WX_MSW_PRIVATE_FSWATCHER_H_
12#define WX_MSW_PRIVATE_FSWATCHER_H_
13
14#include "wx/filename.h"
15#include "wx/vector.h"
16#include "wx/msw/private.h"
17
18// ============================================================================
19// wxFSWatcherEntry implementation & helper declarations
20// ============================================================================
21
22class wxFSWatcherImplMSW;
23
24class wxFSWatchEntryMSW : public wxFSWatchInfo
25{
26public:
27 enum
28 {
29 BUFFER_SIZE = 4096 // TODO parametrize
30 };
31
32 wxFSWatchEntryMSW(const wxFSWatchInfo& winfo) :
33 wxFSWatchInfo(winfo)
34 {
35 // get handle for this path
36 m_handle = OpenDir(m_path);
37 m_overlapped = (OVERLAPPED*)calloc(1, sizeof(OVERLAPPED));
38 wxZeroMemory(m_buffer);
39 }
40
41 virtual ~wxFSWatchEntryMSW()
42 {
43 wxLogTrace(wxTRACE_FSWATCHER, "Deleting entry '%s'", m_path);
44
45 if (m_handle != INVALID_HANDLE_VALUE)
46 {
47 if (!CloseHandle(m_handle))
48 {
49 wxLogSysError(_("Unable to close the handle for '%s'"),
50 m_path);
51 }
52 }
53 delete m_overlapped;
54 }
55
56 bool IsOk() const
57 {
58 return m_handle != INVALID_HANDLE_VALUE;
59 }
60
61 HANDLE GetHandle() const
62 {
63 return m_handle;
64 }
65
66 void* GetBuffer()
67 {
68 return m_buffer;
69 }
70
71 OVERLAPPED* GetOverlapped() const
72 {
73 return m_overlapped;
74 }
75
76private:
77 // opens dir with all flags, attributes etc. necessary to be later
78 // asynchronous watched with ReadDirectoryChangesW
79 static HANDLE OpenDir(const wxString& path)
80 {
81 HANDLE handle = CreateFile(path, FILE_LIST_DIRECTORY,
82 FILE_SHARE_READ | FILE_SHARE_WRITE |
83 FILE_SHARE_DELETE,
84 NULL, OPEN_EXISTING,
85 FILE_FLAG_BACKUP_SEMANTICS |
86 FILE_FLAG_OVERLAPPED,
87 NULL);
88 if (handle == INVALID_HANDLE_VALUE)
89 {
90 wxLogSysError(_("Failed to open directory \"%s\" for monitoring."),
91 path);
92 }
93
94 return handle;
95 }
96
97 HANDLE m_handle; // handle to opened directory
98 char m_buffer[BUFFER_SIZE]; // buffer for fs events
99 OVERLAPPED* m_overlapped;
100
101 wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryMSW);
102};
103
104
105// ============================================================================
106// wxFSWatcherImplMSW helper classes implementations
107// ============================================================================
108
109class wxIOCPService
110{
111public:
112 wxIOCPService() :
113 m_iocp(INVALID_HANDLE_VALUE)
114 {
115 Init();
116 }
117
118 ~wxIOCPService()
119 {
120 if (m_iocp != INVALID_HANDLE_VALUE)
121 {
122 if (!CloseHandle(m_iocp))
123 {
124 wxLogSysError(_("Unable to close I/O completion port handle"));
125 }
126 }
127 m_watches.clear();
128 }
129
130 // associates a wxFSWatchEntryMSW with completion port
131 bool Add(wxSharedPtr<wxFSWatchEntryMSW> watch)
132 {
133 wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
134 wxCHECK_MSG( watch->IsOk(), false, "Invalid watch" );
135
136 // associate with IOCP
137 HANDLE ret = CreateIoCompletionPort(watch->GetHandle(), m_iocp,
138 (ULONG_PTR)watch.get(), 0);
139 if (ret == NULL)
140 {
141 wxLogSysError(_("Unable to associate handle with "
142 "I/O completion port"));
143 return false;
144 }
145 else if (ret != m_iocp)
146 {
147 wxFAIL_MSG(_("Unexpectedly new I/O completion port was created"));
148 return false;
149 }
150
151 // add to watch map
152 wxFSWatchEntries::value_type val(watch->GetPath(), watch);
153 return m_watches.insert(val).second;
154 }
155
156 // post completion packet
157 bool PostEmptyStatus()
158 {
159 wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
160
161 int ret = PostQueuedCompletionStatus(m_iocp, 0, NULL, NULL);
162 if (!ret)
163 {
164 wxLogSysError(_("Unable to post completion status"));
165 }
166
167 return ret != 0;
168 }
169
170 // Wait for completion status to arrive.
171 // This function can block forever in it's wait for completion status.
172 // Use PostEmptyStatus() to wake it up (and end the worker thread)
173 bool GetStatus(unsigned long* count, wxFSWatchEntryMSW** watch,
174 OVERLAPPED** overlapped)
175 {
176 wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
177 wxCHECK_MSG( count != NULL, false, "Null out parameter 'count'");
178 wxCHECK_MSG( watch != NULL, false, "Null out parameter 'watch'");
179 wxCHECK_MSG( overlapped != NULL, false,
180 "Null out parameter 'overlapped'");
181
182 int ret = GetQueuedCompletionStatus(m_iocp, count, (PULONG_PTR)watch,
183 overlapped, INFINITE);
184 if (!ret)
185 {
186 wxLogSysError(_("Unable to dequeue completion packet"));
187 }
188 return ret != 0;
189 }
190
191protected:
192 bool Init()
193 {
194 m_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
195 if (m_iocp == NULL)
196 {
197 wxLogSysError(_("Unable to create I/O completion port"));
198 }
199 return m_iocp != NULL;
200 }
201
202 HANDLE m_iocp;
203 wxFSWatchEntries m_watches;
204};
205
206
207class wxIOCPThread : public wxThread
208{
209public:
210 wxIOCPThread(wxFSWatcherImplMSW* service, wxIOCPService* iocp);
211
212 // finishes this thread
213 bool Finish();
214
215protected:
216 // structure to hold information needed to process one native event
217 // this is just a dummy holder, so it doesn't take ownership of it's data
218 struct wxEventProcessingData
219 {
220 wxEventProcessingData(const FILE_NOTIFY_INFORMATION* ne,
221 const wxFSWatchEntryMSW* watch) :
222 nativeEvent(ne), watch(watch)
223 {}
224
225 const FILE_NOTIFY_INFORMATION* nativeEvent;
226 const wxFSWatchEntryMSW* watch;
227 };
228
229 virtual ExitCode Entry();
230
231 // wait for events to occur, read them and send to interested parties
232 // returns false it empty status was read, which means we whould exit
233 // true otherwise
234 bool ReadEvents();
235
236 void ProcessNativeEvents(wxVector<wxEventProcessingData>& events);
237
238 void SendEvent(wxFileSystemWatcherEvent& evt);
239
240 static int Native2WatcherFlags(int flags);
241
242 static wxString FileNotifyInformationToString(
243 const FILE_NOTIFY_INFORMATION& e);
244
245 static wxFileName GetEventPath(const wxFSWatchEntryMSW& watch,
246 const FILE_NOTIFY_INFORMATION& e);
247
248 wxFSWatcherImplMSW* m_service;
249 wxIOCPService* m_iocp;
250};
251
252#endif /* WX_MSW_PRIVATE_FSWATCHER_H_ */