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