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