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 <Catalog.h> 39 #include <Locale.h> 40 #include <NodeMonitor.h> 41 #include "Commands.h" 42 #include "FSUtils.h" 43 #include "Tracker.h" 44 45 46 // prototypes 47 static void MakeNodeFromName(node_ref *node, char *name); 48 static inline void MakeRefName(char *refName, const node_ref *node); 49 static inline void MakeModeName(char *modeName, const node_ref *node); 50 static inline void MakeModeNameFromRefName(char *modeName, char *refName); 51 static inline bool CompareModeAndRefName(const char *modeName, const char *refName); 52 53 /* 54 static bool 55 FSClipboardCheckIntegrity() 56 { 57 return true; 58 } 59 */ 60 61 static void 62 MakeNodeFromName(node_ref *node, char *name) 63 { 64 char *nodeString = strchr(name, '_'); 65 if (nodeString != NULL) { 66 node->node = strtoll(nodeString + 1, (char **)NULL, 10); 67 node->device = atoi(name + 1); 68 } 69 } 70 71 72 static inline void 73 MakeRefName(char *refName, const node_ref *node) 74 { 75 sprintf(refName, "r%ld_%Ld", node->device, node->node); 76 } 77 78 79 static inline void 80 MakeModeName(char *modeName, const node_ref *node) 81 { 82 sprintf(modeName, "m%ld_%Ld", node->device, node->node); 83 } 84 85 86 static inline void 87 MakeModeName(char *name) 88 { 89 name[0] = 'm'; 90 } 91 92 93 static inline void 94 MakeModeNameFromRefName(char *modeName, char *refName) 95 { 96 strcpy(modeName, refName); 97 modeName[0] = 'm'; 98 } 99 100 101 static inline bool 102 CompareModeAndRefName(const char *modeName, const char *refName) 103 { 104 return !strcmp(refName + 1, modeName + 1); 105 } 106 107 108 // #pragma mark - 109 110 111 #undef B_TRANSLATION_CONTEXT 112 #define B_TRANSLATION_CONTEXT "FSClipBoard" 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 || model->IsTrash() 232 || model->IsDesktop()) 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("", 472 B_TRANSLATE("You must drop items on one of the disk icons " 473 "in the \"Disks\" window."), B_TRANSLATE("Cancel"), NULL, NULL, 474 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 475 alert->SetShortcut(0, B_ESCAPE); 476 alert->Go(); 477 okToMove = false; 478 } 479 480 BEntry entry; 481 model->GetEntry(&entry); 482 483 // can't copy items into the trash 484 if (copyList->CountItems() > 0 && model->IsTrash()) { 485 BAlert* alert = new BAlert("", 486 B_TRANSLATE("Sorry, you can't copy items to the Trash."), 487 B_TRANSLATE("Cancel"), NULL, NULL, B_WIDTH_AS_USUAL, 488 B_WARNING_ALERT); 489 alert->SetShortcut(0, B_ESCAPE); 490 alert->Go(); 491 okToMove = false; 492 } 493 494 if (!okToMove) { 495 // there was some problem with our target, so we bail out here 496 delete moveList; 497 delete copyList; 498 return false; 499 } 500 501 // asynchronous calls take over ownership of the objects passed to it 502 if (moveList->CountItems() > 0) 503 FSMoveToFolder(moveList, new BEntry(entry), linksMode ? linksMode : kMoveSelectionTo); 504 else 505 delete moveList; 506 507 if (copyList->CountItems() > 0) 508 FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo); 509 else 510 delete copyList; 511 512 return true; 513 } 514 515 516 /** Seek node in clipboard, if found return it's moveMode 517 * else return 0 518 */ 519 520 uint32 521 FSClipboardFindNodeMode(Model *model, bool autoLock, bool updateRefIfNeeded) 522 { 523 int32 moveMode = 0; 524 if (autoLock) { 525 if (!be_clipboard->Lock()) 526 return 0; 527 } 528 bool remove = false; 529 bool change = false; 530 531 BMessage *clip = be_clipboard->Data(); 532 if (clip != NULL) { 533 const node_ref *node = model->NodeRef(); 534 char modeName[64]; 535 MakeModeName(modeName, node); 536 if ((clip->FindInt32(modeName, &moveMode) == B_OK)) { 537 const entry_ref *ref = model->EntryRef(); 538 entry_ref clipref; 539 char refName[64]; 540 MakeRefName(refName, node); 541 if ((clip->FindRef(refName, &clipref) == B_OK)) { 542 if (clipref != *ref) { 543 if (updateRefIfNeeded) { 544 clip->ReplaceRef(refName, ref); 545 change = true; 546 } else { 547 clip->RemoveName(refName); 548 clip->RemoveName(modeName); 549 change = true; 550 remove = true; 551 moveMode = 0; 552 } 553 } 554 } else { 555 clip->RemoveName(modeName); 556 change = true; 557 remove = true; 558 moveMode = 0; 559 } 560 } 561 } 562 if (change) 563 be_clipboard->Commit(); 564 565 if (autoLock) 566 be_clipboard->Unlock(); 567 568 if (remove) 569 FSClipboardRemove(model); 570 571 return (uint32)moveMode; 572 } 573 574 575 void 576 FSClipboardRemove(Model *model) 577 { 578 BMessenger messenger(kTrackerSignature); 579 if (messenger.IsValid()) { 580 BMessage *report = new BMessage(kFSClipboardChanges); 581 TClipboardNodeRef tcnode; 582 tcnode.node = *model->NodeRef(); 583 tcnode.moveMode = kDelete; 584 const entry_ref *ref = model->EntryRef(); 585 report->AddInt32("device", ref->device); 586 report->AddInt64("directory", ref->directory); 587 report->AddBool("clearClipboard", false); 588 report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode), true); 589 messenger.SendMessage(report); 590 delete report; 591 } 592 } 593 594 595 // #pragma mark - 596 597 598 BClipboardRefsWatcher::BClipboardRefsWatcher() 599 : BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096), 600 fNotifyList(10, false) 601 { 602 watch_node(NULL, B_WATCH_MOUNT, this); 603 fRefsInClipboard = FSClipboardHasRefs(); 604 be_clipboard->StartWatching(this); 605 } 606 607 608 BClipboardRefsWatcher::~BClipboardRefsWatcher() 609 { 610 stop_watching(this); 611 be_clipboard->StopWatching(this); 612 } 613 614 615 void 616 BClipboardRefsWatcher::AddToNotifyList(BMessenger target) 617 { 618 if (Lock()) { 619 // add the messenger if it's not already in the list 620 // ToDo: why do we have to care about that? 621 BMessenger *messenger; 622 bool found = false; 623 624 for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) { 625 if (*messenger == target) { 626 found = true; 627 break; 628 } 629 } 630 if (!found) 631 fNotifyList.AddItem(new BMessenger(target)); 632 633 Unlock(); 634 } 635 } 636 637 638 void 639 BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target) 640 { 641 if (Lock()) { 642 BMessenger *messenger; 643 644 for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) { 645 if (*messenger == target) { 646 delete fNotifyList.RemoveItemAt(index); 647 break; 648 } 649 } 650 Unlock(); 651 } 652 } 653 654 655 void 656 BClipboardRefsWatcher::AddNode(const node_ref *node) 657 { 658 TTracker::WatchNode(node, B_WATCH_NAME, this); 659 fRefsInClipboard = true; 660 } 661 662 663 void 664 BClipboardRefsWatcher::RemoveNode(node_ref *node, bool removeFromClipboard) 665 { 666 watch_node(node, B_STOP_WATCHING, this); 667 668 if (!removeFromClipboard) 669 return; 670 671 if (be_clipboard->Lock()) { 672 BMessage *clip = be_clipboard->Data(); 673 if (clip != NULL) { 674 char name[64]; 675 MakeRefName(name, node); 676 clip->RemoveName(name); 677 MakeModeName(name); 678 clip->RemoveName(name); 679 680 be_clipboard->Commit(); 681 } 682 be_clipboard->Unlock(); 683 } 684 } 685 686 687 void 688 BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device) 689 { 690 if (!be_clipboard->Lock()) 691 return; 692 693 BMessage *clip = be_clipboard->Data(); 694 if (clip != NULL) { 695 char deviceName[6]; 696 sprintf(deviceName, "r%ld_", device); 697 698 int32 index = 0; 699 char *refName; 700 type_code type; 701 int32 count; 702 while (clip->GetInfo(B_REF_TYPE, index, 703 #ifdef B_BEOS_VERSION_DANO 704 (const char **) 705 #endif 706 &refName, &type, &count) == B_OK) { 707 if (!strncmp(deviceName, refName, strlen(deviceName))) { 708 clip->RemoveName(refName); 709 MakeModeName(refName); 710 clip->RemoveName(refName); 711 712 node_ref node; 713 MakeNodeFromName(&node, refName); 714 watch_node(&node, B_STOP_WATCHING, this); 715 } 716 index++; 717 } 718 be_clipboard->Commit(); 719 } 720 be_clipboard->Unlock(); 721 } 722 723 724 void 725 BClipboardRefsWatcher::UpdateNode(node_ref *node, entry_ref *ref) 726 { 727 if (!be_clipboard->Lock()) 728 return; 729 730 BMessage *clip = be_clipboard->Data(); 731 if (clip != NULL) { 732 char name[64]; 733 MakeRefName(name, node); 734 if ((clip->ReplaceRef(name, ref)) != B_OK) { 735 clip->RemoveName(name); 736 MakeModeName(name); 737 clip->RemoveName(name); 738 739 RemoveNode(node); 740 } 741 be_clipboard->Commit(); 742 } 743 be_clipboard->Unlock(); 744 } 745 746 747 void 748 BClipboardRefsWatcher::Clear() 749 { 750 stop_watching(this); 751 watch_node(NULL, B_WATCH_MOUNT, this); 752 753 BMessage message(kFSClipboardChanges); 754 message.AddBool("clearClipboard", true); 755 if (Lock()) { 756 int32 items = fNotifyList.CountItems(); 757 for (int32 i = 0;i < items;i++) { 758 fNotifyList.ItemAt(i)->SendMessage(&message); 759 } 760 Unlock(); 761 } 762 } 763 764 /* 765 void 766 BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard, const node_ref *node) 767 { 768 BMessage message(kFSClipboardChanges); 769 message.AddInt32("device", node->device); 770 message.AddInt64("directory", node->node); 771 message.AddBool("clearClipboard", clearClipboard); 772 773 if (Lock()) { 774 int32 items = fNotifyList.CountItems(); 775 for (int32 i = 0;i < items;i++) { 776 fNotifyList.ItemAt(i)->SendMessage(&message); 777 } 778 Unlock(); 779 } 780 } 781 */ 782 783 void 784 BClipboardRefsWatcher::UpdatePoseViews(BMessage *reportMessage) 785 { 786 if (Lock()) { 787 // check if it was cleared, if so clear watching 788 bool clearClipboard = false; 789 if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK 790 && clearClipboard) { 791 stop_watching(this); 792 watch_node(NULL, B_WATCH_MOUNT, this); 793 } 794 795 // loop through reported node_ref's movemodes: 796 // move or copy: start watching node_ref 797 // remove: stop watching node_ref 798 int32 index = 0; 799 TClipboardNodeRef *tcnode = NULL; 800 ssize_t size; 801 while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index, (const void**)&tcnode, &size) == B_OK) { 802 if (tcnode->moveMode == kDelete) { 803 watch_node(&tcnode->node, B_STOP_WATCHING, this); 804 } else { 805 watch_node(&tcnode->node, B_STOP_WATCHING, this); 806 TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this); 807 fRefsInClipboard = true; 808 } 809 index++; 810 } 811 812 // send report 813 int32 items = fNotifyList.CountItems(); 814 for (int32 i = 0;i < items;i++) { 815 fNotifyList.ItemAt(i)->SendMessage(reportMessage); 816 } 817 Unlock(); 818 } 819 } 820 821 822 void 823 BClipboardRefsWatcher::MessageReceived(BMessage *message) 824 { 825 if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) { 826 if (!(fRefsInClipboard = FSClipboardHasRefs())) 827 Clear(); 828 return; 829 } else if (message->what != B_NODE_MONITOR) { 830 _inherited::MessageReceived(message); 831 return; 832 } 833 834 switch (message->FindInt32("opcode")) { 835 case B_ENTRY_MOVED: 836 { 837 ino_t toDir; 838 ino_t fromDir; 839 node_ref node; 840 const char *name = NULL; 841 message->FindInt64("from directory", &fromDir); 842 message->FindInt64("to directory", &toDir); 843 message->FindInt64("node", &node.node); 844 message->FindInt32("device", &node.device); 845 message->FindString("name", &name); 846 entry_ref ref(node.device, toDir, name); 847 UpdateNode(&node, &ref); 848 break; 849 } 850 851 case B_DEVICE_UNMOUNTED: 852 { 853 dev_t device; 854 message->FindInt32("device", &device); 855 RemoveNodesByDevice(device); 856 break; 857 } 858 859 case B_ENTRY_REMOVED: 860 { 861 node_ref node; 862 message->FindInt64("node", &node.node); 863 message->FindInt32("device", &node.device); 864 RemoveNode(&node, true); 865 break; 866 } 867 } 868 } 869