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 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 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 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 91 MakeModeName(char* name) 92 { 93 name[0] = 'm'; 94 } 95 96 97 static inline void 98 MakeModeNameFromRefName(char* modeName, char* refName) 99 { 100 strcpy(modeName, refName); 101 modeName[0] = 'm'; 102 } 103 104 105 static inline bool 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 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 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 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 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 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 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 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 = NULL; 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 405 || updateNodeRef.node != ref.directory) { 406 if (updateMessage != NULL) { 407 tracker.SendMessage(updateMessage); 408 delete updateMessage; 409 } 410 411 updateNodeRef.device = ref.device; 412 updateNodeRef.node = ref.directory; 413 414 updateMessage = new BMessage(kFSClipboardChanges); 415 updateMessage->AddInt32("device", updateNodeRef.device); 416 updateMessage->AddInt64("directory", updateNodeRef.node); 417 } 418 419 // we need this data later on 420 MakeModeNameFromRefName(modeName, refName); 421 if (!linksMode && clip->FindInt32(modeName, (int32*)&moveMode) 422 != B_OK) { 423 continue; 424 } 425 426 BEntry entry(&ref); 427 428 uint32 newMoveMode = 0; 429 bool sameDirectory = destNodeRef->device == ref.device 430 && destNodeRef->node == ref.directory; 431 432 if (!entry.Exists()) { 433 // The entry doesn't exist anymore, so we'll remove 434 // that entry from the clipboard as well 435 clip->RemoveName(refName); 436 clip->RemoveName(modeName); 437 438 newMoveMode = kDelete; 439 } else { 440 // the entry does exist, so lets see what we will 441 // do with it 442 if (!sameDirectory) { 443 if (linksMode || moveMode == kMoveSelectionTo) { 444 // the linksMode uses the moveList as well 445 moveList->AddItem(new entry_ref(ref)); 446 } else if (moveMode == kCopySelectionTo) 447 copyList->AddItem(new entry_ref(ref)); 448 } else { 449 // if the entry should have been removed from its 450 // directory, we want to copy that entry next time, no 451 // matter if the items don't have to be moved at all 452 // (source == target) 453 if (moveMode == kMoveSelectionTo) 454 newMoveMode = kCopySelectionTo; 455 else { 456 // we are copying a file into its same directory, do 457 // a duplicate 458 duplicateList->AddItem(new entry_ref(ref)); 459 } 460 } 461 } 462 463 // add the change to the update message (if necessary) 464 if (newMoveMode) { 465 clip->ReplaceInt32(modeName, kCopySelectionTo); 466 467 TClipboardNodeRef clipNode; 468 MakeNodeFromName(&clipNode.node, modeName); 469 clipNode.moveMode = kDelete; 470 updateMessage->AddData("tcnode", T_CLIPBOARD_NODE, 471 &clipNode, sizeof(TClipboardNodeRef), true); 472 } 473 } 474 be_clipboard->Commit(); 475 476 // send notification for the last directory 477 if (updateMessage != NULL) { 478 tracker.SendMessage(updateMessage); 479 delete updateMessage; 480 } 481 } 482 be_clipboard->Unlock(); 483 } 484 485 bool okToMove = true; 486 487 // can't copy/paste to root('/') directory 488 if (model->IsRoot()) { 489 BAlert* alert = new BAlert("", 490 B_TRANSLATE("You must drop items on one of the disk icons " 491 "in the \"Disks\" window."), B_TRANSLATE("Cancel"), NULL, NULL, 492 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 493 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 494 alert->Go(); 495 okToMove = false; 496 } 497 498 BEntry entry; 499 model->GetEntry(&entry); 500 501 // can't copy items into the trash 502 if (copyList->CountItems() > 0 && model->IsTrash()) { 503 BAlert* alert = new BAlert("", 504 B_TRANSLATE("Sorry, you can't copy items to the Trash."), 505 B_TRANSLATE("Cancel"), NULL, NULL, B_WIDTH_AS_USUAL, 506 B_WARNING_ALERT); 507 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 508 alert->Go(); 509 okToMove = false; 510 } 511 512 if (!okToMove) { 513 // there was some problem with our target, so we bail out here 514 delete moveList; 515 delete copyList; 516 return false; 517 } 518 519 // asynchronous calls take over ownership of the objects passed to it 520 if (moveList->CountItems() > 0) { 521 FSMoveToFolder(moveList, new BEntry(entry), 522 linksMode ? linksMode : kMoveSelectionTo); 523 } else 524 delete moveList; 525 526 if (copyList->CountItems() > 0) 527 FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo); 528 else 529 delete copyList; 530 531 if (duplicateList->CountItems() > 0) 532 FSMoveToFolder(duplicateList, new BEntry(entry), kDuplicateSelection); 533 else 534 delete duplicateList; 535 536 return true; 537 } 538 539 540 // Seek node in clipboard, if found return it's moveMode 541 // else return 0 542 uint32 543 FSClipboardFindNodeMode(Model* model, bool autoLock, bool updateRefIfNeeded) 544 { 545 int32 moveMode = 0; 546 if (autoLock) { 547 if (!be_clipboard->Lock()) 548 return 0; 549 } 550 bool remove = false; 551 bool change = false; 552 553 BMessage* clip = be_clipboard->Data(); 554 if (clip != NULL) { 555 const node_ref* node = model->NodeRef(); 556 char modeName[64]; 557 MakeModeName(modeName, node); 558 if ((clip->FindInt32(modeName, &moveMode) == B_OK)) { 559 const entry_ref* ref = model->EntryRef(); 560 entry_ref clipref; 561 char refName[64]; 562 MakeRefName(refName, node); 563 if ((clip->FindRef(refName, &clipref) == B_OK)) { 564 if (clipref != *ref) { 565 if (updateRefIfNeeded) { 566 clip->ReplaceRef(refName, ref); 567 change = true; 568 } else { 569 clip->RemoveName(refName); 570 clip->RemoveName(modeName); 571 change = true; 572 remove = true; 573 moveMode = 0; 574 } 575 } 576 } else { 577 clip->RemoveName(modeName); 578 change = true; 579 remove = true; 580 moveMode = 0; 581 } 582 } 583 } 584 if (change) 585 be_clipboard->Commit(); 586 587 if (autoLock) 588 be_clipboard->Unlock(); 589 590 if (remove) 591 FSClipboardRemove(model); 592 593 return (uint32)moveMode; 594 } 595 596 597 void 598 FSClipboardRemove(Model* model) 599 { 600 BMessenger messenger(kTrackerSignature); 601 if (messenger.IsValid()) { 602 BMessage* report = new BMessage(kFSClipboardChanges); 603 TClipboardNodeRef tcnode; 604 tcnode.node = *model->NodeRef(); 605 tcnode.moveMode = kDelete; 606 const entry_ref* ref = model->EntryRef(); 607 report->AddInt32("device", ref->device); 608 report->AddInt64("directory", ref->directory); 609 report->AddBool("clearClipboard", false); 610 report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode), 611 true); 612 messenger.SendMessage(report); 613 delete report; 614 } 615 } 616 617 618 // #pragma mark - 619 620 621 BClipboardRefsWatcher::BClipboardRefsWatcher() 622 : BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096), 623 fNotifyList(10, false) 624 { 625 watch_node(NULL, B_WATCH_MOUNT, this); 626 fRefsInClipboard = FSClipboardHasRefs(); 627 be_clipboard->StartWatching(this); 628 } 629 630 631 BClipboardRefsWatcher::~BClipboardRefsWatcher() 632 { 633 stop_watching(this); 634 be_clipboard->StopWatching(this); 635 } 636 637 638 void 639 BClipboardRefsWatcher::AddToNotifyList(BMessenger target) 640 { 641 if (Lock()) { 642 // add the messenger if it's not already in the list 643 // ToDo: why do we have to care about that? 644 BMessenger* messenger; 645 bool found = false; 646 647 for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL; 648 index++) { 649 if (*messenger == target) { 650 found = true; 651 break; 652 } 653 } 654 if (!found) 655 fNotifyList.AddItem(new BMessenger(target)); 656 657 Unlock(); 658 } 659 } 660 661 662 void 663 BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target) 664 { 665 if (Lock()) { 666 BMessenger* messenger; 667 668 for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL; 669 index++) { 670 if (*messenger == target) { 671 delete fNotifyList.RemoveItemAt(index); 672 break; 673 } 674 } 675 Unlock(); 676 } 677 } 678 679 680 void 681 BClipboardRefsWatcher::AddNode(const node_ref* node) 682 { 683 TTracker::WatchNode(node, B_WATCH_NAME, this); 684 fRefsInClipboard = true; 685 } 686 687 688 void 689 BClipboardRefsWatcher::RemoveNode(node_ref* node, bool removeFromClipboard) 690 { 691 watch_node(node, B_STOP_WATCHING, this); 692 693 if (!removeFromClipboard) 694 return; 695 696 if (be_clipboard->Lock()) { 697 BMessage* clip = be_clipboard->Data(); 698 if (clip != NULL) { 699 char name[64]; 700 MakeRefName(name, node); 701 clip->RemoveName(name); 702 MakeModeName(name); 703 clip->RemoveName(name); 704 705 be_clipboard->Commit(); 706 } 707 be_clipboard->Unlock(); 708 } 709 } 710 711 712 void 713 BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device) 714 { 715 if (!be_clipboard->Lock()) 716 return; 717 718 BMessage* clip = be_clipboard->Data(); 719 if (clip != NULL) { 720 char deviceName[6]; 721 sprintf(deviceName, "r%" B_PRIdDEV "_", device); 722 723 int32 index = 0; 724 char* refName; 725 type_code type; 726 int32 count; 727 while (clip->GetInfo(B_REF_TYPE, index, 728 #ifdef B_BEOS_VERSION_DANO 729 (const char**) 730 #endif 731 &refName, &type, &count) == B_OK) { 732 if (!strncmp(deviceName, refName, strlen(deviceName))) { 733 clip->RemoveName(refName); 734 MakeModeName(refName); 735 clip->RemoveName(refName); 736 737 node_ref node; 738 MakeNodeFromName(&node, refName); 739 watch_node(&node, B_STOP_WATCHING, this); 740 } 741 index++; 742 } 743 be_clipboard->Commit(); 744 } 745 be_clipboard->Unlock(); 746 } 747 748 749 void 750 BClipboardRefsWatcher::UpdateNode(node_ref* node, entry_ref* ref) 751 { 752 if (!be_clipboard->Lock()) 753 return; 754 755 BMessage* clip = be_clipboard->Data(); 756 if (clip != NULL) { 757 char name[64]; 758 MakeRefName(name, node); 759 if ((clip->ReplaceRef(name, ref)) != B_OK) { 760 clip->RemoveName(name); 761 MakeModeName(name); 762 clip->RemoveName(name); 763 764 RemoveNode(node); 765 } 766 be_clipboard->Commit(); 767 } 768 be_clipboard->Unlock(); 769 } 770 771 772 void 773 BClipboardRefsWatcher::Clear() 774 { 775 stop_watching(this); 776 watch_node(NULL, B_WATCH_MOUNT, this); 777 778 BMessage message(kFSClipboardChanges); 779 message.AddBool("clearClipboard", true); 780 if (Lock()) { 781 int32 items = fNotifyList.CountItems(); 782 for (int32 i = 0;i < items;i++) { 783 fNotifyList.ItemAt(i)->SendMessage(&message); 784 } 785 Unlock(); 786 } 787 } 788 789 790 //void 791 //BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard, 792 // const node_ref* node) 793 //{ 794 // BMessage message(kFSClipboardChanges); 795 // message.AddInt32("device", node->device); 796 // message.AddInt64("directory", node->node); 797 // message.AddBool("clearClipboard", clearClipboard); 798 // 799 // if (Lock()) { 800 // int32 items = fNotifyList.CountItems(); 801 // for (int32 i = 0;i < items;i++) { 802 // fNotifyList.ItemAt(i)->SendMessage(&message); 803 // } 804 // Unlock(); 805 // } 806 //} 807 808 809 void 810 BClipboardRefsWatcher::UpdatePoseViews(BMessage* reportMessage) 811 { 812 if (Lock()) { 813 // check if it was cleared, if so clear watching 814 bool clearClipboard = false; 815 if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK 816 && clearClipboard) { 817 stop_watching(this); 818 watch_node(NULL, B_WATCH_MOUNT, this); 819 } 820 821 // loop through reported node_ref's movemodes: 822 // move or copy: start watching node_ref 823 // remove: stop watching node_ref 824 int32 index = 0; 825 TClipboardNodeRef* tcnode = NULL; 826 ssize_t size; 827 while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index, 828 (const void**)&tcnode, &size) == B_OK) { 829 if (tcnode->moveMode == kDelete) { 830 watch_node(&tcnode->node, B_STOP_WATCHING, this); 831 } else { 832 watch_node(&tcnode->node, B_STOP_WATCHING, this); 833 TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this); 834 fRefsInClipboard = true; 835 } 836 index++; 837 } 838 839 // send report 840 int32 items = fNotifyList.CountItems(); 841 for (int32 i = 0;i < items;i++) { 842 fNotifyList.ItemAt(i)->SendMessage(reportMessage); 843 } 844 Unlock(); 845 } 846 } 847 848 849 void 850 BClipboardRefsWatcher::MessageReceived(BMessage* message) 851 { 852 if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) { 853 if (!(fRefsInClipboard = FSClipboardHasRefs())) 854 Clear(); 855 return; 856 } else if (message->what != B_NODE_MONITOR) { 857 _inherited::MessageReceived(message); 858 return; 859 } 860 861 switch (message->FindInt32("opcode")) { 862 case B_ENTRY_MOVED: 863 { 864 ino_t toDir; 865 ino_t fromDir; 866 node_ref node; 867 const char* name = NULL; 868 message->FindInt64("from directory", &fromDir); 869 message->FindInt64("to directory", &toDir); 870 message->FindInt64("node", &node.node); 871 message->FindInt32("device", &node.device); 872 message->FindString("name", &name); 873 entry_ref ref(node.device, toDir, name); 874 UpdateNode(&node, &ref); 875 break; 876 } 877 878 case B_DEVICE_UNMOUNTED: 879 { 880 dev_t device; 881 message->FindInt32("device", &device); 882 RemoveNodesByDevice(device); 883 break; 884 } 885 886 case B_ENTRY_REMOVED: 887 { 888 node_ref node; 889 message->FindInt64("node", &node.node); 890 message->FindInt32("device", &node.device); 891 RemoveNode(&node, true); 892 break; 893 } 894 } 895 } 896