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(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 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 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 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 621 BClipboardRefsWatcher::~BClipboardRefsWatcher() 622 { 623 stop_watching(this); 624 be_clipboard->StopWatching(this); 625 } 626 627 628 void 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 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 671 BClipboardRefsWatcher::AddNode(const node_ref* node) 672 { 673 TTracker::WatchNode(node, B_WATCH_NAME, this); 674 fRefsInClipboard = true; 675 } 676 677 678 void 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 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 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 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 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 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