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 <errno.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <sys/resource.h> 39 #include <unistd.h> 40 41 #include <Alert.h> 42 #include <Autolock.h> 43 #include <Debug.h> 44 #include <FindDirectory.h> 45 #include <fs_attr.h> 46 #include <fs_info.h> 47 #include <image.h> 48 #include <MenuItem.h> 49 #include <NodeInfo.h> 50 #include <NodeMonitor.h> 51 #include <Path.h> 52 #include <Roster.h> 53 #include <StopWatch.h> 54 #include <Volume.h> 55 #include <VolumeRoster.h> 56 57 #include "Attributes.h" 58 #include "AutoLock.h" 59 #include "AutoMounterSettings.h" 60 #include "BackgroundImage.h" 61 #include "Bitmaps.h" 62 #include "Commands.h" 63 #include "ContainerWindow.h" 64 #include "DeskWindow.h" 65 #include "FindPanel.h" 66 #include "FSClipboard.h" 67 #include "FSUtils.h" 68 #include "InfoWindow.h" 69 #include "MimeTypes.h" 70 #include "MimeTypeList.h" 71 #include "NodePreloader.h" 72 #include "OpenWithWindow.h" 73 #include "PoseView.h" 74 #include "QueryContainerWindow.h" 75 #include "StatusWindow.h" 76 #include "Tracker.h" 77 #include "TrackerSettings.h" 78 #include "TrashWatcher.h" 79 #include "FunctionObject.h" 80 #include "TrackerSettings.h" 81 #include "TrackerSettingsWindow.h" 82 #include "TaskLoop.h" 83 #include "Thread.h" 84 #include "Utilities.h" 85 #include "VolumeWindow.h" 86 87 // PPC binary compatibility. 88 #include "AboutBox.cpp" 89 90 // prototypes for some private kernel calls that will some day be public 91 #ifndef _IMPEXP_ROOT 92 # define _IMPEXP_ROOT 93 #endif 94 95 const int32 DEFAULT_MON_NUM = 4096; 96 // copied from fsil.c 97 98 const int8 kOpenWindowNoFlags = 0; 99 const int8 kOpenWindowMinimized = 1; 100 const int8 kOpenWindowHasState = 2; 101 102 const uint32 PSV_MAKE_PRINTER_ACTIVE_QUIETLY = 'pmaq'; 103 // from pr_server.h 104 105 106 namespace BPrivate { 107 108 NodePreloader *gPreloader = NULL; 109 110 void 111 InitIconPreloader() 112 { 113 static int32 lock = 0; 114 115 if (atomic_add(&lock, 1) != 0) { 116 // Just wait for the icon cache to be instantiated 117 int32 tries = 20; 118 while (IconCache::sIconCache == NULL && tries-- > 0) 119 snooze(10000); 120 return; 121 } 122 123 if (IconCache::sIconCache != NULL) 124 return; 125 126 // only start the node preloader if its Tracker or the Deskbar itself - don't 127 // start it for file panels 128 129 bool preload = dynamic_cast<TTracker *>(be_app) != NULL; 130 if (!preload) { 131 // check for deskbar 132 app_info info; 133 if (be_app->GetAppInfo(&info) == B_OK 134 && !strcmp(info.signature, kDeskbarSignature)) 135 preload = true; 136 } 137 if (preload) 138 gPreloader = NodePreloader::InstallNodePreloader("NodePreloader", be_app); 139 140 IconCache::sIconCache = new IconCache(); 141 142 atomic_add(&lock, -1); 143 } 144 145 } // namespace BPrivate 146 147 148 uint32 149 GetVolumeFlags(Model *model) 150 { 151 fs_info info; 152 if (model->IsVolume()) { 153 // search for the correct volume 154 int32 cookie = 0; 155 dev_t device; 156 while ((device = next_dev(&cookie)) >= B_OK) { 157 if (fs_stat_dev(device,&info)) 158 continue; 159 160 if (!strcmp(info.volume_name,model->Name())) 161 return info.flags; 162 } 163 return B_FS_HAS_ATTR; 164 } 165 if (!fs_stat_dev(model->NodeRef()->device,&info)) 166 return info.flags; 167 168 return B_FS_HAS_ATTR; 169 } 170 171 172 // #pragma mark - 173 174 175 TTracker::TTracker() 176 : BApplication(kTrackerSignature), 177 fSettingsWindow(NULL) 178 { 179 // set the cwd to /boot/home, anything that's launched 180 // from Tracker will automatically inherit this 181 BPath homePath; 182 183 if (find_directory(B_USER_DIRECTORY, &homePath) == B_OK) 184 chdir(homePath.Path()); 185 186 // ask for a bunch more file descriptors so that nested copying works well 187 struct rlimit rl; 188 rl.rlim_cur = 512; 189 rl.rlim_max = RLIM_SAVED_MAX; 190 setrlimit(RLIMIT_NOFILE, &rl); 191 192 fNodeMonitorCount = DEFAULT_MON_NUM; 193 194 #ifdef CHECK_OPEN_MODEL_LEAKS 195 InitOpenModelDumping(); 196 #endif 197 198 InitIconPreloader(); 199 200 #ifdef LEAK_CHECKING 201 SetNewLeakChecking(true); 202 SetMallocLeakChecking(true); 203 #endif 204 205 //This is how often it should update the free space bar on the volume icons 206 SetPulseRate(1000000); 207 } 208 209 210 TTracker::~TTracker() 211 { 212 } 213 214 215 bool 216 TTracker::QuitRequested() 217 { 218 // don't allow user quitting 219 if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) { 220 // but allow quitting to hide fSettingsWindow 221 int32 index = 0; 222 BWindow *window = NULL; 223 while ((window = WindowAt(index++)) != NULL) { 224 if (window == fSettingsWindow) { 225 if (fSettingsWindow->Lock()) { 226 if (!fSettingsWindow->IsHidden() 227 && fSettingsWindow->IsActive()) 228 fSettingsWindow->Hide(); 229 fSettingsWindow->Unlock(); 230 } 231 break; 232 } 233 } 234 return false; 235 } 236 237 gStatusWindow->AttemptToQuit(); 238 // try quitting the copy/move/empty trash threads 239 240 BMessage message; 241 AutoLock<WindowList> lock(&fWindowList); 242 // save open windows in a message inside an attribute of the desktop 243 int32 count = fWindowList.CountItems(); 244 for (int32 i = 0; i < count; i++) { 245 BContainerWindow *window = dynamic_cast<BContainerWindow *> 246 (fWindowList.ItemAt(i)); 247 248 if (window && window->Lock()) { 249 if (window->TargetModel() 250 && !window->PoseView()->IsDesktopWindow()) { 251 if (window->TargetModel()->IsRoot()) 252 message.AddBool("open_disks_window", true); 253 else { 254 BEntry entry; 255 BPath path; 256 const entry_ref *ref = window->TargetModel()->EntryRef(); 257 if (entry.SetTo(ref) == B_OK && entry.GetPath(&path) == B_OK) { 258 int8 flags = window->IsMinimized() ? kOpenWindowMinimized : kOpenWindowNoFlags; 259 uint32 deviceFlags = GetVolumeFlags(window->TargetModel()); 260 261 // save state for every window which is 262 // a) already open on another workspace 263 // b) on a volume not capable of writing attributes 264 if (window != FindContainerWindow(ref) 265 || (deviceFlags & (B_FS_HAS_ATTR | B_FS_IS_READONLY)) != B_FS_HAS_ATTR) { 266 BMessage stateMessage; 267 window->SaveState(stateMessage); 268 window->SetSaveStateEnabled(false); 269 // This is to prevent its state to be saved to the node when closed. 270 message.AddMessage("window state", &stateMessage); 271 flags |= kOpenWindowHasState; 272 } 273 const char *target; 274 bool pathAlreadyExists = false; 275 for (int32 index = 0;message.FindString("paths", index, &target) == B_OK;index++) { 276 if (!strcmp(target,path.Path())) { 277 pathAlreadyExists = true; 278 break; 279 } 280 } 281 if (!pathAlreadyExists) 282 message.AddString("paths", path.Path()); 283 message.AddInt8(path.Path(), flags); 284 } 285 } 286 } 287 window->Unlock(); 288 } 289 } 290 lock.Unlock(); 291 292 // write windows to open on disk 293 BDirectory deskDir; 294 if (!BootedInSafeMode() && FSGetDeskDir(&deskDir) == B_OK) { 295 // if message is empty, delete the corresponding attribute 296 if (message.CountNames(B_ANY_TYPE)) { 297 size_t size = (size_t)message.FlattenedSize(); 298 char *buffer = new char[size]; 299 message.Flatten(buffer, (ssize_t)size); 300 deskDir.WriteAttr(kAttrOpenWindows, B_MESSAGE_TYPE, 0, buffer, size); 301 delete [] buffer; 302 } else 303 deskDir.RemoveAttr(kAttrOpenWindows); 304 } 305 306 for (int32 count = 0; count < 50; count++) { 307 // wait 5 seconds for the copiing/moving to quit 308 if (gStatusWindow->AttemptToQuit()) 309 break; 310 311 snooze(100000); 312 } 313 314 return _inherited::QuitRequested(); 315 } 316 317 318 void 319 TTracker::Quit() 320 { 321 TrackerSettings().SaveSettings(false); 322 323 fClipboardRefsWatcher->Lock(); 324 fClipboardRefsWatcher->Quit(); 325 326 fTrashWatcher->Lock(); 327 fTrashWatcher->Quit(); 328 329 WellKnowEntryList::Quit(); 330 331 delete gPreloader; 332 delete fTaskLoop; 333 delete IconCache::sIconCache; 334 335 _inherited::Quit(); 336 } 337 338 339 void 340 TTracker::MessageReceived(BMessage *message) 341 { 342 if (HandleScriptingMessage(message)) 343 return; 344 345 switch (message->what) { 346 case kGetInfo: 347 OpenInfoWindows(message); 348 break; 349 350 case kMoveToTrash: 351 MoveRefsToTrash(message); 352 break; 353 354 case kCloseWindowAndChildren: 355 { 356 const node_ref *itemNode; 357 int32 bytes; 358 message->FindData("node_ref", B_RAW_TYPE, 359 (const void **)&itemNode, &bytes); 360 CloseWindowAndChildren(itemNode); 361 break; 362 } 363 364 case kCloseAllWindows: 365 CloseAllWindows(); 366 break; 367 368 case kCloseAllInWorkspace: 369 CloseAllInWorkspace(); 370 break; 371 372 case kFindButton: 373 (new FindWindow())->Show(); 374 break; 375 376 case kEditQuery: 377 EditQueries(message); 378 break; 379 380 case kShowSplash: 381 run_be_about(); 382 break; 383 384 case kAddPrinter: 385 // show the addprinter window 386 run_add_printer_panel(); 387 break; 388 389 case kMakeActivePrinter: 390 // get the current selection 391 SetDefaultPrinter(message); 392 break; 393 394 #ifdef MOUNT_MENU_IN_DESKBAR 395 396 case 'gmtv': 397 { 398 // Someone (probably the deskbar) has requested a list of 399 // mountable volumes. 400 BMessage reply; 401 AutoMounterLoop()->EachMountableItemAndFloppy(&AddMountableItemToMessage, 402 &reply); 403 message->SendReply(&reply); 404 break; 405 } 406 407 #endif 408 409 case kUnmountVolume: 410 // When the user attempts to unmount a volume from the mount 411 // context menu, this is where the message gets received. 412 // Save pose locations and forward this to the automounter 413 SaveAllPoseLocations(); 414 // Fall through... 415 case kMountVolume: 416 case kMountAllNow: 417 MountServer().SendMessage(message); 418 break; 419 420 case kRunAutomounterSettings: 421 AutomountSettingsDialog::RunAutomountSettings(MountServer()); 422 break; 423 424 case kRestoreBackgroundImage: 425 { 426 BDeskWindow *desktop = GetDeskWindow(); 427 AutoLock<BWindow> lock(desktop); 428 desktop->UpdateDesktopBackgroundImages(); 429 break; 430 } 431 432 case kShowSettingsWindow: 433 ShowSettingsWindow(); 434 break; 435 436 case kFavoriteCountChangedExternally: 437 SendNotices(kFavoriteCountChangedExternally, message); 438 break; 439 440 case kStartWatchClipboardRefs: 441 { 442 BMessenger messenger; 443 message->FindMessenger("target", &messenger); 444 if (messenger.IsValid()) 445 fClipboardRefsWatcher->AddToNotifyList(messenger); 446 break; 447 } 448 449 case kStopWatchClipboardRefs: 450 { 451 BMessenger messenger; 452 message->FindMessenger("target", &messenger); 453 if (messenger.IsValid()) 454 fClipboardRefsWatcher->RemoveFromNotifyList(messenger); 455 break; 456 } 457 458 case kFSClipboardChanges: 459 fClipboardRefsWatcher->UpdatePoseViews(message); 460 break; 461 462 case kShowVolumeSpaceBar: 463 case kSpaceBarColorChanged: 464 gPeriodicUpdatePoses.DoPeriodicUpdate(true); 465 break; 466 467 default: 468 _inherited::MessageReceived(message); 469 break; 470 } 471 } 472 473 474 void 475 TTracker::Pulse() 476 { 477 if (!TrackerSettings().ShowVolumeSpaceBar()) 478 return; 479 480 // update the volume icon's free space bars 481 gPeriodicUpdatePoses.DoPeriodicUpdate(false); 482 } 483 484 485 void 486 TTracker::SetDefaultPrinter(const BMessage *message) 487 { 488 // get the first item selected 489 int32 count = 0; 490 uint32 type = 0; 491 message->GetInfo("refs", &type, &count); 492 493 if (count <= 0) 494 return; 495 496 // will make the first item the default printer, disregards any other files 497 entry_ref ref; 498 ASSERT(message->FindRef("refs", 0, &ref) == B_OK); 499 if (message->FindRef("refs", 0, &ref) != B_OK) 500 return; 501 502 #if B_BEOS_VERSION_DANO 503 set_default_printer(ref.name); 504 #else 505 // create a message for the print server 506 BMessenger messenger("application/x-vnd.Be-PSRV", -1); 507 if (!messenger.IsValid()) 508 return; 509 510 // send the selection to the print server 511 BMessage makeActiveMessage(PSV_MAKE_PRINTER_ACTIVE_QUIETLY); 512 makeActiveMessage.AddString("printer", ref.name); 513 514 BMessage reply; 515 messenger.SendMessage(&makeActiveMessage, &reply); 516 #endif 517 } 518 519 520 void 521 TTracker::MoveRefsToTrash(const BMessage *message) 522 { 523 int32 count; 524 uint32 type; 525 message->GetInfo("refs", &type, &count); 526 527 if (count <= 0) 528 return; 529 530 BObjectList<entry_ref> *srcList = new BObjectList<entry_ref>(count, true); 531 532 for (int32 index = 0; index < count; index++) { 533 534 entry_ref ref; 535 ASSERT(message->FindRef("refs", index, &ref) == B_OK); 536 if (message->FindRef("refs", index, &ref) != B_OK) 537 continue; 538 539 AutoLock<WindowList> lock(&fWindowList); 540 BContainerWindow *window = FindParentContainerWindow(&ref); 541 if (window) 542 // if we have a window open for this entry, ask the pose to 543 // delete it, this will select the next entry 544 window->PoseView()->MoveEntryToTrash(&ref); 545 else 546 // add all others to a list that gets deleted separately 547 srcList->AddItem(new entry_ref(ref)); 548 } 549 550 if (srcList->CountItems()) 551 // async move to trash 552 FSMoveToTrash(srcList); 553 } 554 555 556 template <class T, class FT> 557 class EntryAndNodeDoSoonWithMessageFunctor : public FunctionObjectWithResult<bool> { 558 public: 559 EntryAndNodeDoSoonWithMessageFunctor(FT func, T *target, const entry_ref *child, 560 const node_ref *parent, const BMessage *message) 561 : fFunc(func), 562 fTarget(target), 563 fNode(*parent), 564 fEntry(*child) 565 { 566 fSendMessage = (message != NULL); 567 if (message) 568 fMessage = *message; 569 } 570 571 virtual ~EntryAndNodeDoSoonWithMessageFunctor() {} 572 virtual void operator()() 573 { result = (fTarget->*fFunc)(&fEntry, &fNode, fSendMessage ? &fMessage : NULL); } 574 575 protected: 576 FT fFunc; 577 T *fTarget; 578 node_ref fNode; 579 entry_ref fEntry; 580 BMessage fMessage; 581 bool fSendMessage; 582 }; 583 584 585 bool 586 TTracker::LaunchAndCloseParentIfOK(const entry_ref *launchThis, 587 const node_ref *closeThis, const BMessage *messageToBundle) 588 { 589 BMessage refsReceived(B_REFS_RECEIVED); 590 if (messageToBundle) { 591 refsReceived = *messageToBundle; 592 refsReceived.what = B_REFS_RECEIVED; 593 } 594 refsReceived.AddRef("refs", launchThis); 595 // synchronous launch, we are already in our own thread 596 if (TrackerLaunch(&refsReceived, false) == B_OK) { 597 // if launched fine, close parent window in a bit 598 fTaskLoop->RunLater(NewMemberFunctionObject(&TTracker::CloseParent, this, *closeThis), 599 1000000); 600 } 601 return false; 602 } 603 604 605 status_t 606 TTracker::OpenRef(const entry_ref *ref, const node_ref *nodeToClose, 607 const node_ref *nodeToSelect, OpenSelector selector, 608 const BMessage *messageToBundle) 609 { 610 Model *model = NULL; 611 BEntry entry(ref, true); 612 status_t result = entry.InitCheck(); 613 614 bool brokenLinkWithSpecificHandler = false; 615 BString brokenLinkPreferredApp; 616 617 if (result != B_OK) { 618 model = new Model(ref, false); 619 if (model->IsSymLink() && !model->LinkTo()) { 620 model->GetPreferredAppForBrokenSymLink(brokenLinkPreferredApp); 621 if (brokenLinkPreferredApp.Length() && brokenLinkPreferredApp != kTrackerSignature) 622 brokenLinkWithSpecificHandler = true; 623 } 624 625 if (!brokenLinkWithSpecificHandler) { 626 delete model; 627 BAlert *alert = new BAlert("", 628 "There was an error resolving the link.", 629 "Cancel", 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 630 alert->SetShortcut(0, B_ESCAPE); 631 alert->Go(); 632 return result; 633 } 634 } else 635 model = new Model(&entry); 636 637 result = model->InitCheck(); 638 if (result != B_OK) { 639 delete model; 640 return result; 641 } 642 643 bool openAsContainer = model->IsContainer(); 644 645 if (openAsContainer && selector != kOpenWith) { 646 // if folder or query has a preferred handler and it's not the 647 // Tracker, open it by sending refs to the handling app 648 649 // if we are responding to the final open of OpenWith, just 650 // skip this and proceed to opening the container with Tracker 651 model->OpenNode(); 652 BNodeInfo nodeInfo(model->Node()); 653 char preferredApp[B_MIME_TYPE_LENGTH]; 654 if (nodeInfo.GetPreferredApp(preferredApp) == B_OK 655 && strcasecmp(preferredApp, kTrackerSignature) != 0) 656 openAsContainer = false; 657 model->CloseNode(); 658 } 659 660 if (openAsContainer || selector == kRunOpenWithWindow) { 661 // special case opening plain folders, queries or using open with 662 OpenContainerWindow(model, 0, selector, kRestoreDecor); // window adopts model 663 if (nodeToClose) 664 CloseParentWaitingForChildSoon(ref, nodeToClose); 665 } else if (model->IsQueryTemplate()) { 666 // query template - open new find window 667 (new FindWindow(model->EntryRef()))->Show(); 668 if (nodeToClose) 669 CloseParentWaitingForChildSoon(ref, nodeToClose); 670 } else { 671 delete model; 672 // run Launch in a separate thread 673 // and close parent if successfull 674 if (nodeToClose) 675 Thread::Launch(new EntryAndNodeDoSoonWithMessageFunctor<TTracker, 676 bool (TTracker::*)(const entry_ref *, const node_ref *, 677 const BMessage *)>(&TTracker::LaunchAndCloseParentIfOK, this, 678 ref, nodeToClose, messageToBundle)); 679 else { 680 BMessage refsReceived(B_REFS_RECEIVED); 681 if (messageToBundle) { 682 refsReceived = *messageToBundle; 683 refsReceived.what = B_REFS_RECEIVED; 684 } 685 refsReceived.AddRef("refs", ref); 686 if (brokenLinkWithSpecificHandler) 687 // This cruft is to support a hacky workaround for double-clicking 688 // broken refs for cifs; should get fixed in R5 689 LaunchBrokenLink(brokenLinkPreferredApp.String(), &refsReceived); 690 else 691 TrackerLaunch(&refsReceived, true); 692 } 693 } 694 if (nodeToSelect) 695 SelectChildInParentSoon(ref, nodeToSelect); 696 697 return B_OK; 698 } 699 700 701 void 702 TTracker::RefsReceived(BMessage *message) 703 { 704 OpenSelector selector = kOpen; 705 if (message->HasInt32("launchUsingSelector")) 706 selector = kRunOpenWithWindow; 707 708 entry_ref handlingApp; 709 if (message->FindRef("handler", &handlingApp) == B_OK) 710 selector = kOpenWith; 711 712 int32 count; 713 uint32 type; 714 message->GetInfo("refs", &type, &count); 715 716 switch (selector) { 717 case kRunOpenWithWindow: 718 OpenContainerWindow(0, message, selector); 719 // window adopts model 720 break; 721 722 case kOpenWith: 723 { 724 // Open With resulted in passing refs and a handler, open the files 725 // with the handling app 726 message->RemoveName("handler"); 727 728 // have to find out if handling app is the Tracker 729 // if it is, just pass it to the active Tracker, no matter which Tracker 730 // was chosen to handle the refs 731 char signature[B_MIME_TYPE_LENGTH]; 732 signature[0] = '\0'; 733 { 734 BFile handlingNode(&handlingApp, O_RDONLY); 735 BAppFileInfo appInfo(&handlingNode); 736 appInfo.GetSignature(signature); 737 } 738 739 if (strcasecmp(signature, kTrackerSignature) != 0) { 740 // handling app not Tracker, pass entries to the apps RefsReceived 741 TrackerLaunch(&handlingApp, message, true); 742 break; 743 } 744 // fall thru, opening refs by the Tracker, as if they were double clicked 745 } 746 747 case kOpen: 748 { 749 // copy over "Poses" messenger so that refs received recipients know 750 // where the open came from 751 BMessage *bundleThis = NULL; 752 BMessenger messenger; 753 if (message->FindMessenger("TrackerViewToken", &messenger) == B_OK) { 754 bundleThis = new BMessage(); 755 bundleThis->AddMessenger("TrackerViewToken", messenger); 756 } 757 758 for (int32 index = 0; index < count; index++) { 759 entry_ref ref; 760 message->FindRef("refs", index, &ref); 761 762 const node_ref *nodeToClose = NULL; 763 const node_ref *nodeToSelect = NULL; 764 ssize_t numBytes; 765 766 message->FindData("nodeRefsToClose", B_RAW_TYPE, index, 767 (const void **)&nodeToClose, &numBytes); 768 message->FindData("nodeRefToSelect", B_RAW_TYPE, index, 769 (const void **)&nodeToSelect, &numBytes); 770 771 OpenRef(&ref, nodeToClose, nodeToSelect, selector, bundleThis); 772 } 773 774 delete bundleThis; 775 break; 776 } 777 } 778 } 779 780 781 void 782 TTracker::ArgvReceived(int32 argc, char **argv) 783 { 784 BMessage *message = CurrentMessage(); 785 const char *currentWorkingDirectoryPath = NULL; 786 entry_ref ref; 787 788 if (message->FindString("cwd", ¤tWorkingDirectoryPath) == B_OK) { 789 BDirectory workingDirectory(currentWorkingDirectoryPath); 790 for (int32 index = 1; index < argc; index++) { 791 BEntry entry; 792 if (entry.SetTo(&workingDirectory, argv[index]) == B_OK 793 && entry.GetRef(&ref) == B_OK) 794 OpenRef(&ref); 795 else if (get_ref_for_path(argv[index], &ref) == B_OK) 796 OpenRef(&ref); 797 } 798 } 799 } 800 801 void 802 TTracker::OpenContainerWindow(Model *model, BMessage *originalRefsList, 803 OpenSelector openSelector, uint32 openFlags, bool checkAlreadyOpen, 804 const BMessage *stateMessage) 805 { 806 AutoLock<WindowList> lock(&fWindowList); 807 BContainerWindow *window = NULL; 808 if (checkAlreadyOpen && openSelector != kRunOpenWithWindow) 809 // find out if window already open 810 window = FindContainerWindow(model->NodeRef()); 811 812 bool someWindowActivated = false; 813 814 uint32 workspace = (uint32)(1 << current_workspace()); 815 int32 windowCount = 0; 816 817 while (window) { 818 // At least one window open, just pull to front 819 // make sure we don't jerk workspaces around 820 uint32 windowWorkspaces = window->Workspaces(); 821 if (windowWorkspaces & workspace) { 822 window->Activate(); 823 someWindowActivated = true; 824 } 825 window = FindContainerWindow(model->NodeRef(), ++windowCount); 826 } 827 828 if (someWindowActivated) { 829 delete model; 830 return; 831 } // If no window was actiated, (none in the current workspace 832 // we open a new one. 833 834 if (openSelector == kRunOpenWithWindow) { 835 BMessage *refList = NULL; 836 if (!originalRefsList) { 837 // when passing just a single model, stuff it's entry in a single 838 // element list anyway 839 ASSERT(model); 840 refList = new BMessage; 841 refList->AddRef("refs", model->EntryRef()); 842 delete model; 843 model = NULL; 844 } else 845 // clone the message, window adopts it for it's own use 846 refList = new BMessage(*originalRefsList); 847 window = new OpenWithContainerWindow(refList, &fWindowList); 848 } else if (model->IsRoot()) { 849 // window will adopt the model 850 window = new BVolumeWindow(&fWindowList, openFlags); 851 } else if (model->IsQuery()) { 852 // window will adopt the model 853 window = new BQueryContainerWindow(&fWindowList, openFlags); 854 } else 855 // window will adopt the model 856 window = new BContainerWindow(&fWindowList, openFlags); 857 858 if (model) 859 window->CreatePoseView(model); 860 861 BMessage restoreStateMessage(kRestoreState); 862 863 if (stateMessage) 864 restoreStateMessage.AddMessage("state", stateMessage); 865 866 window->PostMessage(&restoreStateMessage); 867 } 868 869 870 void 871 TTracker::EditQueries(const BMessage *message) 872 { 873 bool editOnlyIfTemplate; 874 if (message->FindBool("editQueryOnPose", &editOnlyIfTemplate) != B_OK) 875 editOnlyIfTemplate = false; 876 877 type_code type; 878 int32 count; 879 message->GetInfo("refs", &type, &count); 880 for (int32 index = 0; index < count; index++) { 881 entry_ref ref; 882 message->FindRef("refs", index, &ref); 883 BEntry entry(&ref, true); 884 if (entry.InitCheck() == B_OK && entry.Exists()) 885 (new FindWindow(&ref, editOnlyIfTemplate))->Show(); 886 } 887 } 888 889 890 void 891 TTracker::OpenInfoWindows(BMessage *message) 892 { 893 type_code type; 894 int32 count; 895 message->GetInfo("refs", &type, &count); 896 897 for (int32 index = 0; index < count; index++) { 898 entry_ref ref; 899 message->FindRef("refs", index, &ref); 900 BEntry entry; 901 if (entry.SetTo(&ref) == B_OK) { 902 Model *model = new Model(&entry); 903 if (model->InitCheck() != B_OK) { 904 delete model; 905 continue; 906 } 907 908 AutoLock<WindowList> lock(&fWindowList); 909 BInfoWindow *wind = FindInfoWindow(model->NodeRef()); 910 911 if (wind) { 912 wind->Activate(); 913 delete model; 914 } else { 915 wind = new BInfoWindow(model, index, &fWindowList); 916 wind->PostMessage(kRestoreState); 917 } 918 } 919 } 920 } 921 922 923 BDeskWindow * 924 TTracker::GetDeskWindow() const 925 { 926 int32 count = fWindowList.CountItems(); 927 for (int32 index = 0; index < count; index++) { 928 BDeskWindow *window = dynamic_cast<BDeskWindow *> 929 (fWindowList.ItemAt(index)); 930 931 if (window) 932 return window; 933 } 934 TRESPASS(); 935 return NULL; 936 } 937 938 939 BContainerWindow * 940 TTracker::FindContainerWindow(const node_ref *node, int32 number) const 941 { 942 ASSERT(fWindowList.IsLocked()); 943 944 int32 count = fWindowList.CountItems(); 945 946 int32 windowsFound = 0; 947 948 for (int32 index = 0; index < count; index++) { 949 BContainerWindow *window = dynamic_cast<BContainerWindow *> 950 (fWindowList.ItemAt(index)); 951 952 if (window && window->IsShowing(node) && number == windowsFound++) 953 return window; 954 } 955 return NULL; 956 } 957 958 959 BContainerWindow * 960 TTracker::FindContainerWindow(const entry_ref *entry, int32 number) const 961 { 962 ASSERT(fWindowList.IsLocked()); 963 964 int32 count = fWindowList.CountItems(); 965 966 int32 windowsFound = 0; 967 968 for (int32 index = 0; index < count; index++) { 969 BContainerWindow *window = dynamic_cast<BContainerWindow *> 970 (fWindowList.ItemAt(index)); 971 972 if (window && window->IsShowing(entry) && number == windowsFound++) 973 return window; 974 } 975 return NULL; 976 } 977 978 979 bool 980 TTracker::EntryHasWindowOpen(const entry_ref *entry) 981 { 982 AutoLock<WindowList> lock(&fWindowList); 983 return FindContainerWindow(entry) != NULL; 984 } 985 986 987 BContainerWindow * 988 TTracker::FindParentContainerWindow(const entry_ref *ref) const 989 { 990 BEntry entry(ref); 991 BEntry parent; 992 993 if (entry.GetParent(&parent) != B_OK) 994 return NULL; 995 996 entry_ref parentRef; 997 parent.GetRef(&parentRef); 998 999 ASSERT(fWindowList.IsLocked()); 1000 1001 int32 count = fWindowList.CountItems(); 1002 for (int32 index = 0; index < count; index++) { 1003 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1004 (fWindowList.ItemAt(index)); 1005 if (window && window->IsShowing(&parentRef)) 1006 return window; 1007 } 1008 return NULL; 1009 } 1010 1011 1012 BInfoWindow * 1013 TTracker::FindInfoWindow(const node_ref* node) const 1014 { 1015 ASSERT(fWindowList.IsLocked()); 1016 1017 int32 count = fWindowList.CountItems(); 1018 for (int32 index = 0; index < count; index++) { 1019 BInfoWindow *window = dynamic_cast<BInfoWindow *> 1020 (fWindowList.ItemAt(index)); 1021 if (window && window->IsShowing(node)) 1022 return window; 1023 } 1024 return NULL; 1025 } 1026 1027 1028 bool 1029 TTracker::QueryActiveForDevice(dev_t device) 1030 { 1031 AutoLock<WindowList> lock(&fWindowList); 1032 int32 count = fWindowList.CountItems(); 1033 for (int32 index = 0; index < count; index++) { 1034 BQueryContainerWindow *window = dynamic_cast<BQueryContainerWindow *> 1035 (fWindowList.ItemAt(index)); 1036 if (window) { 1037 AutoLock<BWindow> lock(window); 1038 if (window->ActiveOnDevice(device)) 1039 return true; 1040 } 1041 } 1042 return false; 1043 } 1044 1045 1046 void 1047 TTracker::CloseActiveQueryWindows(dev_t device) 1048 { 1049 // used when trying to unmount a volume - an active query would prevent that from 1050 // happening 1051 bool closed = false; 1052 AutoLock<WindowList> lock(fWindowList); 1053 for (int32 index = fWindowList.CountItems(); index >= 0; index--) { 1054 BQueryContainerWindow *window = dynamic_cast<BQueryContainerWindow *> 1055 (fWindowList.ItemAt(index)); 1056 if (window) { 1057 AutoLock<BWindow> lock(window); 1058 if (window->ActiveOnDevice(device)) { 1059 window->PostMessage(B_QUIT_REQUESTED); 1060 closed = true; 1061 } 1062 } 1063 } 1064 lock.Unlock(); 1065 if (closed) 1066 for (int32 timeout = 30; timeout; timeout--) { 1067 // wait a bit for windows to fully close 1068 if (!QueryActiveForDevice(device)) 1069 return; 1070 snooze(100000); 1071 } 1072 } 1073 1074 1075 void 1076 TTracker::SaveAllPoseLocations() 1077 { 1078 int32 numWindows = fWindowList.CountItems(); 1079 for (int32 windowIndex = 0; windowIndex < numWindows; windowIndex++) { 1080 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1081 (fWindowList.ItemAt(windowIndex)); 1082 1083 if (window) { 1084 AutoLock<BWindow> lock(window); 1085 BDeskWindow *deskWindow = dynamic_cast<BDeskWindow *>(window); 1086 1087 if (deskWindow) 1088 deskWindow->SaveDesktopPoseLocations(); 1089 else 1090 window->PoseView()->SavePoseLocations(); 1091 } 1092 } 1093 } 1094 1095 1096 void 1097 TTracker::CloseWindowAndChildren(const node_ref *node) 1098 { 1099 BDirectory dir(node); 1100 if (dir.InitCheck() != B_OK) 1101 return; 1102 1103 AutoLock<WindowList> lock(&fWindowList); 1104 BObjectList<BContainerWindow> closeList; 1105 1106 // make a list of all windows to be closed 1107 // count from end to beginning so we can remove items safely 1108 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1109 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1110 (fWindowList.ItemAt(index)); 1111 if (window && window->TargetModel()) { 1112 BEntry wind_entry; 1113 wind_entry.SetTo(window->TargetModel()->EntryRef()); 1114 1115 if ((*window->TargetModel()->NodeRef() == *node) 1116 || dir.Contains(&wind_entry)) { 1117 1118 // ToDo: 1119 // get rid of the Remove here, BContainerWindow::Quit does it 1120 fWindowList.RemoveItemAt(index); 1121 closeList.AddItem(window); 1122 } 1123 } 1124 } 1125 1126 // now really close the windows 1127 int32 numItems = closeList.CountItems(); 1128 for (int32 index = 0; index < numItems; index++) { 1129 BContainerWindow *window = closeList.ItemAt(index); 1130 window->PostMessage(B_QUIT_REQUESTED); 1131 } 1132 } 1133 1134 1135 void 1136 TTracker::CloseAllInWorkspace() 1137 { 1138 AutoLock<WindowList> lock(&fWindowList); 1139 1140 int32 currentWorkspace = 1 << current_workspace(); 1141 // count from end to beginning so we can remove items safely 1142 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1143 BWindow *window = fWindowList.ItemAt(index); 1144 if (window->Workspaces() & currentWorkspace) 1145 // avoid the desktop 1146 if (!dynamic_cast<BDeskWindow *>(window) 1147 && !dynamic_cast<BStatusWindow *>(window)) 1148 window->PostMessage(B_QUIT_REQUESTED); 1149 } 1150 } 1151 1152 1153 void 1154 TTracker::CloseAllWindows() 1155 { 1156 // this is a response to the DeskBar sending us a B_QUIT, when it really 1157 // means to say close all your windows. It might be better to have it 1158 // send a kCloseAllWindows message and have windowless apps stay running, 1159 // which is what we will do for the Tracker 1160 AutoLock<WindowList> lock(&fWindowList); 1161 1162 int32 count = CountWindows(); 1163 for (int32 index = 0; index < count; index++) { 1164 BWindow *window = WindowAt(index); 1165 // avoid the desktop 1166 if (!dynamic_cast<BDeskWindow *>(window) 1167 && !dynamic_cast<BStatusWindow *>(window)) 1168 window->PostMessage(B_QUIT_REQUESTED); 1169 } 1170 // count from end to beginning so we can remove items safely 1171 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1172 BWindow *window = fWindowList.ItemAt(index); 1173 if (!dynamic_cast<BDeskWindow *>(window) 1174 && !dynamic_cast<BStatusWindow *>(window)) 1175 // ToDo: 1176 // get rid of the Remove here, BContainerWindow::Quit does it 1177 fWindowList.RemoveItemAt(index); 1178 } 1179 } 1180 1181 1182 void 1183 TTracker::_OpenPreviouslyOpenedWindows(const char* pathFilter) 1184 { 1185 size_t filterLength = 0; 1186 if (pathFilter != NULL) 1187 filterLength = strlen(pathFilter); 1188 1189 BDirectory deskDir; 1190 attr_info attrInfo; 1191 if (FSGetDeskDir(&deskDir) != B_OK 1192 || deskDir.GetAttrInfo(kAttrOpenWindows, &attrInfo) != B_OK) 1193 return; 1194 1195 char *buffer = (char *)malloc((size_t)attrInfo.size); 1196 BMessage message; 1197 if (deskDir.ReadAttr(kAttrOpenWindows, B_MESSAGE_TYPE, 0, buffer, 1198 (size_t)attrInfo.size) != attrInfo.size 1199 || message.Unflatten(buffer) != B_OK) { 1200 free(buffer); 1201 return; 1202 } 1203 1204 free(buffer); 1205 1206 node_ref nodeRef; 1207 deskDir.GetNodeRef(&nodeRef); 1208 1209 int32 stateMessageCounter = 0; 1210 const char *path; 1211 for (int32 i = 0; message.FindString("paths", i, &path) == B_OK; i++) { 1212 if (strncmp(path, pathFilter, filterLength)) 1213 continue; 1214 1215 BEntry entry(path, true); 1216 if (entry.InitCheck() != B_OK) 1217 continue; 1218 1219 int8 flags = 0; 1220 for (int32 j = 0; message.FindInt8(path, j, &flags) == B_OK; j++) { 1221 Model *model = new Model(&entry); 1222 if (model->InitCheck() == B_OK && model->IsContainer()) { 1223 BMessage state; 1224 bool restoreStateFromMessage = false; 1225 if ((flags & kOpenWindowHasState) != 0 1226 && message.FindMessage("window state", stateMessageCounter++, 1227 &state) == B_OK) 1228 restoreStateFromMessage = true; 1229 1230 if (restoreStateFromMessage) { 1231 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1232 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1233 | kRestoreDecor, false, &state); 1234 } else { 1235 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1236 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1237 | kRestoreDecor); 1238 } 1239 } else 1240 delete model; 1241 } 1242 } 1243 1244 // Open disks window if needed 1245 1246 if (pathFilter == NULL && TrackerSettings().ShowDisksIcon() 1247 && message.HasBool("open_disks_window")) { 1248 BEntry entry("/"); 1249 Model* model = new Model(&entry); 1250 if (model->InitCheck() == B_OK) 1251 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace); 1252 else 1253 delete model; 1254 } 1255 } 1256 1257 1258 void 1259 TTracker::ReadyToRun() 1260 { 1261 gStatusWindow = new BStatusWindow(); 1262 InitMimeTypes(); 1263 InstallDefaultTemplates(); 1264 InstallIndices(); 1265 InstallTemporaryBackgroundImages(); 1266 1267 fTrashWatcher = new BTrashWatcher(); 1268 fTrashWatcher->Run(); 1269 1270 fClipboardRefsWatcher = new BClipboardRefsWatcher(); 1271 fClipboardRefsWatcher->Run(); 1272 1273 fTaskLoop = new StandAloneTaskLoop(true); 1274 1275 // open desktop window 1276 BContainerWindow *deskWindow = NULL; 1277 BDirectory deskDir; 1278 if (FSGetDeskDir(&deskDir) == B_OK) { 1279 // create desktop 1280 BEntry entry; 1281 deskDir.GetEntry(&entry); 1282 Model *model = new Model(&entry, true); 1283 if (model->InitCheck() == B_OK) { 1284 AutoLock<WindowList> lock(&fWindowList); 1285 deskWindow = new BDeskWindow(&fWindowList); 1286 AutoLock<BWindow> windowLock(deskWindow); 1287 deskWindow->CreatePoseView(model); 1288 deskWindow->Init(); 1289 1290 if (TrackerSettings().ShowDisksIcon()) { 1291 // create model for root of everything 1292 BEntry entry("/"); 1293 Model model(&entry); 1294 if (model.InitCheck() == B_OK) { 1295 // add the root icon to desktop window 1296 BMessage message; 1297 message.what = B_NODE_MONITOR; 1298 message.AddInt32("opcode", B_ENTRY_CREATED); 1299 message.AddInt32("device", model.NodeRef()->device); 1300 message.AddInt64("node", model.NodeRef()->node); 1301 message.AddInt64("directory", model.EntryRef()->directory); 1302 message.AddString("name", model.EntryRef()->name); 1303 deskWindow->PostMessage(&message, deskWindow->PoseView()); 1304 } 1305 } 1306 } else 1307 delete model; 1308 } 1309 1310 // kick off building the mime type list for find panels, etc. 1311 fMimeTypeList = new MimeTypeList(); 1312 1313 if (!BootedInSafeMode()) { 1314 // kick of transient query killer 1315 DeleteTransientQueriesTask::StartUpTransientQueryCleaner(); 1316 // the mount_server will have mounted the previous volumes already. 1317 _OpenPreviouslyOpenedWindows(); 1318 } 1319 } 1320 1321 MimeTypeList * 1322 TTracker::MimeTypes() const 1323 { 1324 return fMimeTypeList; 1325 } 1326 1327 void 1328 TTracker::SelectChildInParentSoon(const entry_ref *parent, 1329 const node_ref *child) 1330 { 1331 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1332 (&TTracker::SelectChildInParent, this, parent, child), 1333 100000, 200000, 5000000); 1334 } 1335 1336 void 1337 TTracker::CloseParentWaitingForChildSoon(const entry_ref *child, 1338 const node_ref *parent) 1339 { 1340 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1341 (&TTracker::CloseParentWaitingForChild, this, child, parent), 1342 200000, 100000, 5000000); 1343 } 1344 1345 void 1346 TTracker::SelectPoseAtLocationSoon(node_ref parent, BPoint pointInPose) 1347 { 1348 fTaskLoop->RunLater(NewMemberFunctionObject 1349 (&TTracker::SelectPoseAtLocationInParent, this, parent, pointInPose), 1350 100000); 1351 } 1352 1353 void 1354 TTracker::SelectPoseAtLocationInParent(node_ref parent, BPoint pointInPose) 1355 { 1356 AutoLock<WindowList> lock(&fWindowList); 1357 BContainerWindow *parentWindow = FindContainerWindow(&parent); 1358 if (parentWindow) { 1359 AutoLock<BWindow> lock(parentWindow); 1360 parentWindow->PoseView()->SelectPoseAtLocation(pointInPose); 1361 } 1362 } 1363 1364 bool 1365 TTracker::CloseParentWaitingForChild(const entry_ref *child, 1366 const node_ref *parent) 1367 { 1368 AutoLock<WindowList> lock(&fWindowList); 1369 1370 BContainerWindow *parentWindow = FindContainerWindow(parent); 1371 if (!parentWindow) 1372 // parent window already closed, give up 1373 return true; 1374 1375 // If child is a symbolic link, dereference it, so that 1376 // FindContainerWindow will succeed. 1377 BEntry entry(child, true); 1378 entry_ref resolvedChild; 1379 if (entry.GetRef(&resolvedChild) != B_OK) 1380 resolvedChild = *child; 1381 1382 BContainerWindow *window = FindContainerWindow(&resolvedChild); 1383 if (window) { 1384 AutoLock<BWindow> lock(window); 1385 if (!window->IsHidden()) 1386 return CloseParentWindowCommon(parentWindow); 1387 } 1388 return false; 1389 } 1390 1391 void 1392 TTracker::CloseParent(node_ref parent) 1393 { 1394 AutoLock<WindowList> lock(&fWindowList); 1395 if (!lock) 1396 return; 1397 1398 CloseParentWindowCommon(FindContainerWindow(&parent)); 1399 } 1400 1401 void 1402 TTracker::ShowSettingsWindow() 1403 { 1404 if (!fSettingsWindow) { 1405 fSettingsWindow = new TrackerSettingsWindow(); 1406 fSettingsWindow->Show(); 1407 } else { 1408 if (fSettingsWindow->Lock()) { 1409 if (fSettingsWindow->IsHidden()) 1410 fSettingsWindow->Show(); 1411 else 1412 fSettingsWindow->Activate(); 1413 fSettingsWindow->Unlock(); 1414 } 1415 } 1416 } 1417 1418 bool 1419 TTracker::CloseParentWindowCommon(BContainerWindow *window) 1420 { 1421 ASSERT(fWindowList.IsLocked()); 1422 1423 if (dynamic_cast<BDeskWindow *>(window)) 1424 // don't close the destop 1425 return false; 1426 1427 window->PostMessage(B_QUIT_REQUESTED); 1428 return true; 1429 } 1430 1431 bool 1432 TTracker::SelectChildInParent(const entry_ref *parent, const node_ref *child) 1433 { 1434 AutoLock<WindowList> lock(&fWindowList); 1435 1436 BContainerWindow *window = FindContainerWindow(parent); 1437 if (!window) 1438 // parent window already closed, give up 1439 return false; 1440 1441 AutoLock<BWindow> windowLock(window); 1442 1443 if (windowLock.IsLocked()) { 1444 BPoseView *view = window->PoseView(); 1445 int32 index; 1446 BPose *pose = view->FindPose(child, &index); 1447 if (pose) { 1448 view->SelectPose(pose, index); 1449 return true; 1450 } 1451 } 1452 return false; 1453 } 1454 1455 const int32 kNodeMonitorBumpValue = 512; 1456 1457 status_t 1458 TTracker::NeedMoreNodeMonitors() 1459 { 1460 fNodeMonitorCount += kNodeMonitorBumpValue; 1461 PRINT(("bumping nodeMonitorCount to %d\n", fNodeMonitorCount)); 1462 1463 struct rlimit rl; 1464 rl.rlim_cur = fNodeMonitorCount; 1465 rl.rlim_max = RLIM_SAVED_MAX; 1466 if (setrlimit(RLIMIT_NOVMON, &rl) < 0) { 1467 fNodeMonitorCount -= kNodeMonitorBumpValue; 1468 return errno; 1469 } 1470 return B_OK; 1471 1472 } 1473 1474 status_t 1475 TTracker::WatchNode(const node_ref *node, uint32 flags, 1476 BMessenger target) 1477 { 1478 status_t result = watch_node(node, flags, target); 1479 if (result == B_OK || result != B_NO_MEMORY) { 1480 // need to make sure this uses the same error value as 1481 // the node monitor code 1482 return result; 1483 } 1484 1485 PRINT(("failed to start monitoring, trying to allocate more " 1486 "node monitors\n")); 1487 1488 TTracker *tracker = dynamic_cast<TTracker *>(be_app); 1489 if (!tracker) { 1490 // we are the file panel only, just fail 1491 return result; 1492 } 1493 1494 result = tracker->NeedMoreNodeMonitors(); 1495 1496 if (result != B_OK) { 1497 PRINT(("failed to allocate more node monitors, %s\n", 1498 strerror(result))); 1499 return result; 1500 } 1501 1502 // try again, this time with more node monitors 1503 return watch_node(node, flags, target); 1504 } 1505 1506 1507 BMessenger 1508 TTracker::MountServer() const 1509 { 1510 return BMessenger(kMountServerSignature); 1511 } 1512 1513 1514 bool 1515 TTracker::InTrashNode(const entry_ref *node) const 1516 { 1517 return FSInTrashDir(node); 1518 } 1519 1520 1521 bool 1522 TTracker::TrashFull() const 1523 { 1524 return fTrashWatcher->CheckTrashDirs(); 1525 } 1526 1527 1528 bool 1529 TTracker::IsTrashNode(const node_ref *node) const 1530 { 1531 return fTrashWatcher->IsTrashNode(node); 1532 } 1533 1534