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