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