xref: /haiku/src/kits/tracker/FSClipboard.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software..
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include "FSClipboard.h"
36 #include <Clipboard.h>
37 #include <Alert.h>
38 #include <NodeMonitor.h>
39 #include "Commands.h"
40 #include "FSUtils.h"
41 #include "Tracker.h"
42 
43 // prototypes
44 static void MakeNodeFromName(node_ref *node, char *name);
45 static inline void MakeRefName(char *refName, const node_ref *node);
46 static inline void MakeModeName(char *modeName, const node_ref *node);
47 static inline void MakeModeNameFromRefName(char *modeName, char *refName);
48 static inline bool CompareModeAndRefName(const char *modeName, const char *refName);
49 
50 
51 //these are from PoseView.cpp
52 extern const char *kNoCopyToTrashStr;
53 extern const char *kNoCopyToRootStr;
54 extern const char *kOkToMoveStr;
55 
56 /*
57 static bool
58 FSClipboardCheckIntegrity()
59 {
60 	return true;
61 }
62 */
63 
64 static void
65 MakeNodeFromName(node_ref *node, char *name)
66 {
67 	char *nodeString = strchr(name, '_');
68 	if (nodeString != NULL) {
69 		node->node = strtoll(nodeString + 1, (char **)NULL, 10);
70 		node->device = atoi(name + 1);
71 	}
72 }
73 
74 
75 static inline void
76 MakeRefName(char *refName, const node_ref *node)
77 {
78 	sprintf(refName, "r%ld_%Ld", node->device, node->node);
79 }
80 
81 
82 static inline void
83 MakeModeName(char *modeName, const node_ref *node)
84 {
85 	sprintf(modeName, "m%ld_%Ld", node->device, node->node);
86 }
87 
88 
89 static inline void
90 MakeModeName(char *name)
91 {
92 	name[0] = 'm';
93 }
94 
95 
96 static inline void
97 MakeModeNameFromRefName(char *modeName, char *refName)
98 {
99 	strcpy(modeName, refName);
100 	modeName[0] = 'm';
101 }
102 
103 
104 static inline bool
105 CompareModeAndRefName(const char *modeName, const char *refName)
106 {
107 	return !strcmp(refName + 1, modeName + 1);
108 }
109 
110 
111 //	#pragma mark -
112 
113 
114 bool
115 FSClipboardHasRefs()
116 {
117 	bool result = false;
118 
119 	if (be_clipboard->Lock()) {
120 		BMessage *clip = be_clipboard->Data();
121 		if (clip != NULL) {
122 #ifdef B_BEOS_VERSION_DANO
123 			const
124 #endif
125 			char *refName;
126 #ifdef B_BEOS_VERSION_DANO
127 			const
128 #endif
129 			char *modeName;
130 			uint32 type;
131 			int32 count;
132 			if (clip->GetInfo(B_REF_TYPE, 0, &refName, &type, &count) == B_OK
133 				&& clip->GetInfo(B_INT32_TYPE, 0, &modeName, &type, &count) == B_OK)
134 				result = CompareModeAndRefName(modeName, refName);
135 		}
136 		be_clipboard->Unlock();
137 	}
138 	return result;
139 }
140 
141 
142 void
143 FSClipboardStartWatch(BMessenger target)
144 {
145 	if (dynamic_cast<TTracker *>(be_app) != NULL)
146 		((TTracker *)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
147 	else {
148 		// this code is used by external apps using objects using FSClipboard functions
149 		// i.e: applications using FilePanel
150 		BMessenger messenger(kTrackerSignature);
151 		if (messenger.IsValid()) {
152 			BMessage message(kStartWatchClipboardRefs);
153 			message.AddMessenger("target", target);
154 			messenger.SendMessage(&message);
155 		}
156 	}
157 }
158 
159 
160 void
161 FSClipboardStopWatch(BMessenger target)
162 {
163 	if (dynamic_cast<TTracker *>(be_app) != NULL)
164 		((TTracker *)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
165 	else {
166 		// this code is used by external apps using objects using FSClipboard functions
167 		// i.e: applications using FilePanel
168 		BMessenger messenger(kTrackerSignature);
169 		if (messenger.IsValid()) {
170 			BMessage message(kStopWatchClipboardRefs);
171 			message.AddMessenger("target", target);
172 			messenger.SendMessage(&message);
173 		}
174 	}
175 }
176 
177 
178 void
179 FSClipboardClear()
180 {
181 	if (!be_clipboard->Lock())
182 		return;
183 
184 	be_clipboard->Clear();
185 	be_clipboard->Commit();
186 	be_clipboard->Unlock();
187 }
188 
189 
190 /** This function adds the given poses list to the clipboard, for both copy
191  *	and cut. All poses in the list must have "directory" as parent.
192  *	"moveMode" is either kMoveSelection or kCopySelection.
193  *	It will check if the entries are already present, so that there can only
194  *	be one reference to them in the clipboard.
195  */
196 
197 uint32
198 FSClipboardAddPoses(const node_ref *directory, PoseList *list, uint32 moveMode,
199 	bool clearClipboard)
200 {
201 	uint32 refsAdded = 0;
202 	int32 listCount = list->CountItems();
203 
204 	if (listCount == 0 || !be_clipboard->Lock())
205 		return 0;
206 
207 	// update message to be send to all listeners
208 	BMessage updateMessage(kFSClipboardChanges);
209 	updateMessage.AddInt32("device", directory->device);
210 	updateMessage.AddInt64("directory", directory->node);
211 	updateMessage.AddBool("clearClipboard", clearClipboard);
212 
213 	TClipboardNodeRef clipNode;
214 	clipNode.moveMode = moveMode;
215 
216 	if (clearClipboard)
217 		be_clipboard->Clear();
218 
219 	BMessage *clip = be_clipboard->Data();
220 	if (clip != NULL) {
221 		for (int32 index = 0; index < listCount; index++) {
222 			char refName[64], modeName[64];
223 			BPose *pose = (BPose *)list->ItemAt(index);
224 			Model *model = pose->TargetModel();
225 			const node_ref *node = model->NodeRef();
226 
227 			BEntry entry;
228 			model->GetEntry(&entry);
229 			if (model->IsVolume()
230 				|| model->IsRoot()
231 				|| FSIsTrashDir(&entry)
232 				|| FSIsDeskDir(&entry))
233 				continue;
234 
235 			MakeRefName(refName, node);
236 			MakeModeNameFromRefName(modeName, refName);
237 
238 			if (clearClipboard) {
239 				if (clip->AddInt32(modeName, (int32)moveMode) == B_OK)
240 					if (clip->AddRef(refName, model->EntryRef()) == B_OK) {
241 						pose->SetClipboardMode(moveMode);
242 
243 						clipNode.node = *node;
244 						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
245 							sizeof(TClipboardNodeRef), true, listCount);
246 
247 						refsAdded++;
248 					} else
249 						clip->RemoveName(modeName);
250 			} else {
251 				if (clip->ReplaceInt32(modeName, (int32)moveMode) == B_OK) {
252 					// replace old mode if entry already exists in clipboard
253 					if (clip->ReplaceRef(refName, model->EntryRef()) == B_OK) {
254 						pose->SetClipboardMode(moveMode);
255 
256 						clipNode.node = *node;
257 						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
258 							sizeof(TClipboardNodeRef), true, listCount);
259 
260 						refsAdded++;
261 					} else {
262 						clip->RemoveName(modeName);
263 
264 						clipNode.node = *node;
265 						clipNode.moveMode = kDelete;	// note removing node
266 						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
267 							sizeof(TClipboardNodeRef), true, listCount);
268 						clipNode.moveMode = moveMode; // set it back to current value
269 					}
270 				} else {
271 					// add it if it doesn't exist
272 					if (clip->AddRef(refName, model->EntryRef()) == B_OK
273 						&& clip->AddInt32(modeName, (int32)moveMode) == B_OK) {
274 						pose->SetClipboardMode(moveMode);
275 
276 						clipNode.node = *node;
277 						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
278 							sizeof(TClipboardNodeRef), true, listCount);
279 
280 						refsAdded++;
281 					} else {
282 						clip->RemoveName(modeName);
283 						clip->RemoveName(refName);
284 						// here notifying delete isn't needed as node didn't
285 						// exist in clipboard
286 					}
287 				}
288 			}
289 		}
290 		be_clipboard->Commit();
291 	}
292 	be_clipboard->Unlock();
293 
294 	BMessenger(kTrackerSignature).SendMessage(&updateMessage);
295 		// Tracker will notify all listeners
296 
297 	return refsAdded;
298 }
299 
300 
301 uint32
302 FSClipboardRemovePoses(const node_ref *directory, PoseList *list)
303 {
304 	if (!be_clipboard->Lock())
305 		return 0;
306 
307 	// update message to be send to all listeners
308 	BMessage updateMessage(kFSClipboardChanges);
309 	updateMessage.AddInt32("device", directory->device);
310 	updateMessage.AddInt64("directory", directory->node);
311 	updateMessage.AddBool("clearClipboard", false);
312 
313 	TClipboardNodeRef clipNode;
314 	clipNode.moveMode = kDelete;
315 
316 	uint32 refsRemoved = 0;
317 
318 	BMessage *clip = be_clipboard->Data();
319 	if (clip != NULL) {
320 		int32 listCount = list->CountItems();
321 
322 		for (int32 index = 0; index < listCount; index++) {
323 			char refName[64], modeName[64];
324 			BPose *pose = (BPose *)list->ItemAt(index);
325 
326 			clipNode.node = *pose->TargetModel()->NodeRef();
327 			MakeRefName(refName, &clipNode.node);
328 			MakeModeName(modeName);
329 
330 			if (clip->RemoveName(refName) == B_OK && clip->RemoveName(modeName)) {
331 				updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
332 					sizeof(TClipboardNodeRef), true, listCount);
333 				refsRemoved++;
334 			}
335 		}
336 		be_clipboard->Commit();
337 	}
338 	be_clipboard->Unlock();
339 
340 	BMessenger(kTrackerSignature).SendMessage(&updateMessage);
341 		// Tracker will notify all listeners
342 
343 	return refsRemoved;
344 }
345 
346 
347 /** Pastes entries from the clipboard to the target model's directory.
348  *	Updates moveModes and notifies listeners if necessary.
349  */
350 
351 bool
352 FSClipboardPaste(Model *model, uint32 linksMode)
353 {
354 	if (!FSClipboardHasRefs())
355 		return false;
356 
357 	BMessenger tracker(kTrackerSignature);
358 
359 	node_ref *destNodeRef = (node_ref *)model->NodeRef();
360 
361 	// these will be passed to the asynchronous copy/move process
362 	BObjectList<entry_ref> *moveList = new BObjectList<entry_ref>(0, true);
363 	BObjectList<entry_ref> *copyList = new BObjectList<entry_ref>(0, true);
364 
365 	if ((be_clipboard->Lock())) {
366 		BMessage *clip = be_clipboard->Data();
367 		if (clip != NULL) {
368 			char modeName[64];
369 			uint32 moveMode = 0;
370 
371 			BMessage *updateMessage = NULL;
372 			node_ref updateNodeRef;
373 			updateNodeRef.device = -1;
374 
375 			char *refName;
376 			type_code type;
377 			int32 count;
378 			for (int32 index = 0; clip->GetInfo(B_REF_TYPE, index,
379 #ifdef B_BEOS_VERSION_DANO
380 				(const char **)
381 #endif
382 				&refName, &type, &count) == B_OK; index++) {
383 				entry_ref ref;
384 				if (clip->FindRef(refName, &ref) != B_OK)
385 					continue;
386 
387 				// If the entry_ref's directory has changed, send previous notification
388 				// (if any), and start new one for the new directory
389 				if (updateNodeRef.device != ref.device
390 					|| updateNodeRef.node != ref.directory) {
391 					if (updateMessage != NULL) {
392 						tracker.SendMessage(updateMessage);
393 						delete updateMessage;
394 					}
395 
396 					updateNodeRef.device = ref.device;
397 					updateNodeRef.node = ref.directory;
398 
399 					updateMessage = new BMessage(kFSClipboardChanges);
400 					updateMessage->AddInt32("device", updateNodeRef.device);
401 					updateMessage->AddInt64("directory", updateNodeRef.node);
402 				}
403 
404 				// we need this data later on
405 				MakeModeNameFromRefName(modeName, refName);
406 				if (!linksMode && clip->FindInt32(modeName, (int32 *)&moveMode) != B_OK)
407 					continue;
408 
409 				BEntry entry(&ref);
410 
411 				uint32 newMoveMode = 0;
412 				bool sameDirectory = destNodeRef->device == ref.device && destNodeRef->node == ref.directory;
413 
414 				if (!entry.Exists()) {
415 					// The entry doesn't exist anymore, so we'll remove
416 					// that entry from the clipboard as well
417 					clip->RemoveName(refName);
418 					clip->RemoveName(modeName);
419 
420 					newMoveMode = kDelete;
421 				} else {
422 					// the entry does exist, so lets see what we will
423 					// do with it
424 					if (!sameDirectory) {
425 						if (linksMode || moveMode == kMoveSelectionTo) {
426 							// the linksMode uses the moveList as well
427 							moveList->AddItem(new entry_ref(ref));
428 						} else if (moveMode == kCopySelectionTo)
429 							copyList->AddItem(new entry_ref(ref));
430 					}
431 
432 					// if the entry should have been removed from its directory,
433 					// we want to copy that entry next time, no matter if the
434 					// items don't have to be moved at all (source == target)
435 					if (moveMode == kMoveSelectionTo)
436 						newMoveMode = kCopySelectionTo;
437 				}
438 
439 				// add the change to the update message (if necessary)
440 				if (newMoveMode) {
441 					clip->ReplaceInt32(modeName, kCopySelectionTo);
442 
443 					TClipboardNodeRef clipNode;
444 					MakeNodeFromName(&clipNode.node, modeName);
445 					clipNode.moveMode = kDelete;
446 					updateMessage->AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
447 						sizeof(TClipboardNodeRef), true);
448 				}
449 			}
450 			be_clipboard->Commit();
451 
452 			// send notification for the last directory
453 			if (updateMessage != NULL) {
454 				tracker.SendMessage(updateMessage);
455 				delete updateMessage;
456 			}
457 		}
458 		be_clipboard->Unlock();
459 	}
460 
461 	bool okToMove = true;
462 
463 	// can't copy/paste to root('/') directory
464 	if (model->IsRoot()) {
465 		(new BAlert("", kNoCopyToRootStr, "Cancel", NULL, NULL,
466 			B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
467 		okToMove = false;
468 	}
469 
470 	BEntry entry;
471 	model->GetEntry(&entry);
472 
473 	// can't copy items into the trash
474 	if (copyList->CountItems() > 0 && FSIsTrashDir(&entry)) {
475 		(new BAlert("", kNoCopyToTrashStr, "Cancel", NULL, NULL,
476 			B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
477 		okToMove = false;
478 	}
479 
480 	if (!okToMove) {
481 		// there was some problem with our target, so we bail out here
482 		delete moveList;
483 		delete copyList;
484 		return false;
485 	}
486 
487 	// asynchronous calls take over ownership of the objects passed to it
488 	if (moveList->CountItems() > 0)
489 		FSMoveToFolder(moveList, new BEntry(entry), linksMode ? linksMode : kMoveSelectionTo);
490 	else
491 		delete moveList;
492 
493 	if (copyList->CountItems() > 0)
494 		FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo);
495 	else
496 		delete copyList;
497 
498 	return true;
499 }
500 
501 
502 /**	Seek node in clipboard, if found return it's moveMode
503  *	else return 0
504  */
505 
506 uint32
507 FSClipboardFindNodeMode(Model *model, bool updateRefIfNeeded)
508 {
509 	int32 moveMode = 0;
510 
511 	if (be_clipboard->Lock()) {
512 		bool remove = false;
513 		bool change = false;
514 
515 		BMessage *clip = be_clipboard->Data();
516 		if (clip != NULL) {
517 			const node_ref *node = model->NodeRef();
518 			char modeName[64];
519 			MakeModeName(modeName, node);
520 			if ((clip->FindInt32(modeName, &moveMode) == B_OK)) {
521 				const entry_ref *ref = model->EntryRef();
522 				entry_ref clipref;
523 				char refName[64];
524 				MakeRefName(refName, node);
525 				if ((clip->FindRef(refName, &clipref) == B_OK)) {
526 					if (clipref != *ref) {
527 						if (updateRefIfNeeded) {
528 							clip->ReplaceRef(refName, ref);
529 							change = true;
530 						} else {
531 							clip->RemoveName(refName);
532 							clip->RemoveName(modeName);
533 							change = true;
534 							remove = true;
535 							moveMode = 0;
536 						}
537 					}
538 				} else {
539 					clip->RemoveName(modeName);
540 					change = true;
541 					remove = true;
542 					moveMode = 0;
543 				}
544 			}
545 		}
546 		if (change)
547 			be_clipboard->Commit();
548 
549 		be_clipboard->Unlock();
550 
551 		if (remove)
552 			FSClipboardRemove(model);
553 	}
554 
555 	return (uint32)moveMode;
556 }
557 
558 
559 void
560 FSClipboardRemove(Model *model)
561 {
562 	BMessenger messenger(kTrackerSignature);
563 	if (messenger.IsValid()) {
564 		BMessage *report = new BMessage(kFSClipboardChanges);
565 		TClipboardNodeRef tcnode;
566 		tcnode.node = *model->NodeRef();
567 		tcnode.moveMode = kDelete;
568 		const entry_ref *ref = model->EntryRef();
569 		report->AddInt32("device", ref->device);
570 		report->AddInt64("directory", ref->directory);
571 		report->AddBool("clearClipboard", false);
572 		report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode), true);
573 		messenger.SendMessage(report);
574 		delete report;
575 	}
576 }
577 
578 
579 //	#pragma mark -
580 
581 
582 BClipboardRefsWatcher::BClipboardRefsWatcher()
583 	:	BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096),
584 	fNotifyList(10, false)
585 {
586 	watch_node(NULL, B_WATCH_MOUNT, this);
587 	fRefsInClipboard = FSClipboardHasRefs();
588 	be_clipboard->StartWatching(this);
589 }
590 
591 
592 BClipboardRefsWatcher::~BClipboardRefsWatcher()
593 {
594 	stop_watching(this);
595 	be_clipboard->StopWatching(this);
596 }
597 
598 
599 void
600 BClipboardRefsWatcher::AddToNotifyList(BMessenger target)
601 {
602 	if (Lock()) {
603 		// add the messenger if it's not already in the list
604 		// ToDo: why do we have to care about that?
605 		BMessenger *messenger;
606 		bool found = false;
607 
608 		for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) {
609 			if (*messenger == target) {
610 				found = true;
611 				break;
612 			}
613 		}
614 		if (!found)
615 			fNotifyList.AddItem(new BMessenger(target));
616 
617 		Unlock();
618 	}
619 }
620 
621 
622 void
623 BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target)
624 {
625 	if (Lock()) {
626 		BMessenger *messenger;
627 
628 		for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) {
629 			if (*messenger == target) {
630 				delete fNotifyList.RemoveItemAt(index);
631 				break;
632 			}
633 		}
634 		Unlock();
635 	}
636 }
637 
638 
639 void
640 BClipboardRefsWatcher::AddNode(const node_ref *node)
641 {
642 	TTracker::WatchNode(node, B_WATCH_NAME, this);
643 	fRefsInClipboard = true;
644 }
645 
646 
647 void
648 BClipboardRefsWatcher::RemoveNode(node_ref *node, bool removeFromClipboard)
649 {
650 	watch_node(node, B_STOP_WATCHING, this);
651 
652 	if (!removeFromClipboard)
653 		return;
654 
655 	if (be_clipboard->Lock()) {
656 		BMessage *clip = be_clipboard->Data();
657 		if (clip != NULL) {
658 			char name[64];
659 			MakeRefName(name, node);
660 			clip->RemoveName(name);
661 			MakeModeName(name);
662 			clip->RemoveName(name);
663 
664 			be_clipboard->Commit();
665 		}
666 		be_clipboard->Unlock();
667 	}
668 }
669 
670 
671 void
672 BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device)
673 {
674 	if (!be_clipboard->Lock())
675 		return;
676 
677 	BMessage *clip = be_clipboard->Data();
678 	if (clip != NULL) {
679 		char deviceName[6];
680 		sprintf(deviceName, "r%ld_", device);
681 
682 		int32 index = 0;
683 		char *refName;
684 		type_code type;
685 		int32 count;
686 		while (clip->GetInfo(B_REF_TYPE, index,
687 #ifdef B_BEOS_VERSION_DANO
688 			(const char **)
689 #endif
690 			&refName, &type, &count) == B_OK) {
691 			if (!strncmp(deviceName, refName, strlen(deviceName))) {
692 				clip->RemoveName(refName);
693 				MakeModeName(refName);
694 				clip->RemoveName(refName);
695 
696 				node_ref node;
697 				MakeNodeFromName(&node, refName);
698 				watch_node(&node, B_STOP_WATCHING, this);
699 			}
700 			index++;
701 		}
702 		be_clipboard->Commit();
703 	}
704 	be_clipboard->Unlock();
705 }
706 
707 
708 void
709 BClipboardRefsWatcher::UpdateNode(node_ref *node, entry_ref *ref)
710 {
711 	if (!be_clipboard->Lock())
712 		return;
713 
714 	BMessage *clip = be_clipboard->Data();
715 	if (clip != NULL) {
716 		char name[64];
717 		MakeRefName(name, node);
718 		if ((clip->ReplaceRef(name, ref)) != B_OK) {
719 			clip->RemoveName(name);
720 			MakeModeName(name);
721 			clip->RemoveName(name);
722 
723 			RemoveNode(node);
724 		}
725 		be_clipboard->Commit();
726 	}
727 	be_clipboard->Unlock();
728 }
729 
730 
731 void
732 BClipboardRefsWatcher::Clear()
733 {
734 	stop_watching(this);
735 	watch_node(NULL, B_WATCH_MOUNT, this);
736 
737 	BMessage message(kFSClipboardChanges);
738 	message.AddBool("clearClipboard", true);
739 	if (Lock()) {
740 		int32 items = fNotifyList.CountItems();
741 		for (int32 i = 0;i < items;i++) {
742 			fNotifyList.ItemAt(i)->SendMessage(&message);
743 		}
744 		Unlock();
745 	}
746 }
747 
748 /*
749 void
750 BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard, const node_ref *node)
751 {
752 	BMessage message(kFSClipboardChanges);
753 	message.AddInt32("device", node->device);
754 	message.AddInt64("directory", node->node);
755 	message.AddBool("clearClipboard", clearClipboard);
756 
757 	if (Lock()) {
758 		int32 items = fNotifyList.CountItems();
759 		for (int32 i = 0;i < items;i++) {
760 			fNotifyList.ItemAt(i)->SendMessage(&message);
761 		}
762 		Unlock();
763 	}
764 }
765 */
766 
767 void
768 BClipboardRefsWatcher::UpdatePoseViews(BMessage *reportMessage)
769 {
770 	if (Lock()) {
771 		// check if it was cleared, if so clear watching
772 		bool clearClipboard = false;
773 		if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK
774 			&& clearClipboard) {
775 			stop_watching(this);
776 			watch_node(NULL, B_WATCH_MOUNT, this);
777 		}
778 
779 		// loop through reported node_ref's movemodes:
780 		// move or copy: start watching node_ref
781 		// remove: stop watching node_ref
782 		int32 index = 0;
783 		TClipboardNodeRef *tcnode = NULL;
784 		ssize_t size;
785 		while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index, (const void**)&tcnode, &size) == B_OK) {
786 			if (tcnode->moveMode == kDelete) {
787 				watch_node(&tcnode->node, B_STOP_WATCHING, this);
788 			} else {
789 				watch_node(&tcnode->node, B_STOP_WATCHING, this);
790 				TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this);
791 				fRefsInClipboard = true;
792 			}
793 			index++;
794 		}
795 
796 		// send report
797 		int32 items = fNotifyList.CountItems();
798 		for (int32 i = 0;i < items;i++) {
799 			fNotifyList.ItemAt(i)->SendMessage(reportMessage);
800 		}
801 		Unlock();
802 	}
803 }
804 
805 
806 void
807 BClipboardRefsWatcher::MessageReceived(BMessage *message)
808 {
809 	if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) {
810 		if (!(fRefsInClipboard = FSClipboardHasRefs()))
811 			Clear();
812 		return;
813 	} else if (message->what != B_NODE_MONITOR) {
814 		_inherited::MessageReceived(message);
815 		return;
816 	}
817 
818 	switch (message->FindInt32("opcode")) {
819 		case B_ENTRY_MOVED:
820 		{
821 			ino_t toDir;
822 			ino_t fromDir;
823 			node_ref node;
824 			const char *name = NULL;
825 			message->FindInt64("from directory", &fromDir);
826 			message->FindInt64("to directory", &toDir);
827 			message->FindInt64("node", &node.node);
828 			message->FindInt32("device", &node.device);
829 			message->FindString("name", &name);
830 			entry_ref ref(node.device, toDir, name);
831 			UpdateNode(&node, &ref);
832 			break;
833 		}
834 
835 		case B_DEVICE_UNMOUNTED:
836 		{
837 			dev_t device;
838 			message->FindInt32("device", &device);
839 			RemoveNodesByDevice(device);
840 			break;
841 		}
842 
843 		case B_ENTRY_REMOVED:
844 		{
845 			node_ref node;
846 			message->FindInt64("node", &node.node);
847 			message->FindInt32("device", &node.device);
848 			RemoveNode(&node, true);
849 			break;
850 		}
851 	}
852 }
853