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