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