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