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 delete duplicateList; 517 return false; 518 } 519 520 // asynchronous calls take over ownership of the objects passed to it 521 if (moveList->CountItems() > 0) { 522 FSMoveToFolder(moveList, new BEntry(entry), 523 linksMode ? linksMode : kMoveSelectionTo); 524 } else 525 delete moveList; 526 527 if (copyList->CountItems() > 0) 528 FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo); 529 else 530 delete copyList; 531 532 if (duplicateList->CountItems() > 0) 533 FSMoveToFolder(duplicateList, new BEntry(entry), kDuplicateSelection); 534 else 535 delete duplicateList; 536 537 return true; 538 } 539 540 541 // Seek node in clipboard, if found return it's moveMode 542 // else return 0 543 uint32 544 FSClipboardFindNodeMode(Model* model, bool autoLock, bool updateRefIfNeeded) 545 { 546 int32 moveMode = 0; 547 if (autoLock) { 548 if (!be_clipboard->Lock()) 549 return 0; 550 } 551 bool remove = false; 552 bool change = false; 553 554 BMessage* clip = be_clipboard->Data(); 555 if (clip != NULL) { 556 const node_ref* node = model->NodeRef(); 557 char modeName[64]; 558 MakeModeName(modeName, node); 559 if ((clip->FindInt32(modeName, &moveMode) == B_OK)) { 560 const entry_ref* ref = model->EntryRef(); 561 entry_ref clipref; 562 char refName[64]; 563 MakeRefName(refName, node); 564 if ((clip->FindRef(refName, &clipref) == B_OK)) { 565 if (clipref != *ref) { 566 if (updateRefIfNeeded) { 567 clip->ReplaceRef(refName, ref); 568 change = true; 569 } else { 570 clip->RemoveName(refName); 571 clip->RemoveName(modeName); 572 change = true; 573 remove = true; 574 moveMode = 0; 575 } 576 } 577 } else { 578 clip->RemoveName(modeName); 579 change = true; 580 remove = true; 581 moveMode = 0; 582 } 583 } 584 } 585 if (change) 586 be_clipboard->Commit(); 587 588 if (autoLock) 589 be_clipboard->Unlock(); 590 591 if (remove) 592 FSClipboardRemove(model); 593 594 return (uint32)moveMode; 595 } 596 597 598 void 599 FSClipboardRemove(Model* model) 600 { 601 BMessenger messenger(kTrackerSignature); 602 if (messenger.IsValid()) { 603 BMessage* report = new BMessage(kFSClipboardChanges); 604 TClipboardNodeRef tcnode; 605 tcnode.node = *model->NodeRef(); 606 tcnode.moveMode = kDelete; 607 const entry_ref* ref = model->EntryRef(); 608 report->AddInt32("device", ref->device); 609 report->AddInt64("directory", ref->directory); 610 report->AddBool("clearClipboard", false); 611 report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode), 612 true); 613 messenger.SendMessage(report); 614 delete report; 615 } 616 } 617 618 619 // #pragma mark - 620 621 622 BClipboardRefsWatcher::BClipboardRefsWatcher() 623 : BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096), 624 fNotifyList(10, false) 625 { 626 watch_node(NULL, B_WATCH_MOUNT, this); 627 fRefsInClipboard = FSClipboardHasRefs(); 628 be_clipboard->StartWatching(this); 629 } 630 631 632 BClipboardRefsWatcher::~BClipboardRefsWatcher() 633 { 634 stop_watching(this); 635 be_clipboard->StopWatching(this); 636 } 637 638 639 void 640 BClipboardRefsWatcher::AddToNotifyList(BMessenger target) 641 { 642 if (Lock()) { 643 // add the messenger if it's not already in the list 644 // ToDo: why do we have to care about that? 645 BMessenger* messenger; 646 bool found = false; 647 648 for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL; 649 index++) { 650 if (*messenger == target) { 651 found = true; 652 break; 653 } 654 } 655 if (!found) 656 fNotifyList.AddItem(new BMessenger(target)); 657 658 Unlock(); 659 } 660 } 661 662 663 void 664 BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target) 665 { 666 if (Lock()) { 667 BMessenger* messenger; 668 669 for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL; 670 index++) { 671 if (*messenger == target) { 672 delete fNotifyList.RemoveItemAt(index); 673 break; 674 } 675 } 676 Unlock(); 677 } 678 } 679 680 681 void 682 BClipboardRefsWatcher::AddNode(const node_ref* node) 683 { 684 TTracker::WatchNode(node, B_WATCH_NAME, this); 685 fRefsInClipboard = true; 686 } 687 688 689 void 690 BClipboardRefsWatcher::RemoveNode(node_ref* node, bool removeFromClipboard) 691 { 692 watch_node(node, B_STOP_WATCHING, this); 693 694 if (!removeFromClipboard) 695 return; 696 697 if (be_clipboard->Lock()) { 698 BMessage* clip = be_clipboard->Data(); 699 if (clip != NULL) { 700 char name[64]; 701 MakeRefName(name, node); 702 clip->RemoveName(name); 703 MakeModeName(name); 704 clip->RemoveName(name); 705 706 be_clipboard->Commit(); 707 } 708 be_clipboard->Unlock(); 709 } 710 } 711 712 713 void 714 BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device) 715 { 716 if (!be_clipboard->Lock()) 717 return; 718 719 BMessage* clip = be_clipboard->Data(); 720 if (clip != NULL) { 721 char deviceName[6]; 722 sprintf(deviceName, "r%" B_PRIdDEV "_", device); 723 724 int32 index = 0; 725 char* refName; 726 type_code type; 727 int32 count; 728 while (clip->GetInfo(B_REF_TYPE, index, 729 #ifdef B_BEOS_VERSION_DANO 730 (const char**) 731 #endif 732 &refName, &type, &count) == B_OK) { 733 if (!strncmp(deviceName, refName, strlen(deviceName))) { 734 clip->RemoveName(refName); 735 MakeModeName(refName); 736 clip->RemoveName(refName); 737 738 node_ref node; 739 MakeNodeFromName(&node, refName); 740 watch_node(&node, B_STOP_WATCHING, this); 741 } 742 index++; 743 } 744 be_clipboard->Commit(); 745 } 746 be_clipboard->Unlock(); 747 } 748 749 750 void 751 BClipboardRefsWatcher::UpdateNode(node_ref* node, entry_ref* ref) 752 { 753 if (!be_clipboard->Lock()) 754 return; 755 756 BMessage* clip = be_clipboard->Data(); 757 if (clip != NULL) { 758 char name[64]; 759 MakeRefName(name, node); 760 if ((clip->ReplaceRef(name, ref)) != B_OK) { 761 clip->RemoveName(name); 762 MakeModeName(name); 763 clip->RemoveName(name); 764 765 RemoveNode(node); 766 } 767 be_clipboard->Commit(); 768 } 769 be_clipboard->Unlock(); 770 } 771 772 773 void 774 BClipboardRefsWatcher::Clear() 775 { 776 stop_watching(this); 777 watch_node(NULL, B_WATCH_MOUNT, this); 778 779 BMessage message(kFSClipboardChanges); 780 message.AddBool("clearClipboard", true); 781 if (Lock()) { 782 int32 items = fNotifyList.CountItems(); 783 for (int32 i = 0;i < items;i++) { 784 fNotifyList.ItemAt(i)->SendMessage(&message); 785 } 786 Unlock(); 787 } 788 } 789 790 791 //void 792 //BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard, 793 // const node_ref* node) 794 //{ 795 // BMessage message(kFSClipboardChanges); 796 // message.AddInt32("device", node->device); 797 // message.AddInt64("directory", node->node); 798 // message.AddBool("clearClipboard", clearClipboard); 799 // 800 // if (Lock()) { 801 // int32 items = fNotifyList.CountItems(); 802 // for (int32 i = 0;i < items;i++) { 803 // fNotifyList.ItemAt(i)->SendMessage(&message); 804 // } 805 // Unlock(); 806 // } 807 //} 808 809 810 void 811 BClipboardRefsWatcher::UpdatePoseViews(BMessage* reportMessage) 812 { 813 if (Lock()) { 814 // check if it was cleared, if so clear watching 815 bool clearClipboard = false; 816 if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK 817 && clearClipboard) { 818 stop_watching(this); 819 watch_node(NULL, B_WATCH_MOUNT, this); 820 } 821 822 // loop through reported node_ref's movemodes: 823 // move or copy: start watching node_ref 824 // remove: stop watching node_ref 825 int32 index = 0; 826 TClipboardNodeRef* tcnode = NULL; 827 ssize_t size; 828 while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index, 829 (const void**)&tcnode, &size) == B_OK) { 830 if (tcnode->moveMode == kDelete) { 831 watch_node(&tcnode->node, B_STOP_WATCHING, this); 832 } else { 833 watch_node(&tcnode->node, B_STOP_WATCHING, this); 834 TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this); 835 fRefsInClipboard = true; 836 } 837 index++; 838 } 839 840 // send report 841 int32 items = fNotifyList.CountItems(); 842 for (int32 i = 0;i < items;i++) { 843 fNotifyList.ItemAt(i)->SendMessage(reportMessage); 844 } 845 Unlock(); 846 } 847 } 848 849 850 void 851 BClipboardRefsWatcher::MessageReceived(BMessage* message) 852 { 853 if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) { 854 if (!(fRefsInClipboard = FSClipboardHasRefs())) 855 Clear(); 856 return; 857 } else if (message->what != B_NODE_MONITOR) { 858 _inherited::MessageReceived(message); 859 return; 860 } 861 862 switch (message->FindInt32("opcode")) { 863 case B_ENTRY_MOVED: 864 { 865 ino_t toDir; 866 ino_t fromDir; 867 node_ref node; 868 const char* name = NULL; 869 message->FindInt64("from directory", &fromDir); 870 message->FindInt64("to directory", &toDir); 871 message->FindInt64("node", &node.node); 872 message->FindInt32("device", &node.device); 873 message->FindString("name", &name); 874 entry_ref ref(node.device, toDir, name); 875 UpdateNode(&node, &ref); 876 break; 877 } 878 879 case B_DEVICE_UNMOUNTED: 880 { 881 dev_t device; 882 message->FindInt32("device", &device); 883 RemoveNodesByDevice(device); 884 break; 885 } 886 887 case B_ENTRY_REMOVED: 888 { 889 node_ref node; 890 message->FindInt64("node", &node.node); 891 message->FindInt32("device", &node.device); 892 RemoveNode(&node, true); 893 break; 894 } 895 } 896 } 897