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