1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : FileWatch.h // |
---|
4 | // Purpose : Watch awar pointing to file AND file itself // |
---|
5 | // // |
---|
6 | // Coded by Ralf Westram (coder@reallysoft.de) in October 2017 // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #ifndef FILEWATCH_H |
---|
12 | #define FILEWATCH_H |
---|
13 | |
---|
14 | #ifndef AW_AWAR_HXX |
---|
15 | #include <aw_awar.hxx> |
---|
16 | #endif |
---|
17 | #ifndef AW_ROOT_HXX |
---|
18 | #include <aw_root.hxx> |
---|
19 | #endif |
---|
20 | #ifndef AW_INOTIFY_HXX |
---|
21 | #include <aw_inotify.hxx> |
---|
22 | #endif |
---|
23 | #ifndef ARB_FILE_H |
---|
24 | #include <arb_file.h> |
---|
25 | #endif |
---|
26 | |
---|
27 | /* Binds user-callback to an awar which contains a filename (full-path; e.g. from File_selection) |
---|
28 | * - the user-callback will be called whenever the awar triggers |
---|
29 | * - the awar will automatically change when |
---|
30 | * - it points to a file and the file gets modified (awar gets touched) |
---|
31 | * - the file is deleted (awar changes to "") |
---|
32 | * - the file is re-created (if awar is "" -> awar points to file again) |
---|
33 | */ |
---|
34 | |
---|
35 | class FileWatch : virtual Noncopyable { |
---|
36 | AW_awar *awar_selfile; // contains name of file (or sth invalid like "") |
---|
37 | SmartCharPtr watched_file; // if set -> currently watched file |
---|
38 | FileChangedCallback wf_cb; // used to watch file changes |
---|
39 | FileChangedCallback user_cb; // called if awar or (pointed-to) file changes |
---|
40 | // Warning: be aware that callbacks may be called with empty name (""), |
---|
41 | // depending on where awar is used! |
---|
42 | |
---|
43 | void file_modified_handler(const char *file, ChangeReason reason) const { |
---|
44 | // - corrects "selected file" in response to filesystem changes (de- and re-select) |
---|
45 | // - triggers awar callback if file gets modified |
---|
46 | |
---|
47 | switch (reason) { |
---|
48 | case CR_CREATED: |
---|
49 | case CR_MODIFIED: |
---|
50 | if (awar_selfile->read_char_pntr()[0]) { // awar has content (do not overwrite) |
---|
51 | awar_selfile->touch(); |
---|
52 | } |
---|
53 | else if (GB_is_regularfile(file)) { |
---|
54 | awar_selfile->write_string(file); |
---|
55 | } |
---|
56 | break; |
---|
57 | case CR_DELETED: |
---|
58 | aw_assert(!GB_is_regularfile(file)); |
---|
59 | awar_selfile->write_string(""); |
---|
60 | break; |
---|
61 | } |
---|
62 | |
---|
63 | } |
---|
64 | |
---|
65 | void remove_inotification() { |
---|
66 | if (watched_file.isSet()) { |
---|
67 | AW_remove_inotification(&*watched_file, wf_cb); |
---|
68 | watched_file.setNull(); |
---|
69 | } |
---|
70 | } |
---|
71 | |
---|
72 | void awar_modified_handler() { |
---|
73 | SmartCharPtr file(awar_selfile->read_string()); |
---|
74 | |
---|
75 | bool points_to_file = GB_is_regularfile(&*file); |
---|
76 | bool need_change_watch = |
---|
77 | points_to_file |
---|
78 | ? (watched_file.isNull() || strcmp(&*watched_file, &*file) != 0) |
---|
79 | : watched_file.isSet(); |
---|
80 | |
---|
81 | if (need_change_watch) { |
---|
82 | remove_inotification(); |
---|
83 | if (points_to_file) { |
---|
84 | watched_file = file; |
---|
85 | AW_add_inotification(&*watched_file, wf_cb); |
---|
86 | } |
---|
87 | } |
---|
88 | |
---|
89 | user_cb(&*file, CR_MODIFIED); |
---|
90 | } |
---|
91 | |
---|
92 | // callback-wrappers |
---|
93 | static void file_modified_wrapper(const char *file, ChangeReason reason, FileWatch *watch) { watch->file_modified_handler(file, reason); } |
---|
94 | static void awar_modified_wrapper(AW_root*, FileWatch *watch) { watch->awar_modified_handler(); } |
---|
95 | |
---|
96 | public: |
---|
97 | |
---|
98 | FileWatch(const char *sel_file_awar, const FileChangedCallback& file_changed_cb) : |
---|
99 | awar_selfile(AW_root::SINGLETON->awar(sel_file_awar)), |
---|
100 | wf_cb(makeFileChangedCallback(file_modified_wrapper, this)), |
---|
101 | user_cb(file_changed_cb) |
---|
102 | { |
---|
103 | awar_selfile->add_callback(makeRootCallback(awar_modified_wrapper, this)); |
---|
104 | } |
---|
105 | |
---|
106 | ~FileWatch() { |
---|
107 | awar_selfile->remove_callback(makeRootCallback(awar_modified_wrapper, this)); |
---|
108 | remove_inotification(); |
---|
109 | } |
---|
110 | }; |
---|
111 | |
---|
112 | #else |
---|
113 | #error FileWatch.h included twice |
---|
114 | #endif // FILEWATCH_H |
---|