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