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