xref: /haiku/src/kits/print/FolderWatcher.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*****************************************************************************/
2 // FolderWatcher
3 //
4 // Author
5 //   Michael Pfeiffer
6 //
7 // This application and all source files used in its construction, except
8 // where noted, are licensed under the MIT License, and have been written
9 // and are:
10 //
11 // Copyright (c) 2002 Haiku Project
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 /*****************************************************************************/
31 
32 
33 #include "FolderWatcher.h"
34 
35 #include <stdio.h>
36 
37 // BeOS
38 #include <kernel/fs_attr.h>
39 #include <Node.h>
40 #include <NodeInfo.h>
41 #include <NodeMonitor.h>
42 
43 
44 // Implementation of FolderWatcher
45 
46 FolderWatcher::FolderWatcher(BLooper* looper, const BDirectory& folder, bool watchAttrChanges)
47 	: fFolder(folder)
48 	, fListener(NULL)
49 	, fWatchAttrChanges(watchAttrChanges)
50 {
51 		// add this handler to the application for node monitoring
52 	if (looper->Lock()) {
53 		looper->AddHandler(this);
54 		looper->Unlock();
55 	}
56 
57 		// start attribute change watching for existing files
58 	if (watchAttrChanges) {
59 		BEntry entry;
60 		node_ref node;
61 		while (fFolder.GetNextEntry(&entry) == B_OK && entry.GetNodeRef(&node) == B_OK) {
62 			StartAttrWatching(&node);
63 		}
64 	}
65 
66 		// start watching the spooler directory
67 	node_ref ref;
68 	fFolder.GetNodeRef(&ref);
69 	watch_node(&ref, B_WATCH_DIRECTORY, this);
70 }
71 
72 FolderWatcher::~FolderWatcher() {
73 		// stop node watching for spooler directory
74 	node_ref ref;
75 	fFolder.GetNodeRef(&ref);
76 	watch_node(&ref, B_STOP_WATCHING, this);
77 		// stop sending notifications to this handler
78 	stop_watching(this);
79 
80 	if (LockLooper()) {
81 		BLooper* looper = Looper();
82 			// and remove it
83 		looper->RemoveHandler(this);
84 		looper->Unlock();
85 	}
86 }
87 
88 void FolderWatcher::SetListener(FolderListener* listener) {
89 	fListener = listener;
90 }
91 
92 bool FolderWatcher::BuildEntryRef(BMessage* msg, const char* dirName, entry_ref* entry) {
93 	const char* name;
94 	if (msg->FindInt32("device", &entry->device) == B_OK &&
95 		msg->FindInt64(dirName, &entry->directory) == B_OK &&
96 		msg->FindString("name", &name) == B_OK) {
97 		entry->set_name(name);
98 		return true;
99 	}
100 	return false;
101 }
102 
103 bool FolderWatcher::BuildNodeRef(BMessage* msg, node_ref* node) {
104 	return (msg->FindInt32("device", &node->device) == B_OK &&
105 		msg->FindInt64("node", &node->node) == B_OK);
106 }
107 
108 void FolderWatcher::HandleCreatedEntry(BMessage* msg, const char* dirName) {
109 	node_ref node;
110 	entry_ref entry;
111 	if (BuildEntryRef(msg, dirName, &entry) &&
112 		BuildNodeRef(msg, &node)) {
113 		if (fWatchAttrChanges) StartAttrWatching(&node);
114 		fListener->EntryCreated(&node, &entry);
115 	}
116 }
117 
118 void FolderWatcher::HandleRemovedEntry(BMessage* msg) {
119 	node_ref node;
120 	if (BuildNodeRef(msg, &node)) {
121 		if (fWatchAttrChanges) StopAttrWatching(&node);
122 		fListener->EntryRemoved(&node);
123 	}
124 }
125 
126 void FolderWatcher::HandleChangedAttr(BMessage* msg) {
127 	node_ref node;
128 	if (BuildNodeRef(msg, &node)) {
129 		fListener->AttributeChanged(&node);
130 	}
131 }
132 
133 void FolderWatcher::MessageReceived(BMessage* msg) {
134 	int32 opcode;
135 	node_ref folder;
136 	ino_t dir;
137 
138 	if (msg->what == B_NODE_MONITOR) {
139 		if (fListener == NULL || msg->FindInt32("opcode", &opcode) != B_OK) return;
140 
141 		switch (opcode) {
142 			case B_ENTRY_CREATED:
143 				HandleCreatedEntry(msg, "directory");
144 				break;
145 			case B_ENTRY_REMOVED:
146 				HandleRemovedEntry(msg);
147 				break;
148 			case B_ENTRY_MOVED:
149 				fFolder.GetNodeRef(&folder);
150 				if (msg->FindInt64("to directory", &dir) == B_OK && folder.node == dir) {
151 					// entry moved into this folder
152 					HandleCreatedEntry(msg, "to directory");
153 				} else if (msg->FindInt64("from directory", &dir) == B_OK && folder.node == dir) {
154 					// entry removed from this folder
155 					HandleRemovedEntry(msg);
156 				}
157 				break;
158 			case B_ATTR_CHANGED:
159 				HandleChangedAttr(msg);
160 				break;
161 			default: // nothing to do
162 				break;
163 		}
164 	} else {
165 		inherited::MessageReceived(msg);
166 	}
167 }
168 
169 status_t FolderWatcher::StartAttrWatching(node_ref* node) {
170 	return watch_node(node, B_WATCH_ATTR, this);
171 }
172 
173 status_t FolderWatcher::StopAttrWatching(node_ref* node) {
174 	return watch_node(node, B_STOP_WATCHING, this);
175 }
176