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_TRANSLATE_CONTEXT 209 #define B_TRANSLATE_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 if (srcList->CountItems()) 604 // async move to trash 605 FSMoveToTrash(srcList); 606 } 607 608 609 template <class T, class FT> 610 class EntryAndNodeDoSoonWithMessageFunctor : public FunctionObjectWithResult<bool> { 611 public: 612 EntryAndNodeDoSoonWithMessageFunctor(FT func, T *target, const entry_ref *child, 613 const node_ref *parent, const BMessage *message) 614 : fFunc(func), 615 fTarget(target), 616 fNode(*parent), 617 fEntry(*child) 618 { 619 fSendMessage = (message != NULL); 620 if (message) 621 fMessage = *message; 622 } 623 624 virtual ~EntryAndNodeDoSoonWithMessageFunctor() {} 625 virtual void operator()() 626 { result = (fTarget->*fFunc)(&fEntry, &fNode, fSendMessage ? &fMessage : NULL); } 627 628 protected: 629 FT fFunc; 630 T *fTarget; 631 node_ref fNode; 632 entry_ref fEntry; 633 BMessage fMessage; 634 bool fSendMessage; 635 }; 636 637 638 bool 639 TTracker::LaunchAndCloseParentIfOK(const entry_ref *launchThis, 640 const node_ref *closeThis, const BMessage *messageToBundle) 641 { 642 BMessage refsReceived(B_REFS_RECEIVED); 643 if (messageToBundle) { 644 refsReceived = *messageToBundle; 645 refsReceived.what = B_REFS_RECEIVED; 646 } 647 refsReceived.AddRef("refs", launchThis); 648 // synchronous launch, we are already in our own thread 649 if (TrackerLaunch(&refsReceived, false) == B_OK) { 650 // if launched fine, close parent window in a bit 651 fTaskLoop->RunLater(NewMemberFunctionObject(&TTracker::CloseParent, this, *closeThis), 652 1000000); 653 } 654 return false; 655 } 656 657 658 status_t 659 TTracker::OpenRef(const entry_ref *ref, const node_ref *nodeToClose, 660 const node_ref *nodeToSelect, OpenSelector selector, 661 const BMessage *messageToBundle) 662 { 663 Model *model = NULL; 664 BEntry entry(ref, true); 665 status_t result = entry.InitCheck(); 666 667 bool brokenLinkWithSpecificHandler = false; 668 BString brokenLinkPreferredApp; 669 670 if (result != B_OK) { 671 model = new Model(ref, false); 672 if (model->IsSymLink() && !model->LinkTo()) { 673 model->GetPreferredAppForBrokenSymLink(brokenLinkPreferredApp); 674 if (brokenLinkPreferredApp.Length() && brokenLinkPreferredApp != kTrackerSignature) 675 brokenLinkWithSpecificHandler = true; 676 } 677 678 if (!brokenLinkWithSpecificHandler) { 679 delete model; 680 BAlert* alert = new BAlert("", 681 B_TRANSLATE("There was an error resolving the link."), 682 B_TRANSLATE("Cancel"), 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 683 alert->SetShortcut(0, B_ESCAPE); 684 alert->Go(); 685 return result; 686 } 687 } else 688 model = new Model(&entry); 689 690 result = model->InitCheck(); 691 if (result != B_OK) { 692 delete model; 693 return result; 694 } 695 696 bool openAsContainer = model->IsContainer(); 697 698 if (openAsContainer && selector != kOpenWith) { 699 // if folder or query has a preferred handler and it's not the 700 // Tracker, open it by sending refs to the handling app 701 702 // if we are responding to the final open of OpenWith, just 703 // skip this and proceed to opening the container with Tracker 704 model->OpenNode(); 705 BNodeInfo nodeInfo(model->Node()); 706 char preferredApp[B_MIME_TYPE_LENGTH]; 707 if (nodeInfo.GetPreferredApp(preferredApp) == B_OK 708 && strcasecmp(preferredApp, kTrackerSignature) != 0) 709 openAsContainer = false; 710 model->CloseNode(); 711 } 712 713 if (openAsContainer || selector == kRunOpenWithWindow) { 714 // special case opening plain folders, queries or using open with 715 OpenContainerWindow(model, 0, selector, kRestoreDecor); // window adopts model 716 if (nodeToClose) 717 CloseParentWaitingForChildSoon(ref, nodeToClose); 718 } else if (model->IsQueryTemplate()) { 719 // query template - open new find window 720 (new FindWindow(model->EntryRef()))->Show(); 721 if (nodeToClose) 722 CloseParentWaitingForChildSoon(ref, nodeToClose); 723 } else { 724 delete model; 725 // run Launch in a separate thread 726 // and close parent if successfull 727 if (nodeToClose) 728 Thread::Launch(new EntryAndNodeDoSoonWithMessageFunctor<TTracker, 729 bool (TTracker::*)(const entry_ref *, const node_ref *, 730 const BMessage *)>(&TTracker::LaunchAndCloseParentIfOK, this, 731 ref, nodeToClose, messageToBundle)); 732 else { 733 BMessage refsReceived(B_REFS_RECEIVED); 734 if (messageToBundle) { 735 refsReceived = *messageToBundle; 736 refsReceived.what = B_REFS_RECEIVED; 737 } 738 refsReceived.AddRef("refs", ref); 739 if (brokenLinkWithSpecificHandler) 740 // This cruft is to support a hacky workaround for double-clicking 741 // broken refs for cifs; should get fixed in R5 742 LaunchBrokenLink(brokenLinkPreferredApp.String(), &refsReceived); 743 else 744 TrackerLaunch(&refsReceived, true); 745 } 746 } 747 if (nodeToSelect) 748 SelectChildInParentSoon(ref, nodeToSelect); 749 750 return B_OK; 751 } 752 753 754 void 755 TTracker::RefsReceived(BMessage *message) 756 { 757 OpenSelector selector = kOpen; 758 if (message->HasInt32("launchUsingSelector")) 759 selector = kRunOpenWithWindow; 760 761 entry_ref handlingApp; 762 if (message->FindRef("handler", &handlingApp) == B_OK) 763 selector = kOpenWith; 764 765 int32 count; 766 uint32 type; 767 message->GetInfo("refs", &type, &count); 768 769 switch (selector) { 770 case kRunOpenWithWindow: 771 OpenContainerWindow(0, message, selector); 772 // window adopts model 773 break; 774 775 case kOpenWith: 776 { 777 // Open With resulted in passing refs and a handler, open the files 778 // with the handling app 779 message->RemoveName("handler"); 780 781 // have to find out if handling app is the Tracker 782 // if it is, just pass it to the active Tracker, no matter which Tracker 783 // was chosen to handle the refs 784 char signature[B_MIME_TYPE_LENGTH]; 785 signature[0] = '\0'; 786 { 787 BFile handlingNode(&handlingApp, O_RDONLY); 788 BAppFileInfo appInfo(&handlingNode); 789 appInfo.GetSignature(signature); 790 } 791 792 if (strcasecmp(signature, kTrackerSignature) != 0) { 793 // handling app not Tracker, pass entries to the apps RefsReceived 794 TrackerLaunch(&handlingApp, message, true); 795 break; 796 } 797 // fall thru, opening refs by the Tracker, as if they were double clicked 798 } 799 800 case kOpen: 801 { 802 // copy over "Poses" messenger so that refs received recipients know 803 // where the open came from 804 BMessage *bundleThis = NULL; 805 BMessenger messenger; 806 if (message->FindMessenger("TrackerViewToken", &messenger) == B_OK) { 807 bundleThis = new BMessage(); 808 bundleThis->AddMessenger("TrackerViewToken", messenger); 809 } 810 811 for (int32 index = 0; index < count; index++) { 812 entry_ref ref; 813 message->FindRef("refs", index, &ref); 814 815 const node_ref *nodeToClose = NULL; 816 const node_ref *nodeToSelect = NULL; 817 ssize_t numBytes; 818 819 message->FindData("nodeRefsToClose", B_RAW_TYPE, index, 820 (const void **)&nodeToClose, &numBytes); 821 message->FindData("nodeRefToSelect", B_RAW_TYPE, index, 822 (const void **)&nodeToSelect, &numBytes); 823 824 OpenRef(&ref, nodeToClose, nodeToSelect, selector, bundleThis); 825 } 826 827 delete bundleThis; 828 break; 829 } 830 } 831 } 832 833 834 void 835 TTracker::ArgvReceived(int32 argc, char **argv) 836 { 837 BMessage *message = CurrentMessage(); 838 const char *currentWorkingDirectoryPath = NULL; 839 entry_ref ref; 840 841 if (message->FindString("cwd", ¤tWorkingDirectoryPath) == B_OK) { 842 BDirectory workingDirectory(currentWorkingDirectoryPath); 843 for (int32 index = 1; index < argc; index++) { 844 BEntry entry; 845 if (entry.SetTo(&workingDirectory, argv[index]) == B_OK 846 && entry.GetRef(&ref) == B_OK) 847 OpenRef(&ref); 848 else if (get_ref_for_path(argv[index], &ref) == B_OK) 849 OpenRef(&ref); 850 } 851 } 852 } 853 854 void 855 TTracker::OpenContainerWindow(Model *model, BMessage *originalRefsList, 856 OpenSelector openSelector, uint32 openFlags, bool checkAlreadyOpen, 857 const BMessage *stateMessage) 858 { 859 AutoLock<WindowList> lock(&fWindowList); 860 BContainerWindow *window = NULL; 861 if (checkAlreadyOpen && openSelector != kRunOpenWithWindow) 862 // find out if window already open 863 window = FindContainerWindow(model->NodeRef()); 864 865 bool someWindowActivated = false; 866 867 uint32 workspace = (uint32)(1 << current_workspace()); 868 int32 windowCount = 0; 869 870 while (window) { 871 // At least one window open, just pull to front 872 // make sure we don't jerk workspaces around 873 uint32 windowWorkspaces = window->Workspaces(); 874 if (windowWorkspaces & workspace) { 875 window->Activate(); 876 someWindowActivated = true; 877 } 878 window = FindContainerWindow(model->NodeRef(), ++windowCount); 879 } 880 881 if (someWindowActivated) { 882 delete model; 883 return; 884 } // If no window was actiated, (none in the current workspace 885 // we open a new one. 886 887 if (openSelector == kRunOpenWithWindow) { 888 BMessage *refList = NULL; 889 if (!originalRefsList) { 890 // when passing just a single model, stuff it's entry in a single 891 // element list anyway 892 ASSERT(model); 893 refList = new BMessage; 894 refList->AddRef("refs", model->EntryRef()); 895 delete model; 896 model = NULL; 897 } else 898 // clone the message, window adopts it for it's own use 899 refList = new BMessage(*originalRefsList); 900 window = new OpenWithContainerWindow(refList, &fWindowList); 901 } else if (model->IsRoot()) { 902 // window will adopt the model 903 window = new BVolumeWindow(&fWindowList, openFlags); 904 } else if (model->IsQuery()) { 905 // window will adopt the model 906 window = new BQueryContainerWindow(&fWindowList, openFlags); 907 } else 908 // window will adopt the model 909 window = new BContainerWindow(&fWindowList, openFlags); 910 911 if (model) 912 window->CreatePoseView(model); 913 914 BMessage restoreStateMessage(kRestoreState); 915 916 if (stateMessage) 917 restoreStateMessage.AddMessage("state", stateMessage); 918 919 window->PostMessage(&restoreStateMessage); 920 } 921 922 923 void 924 TTracker::EditQueries(const BMessage *message) 925 { 926 bool editOnlyIfTemplate; 927 if (message->FindBool("editQueryOnPose", &editOnlyIfTemplate) != B_OK) 928 editOnlyIfTemplate = false; 929 930 type_code type; 931 int32 count; 932 message->GetInfo("refs", &type, &count); 933 for (int32 index = 0; index < count; index++) { 934 entry_ref ref; 935 message->FindRef("refs", index, &ref); 936 BEntry entry(&ref, true); 937 if (entry.InitCheck() == B_OK && entry.Exists()) 938 (new FindWindow(&ref, editOnlyIfTemplate))->Show(); 939 } 940 } 941 942 943 void 944 TTracker::OpenInfoWindows(BMessage *message) 945 { 946 type_code type; 947 int32 count; 948 message->GetInfo("refs", &type, &count); 949 950 for (int32 index = 0; index < count; index++) { 951 entry_ref ref; 952 message->FindRef("refs", index, &ref); 953 BEntry entry; 954 if (entry.SetTo(&ref) == B_OK) { 955 Model *model = new Model(&entry); 956 if (model->InitCheck() != B_OK) { 957 delete model; 958 continue; 959 } 960 961 AutoLock<WindowList> lock(&fWindowList); 962 BInfoWindow *wind = FindInfoWindow(model->NodeRef()); 963 964 if (wind) { 965 wind->Activate(); 966 delete model; 967 } else { 968 wind = new BInfoWindow(model, index, &fWindowList); 969 wind->PostMessage(kRestoreState); 970 } 971 } 972 } 973 } 974 975 976 BDeskWindow * 977 TTracker::GetDeskWindow() const 978 { 979 int32 count = fWindowList.CountItems(); 980 for (int32 index = 0; index < count; index++) { 981 BDeskWindow *window = dynamic_cast<BDeskWindow *> 982 (fWindowList.ItemAt(index)); 983 984 if (window) 985 return window; 986 } 987 TRESPASS(); 988 return NULL; 989 } 990 991 992 BContainerWindow * 993 TTracker::FindContainerWindow(const node_ref *node, int32 number) const 994 { 995 ASSERT(fWindowList.IsLocked()); 996 997 int32 count = fWindowList.CountItems(); 998 999 int32 windowsFound = 0; 1000 1001 for (int32 index = 0; index < count; index++) { 1002 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1003 (fWindowList.ItemAt(index)); 1004 1005 if (window && window->IsShowing(node) && number == windowsFound++) 1006 return window; 1007 } 1008 return NULL; 1009 } 1010 1011 1012 BContainerWindow * 1013 TTracker::FindContainerWindow(const entry_ref *entry, int32 number) const 1014 { 1015 ASSERT(fWindowList.IsLocked()); 1016 1017 int32 count = fWindowList.CountItems(); 1018 1019 int32 windowsFound = 0; 1020 1021 for (int32 index = 0; index < count; index++) { 1022 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1023 (fWindowList.ItemAt(index)); 1024 1025 if (window && window->IsShowing(entry) && number == windowsFound++) 1026 return window; 1027 } 1028 return NULL; 1029 } 1030 1031 1032 bool 1033 TTracker::EntryHasWindowOpen(const entry_ref *entry) 1034 { 1035 AutoLock<WindowList> lock(&fWindowList); 1036 return FindContainerWindow(entry) != NULL; 1037 } 1038 1039 1040 BContainerWindow * 1041 TTracker::FindParentContainerWindow(const entry_ref *ref) const 1042 { 1043 BEntry entry(ref); 1044 BEntry parent; 1045 1046 if (entry.GetParent(&parent) != B_OK) 1047 return NULL; 1048 1049 entry_ref parentRef; 1050 parent.GetRef(&parentRef); 1051 1052 ASSERT(fWindowList.IsLocked()); 1053 1054 int32 count = fWindowList.CountItems(); 1055 for (int32 index = 0; index < count; index++) { 1056 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1057 (fWindowList.ItemAt(index)); 1058 if (window && window->IsShowing(&parentRef)) 1059 return window; 1060 } 1061 return NULL; 1062 } 1063 1064 1065 BInfoWindow * 1066 TTracker::FindInfoWindow(const node_ref* node) const 1067 { 1068 ASSERT(fWindowList.IsLocked()); 1069 1070 int32 count = fWindowList.CountItems(); 1071 for (int32 index = 0; index < count; index++) { 1072 BInfoWindow *window = dynamic_cast<BInfoWindow *> 1073 (fWindowList.ItemAt(index)); 1074 if (window && window->IsShowing(node)) 1075 return window; 1076 } 1077 return NULL; 1078 } 1079 1080 1081 bool 1082 TTracker::QueryActiveForDevice(dev_t device) 1083 { 1084 AutoLock<WindowList> lock(&fWindowList); 1085 int32 count = fWindowList.CountItems(); 1086 for (int32 index = 0; index < count; index++) { 1087 BQueryContainerWindow *window = dynamic_cast<BQueryContainerWindow *> 1088 (fWindowList.ItemAt(index)); 1089 if (window) { 1090 AutoLock<BWindow> lock(window); 1091 if (window->ActiveOnDevice(device)) 1092 return true; 1093 } 1094 } 1095 return false; 1096 } 1097 1098 1099 void 1100 TTracker::CloseActiveQueryWindows(dev_t device) 1101 { 1102 // used when trying to unmount a volume - an active query would prevent that from 1103 // happening 1104 bool closed = false; 1105 AutoLock<WindowList> lock(fWindowList); 1106 for (int32 index = fWindowList.CountItems(); index >= 0; index--) { 1107 BQueryContainerWindow *window = dynamic_cast<BQueryContainerWindow *> 1108 (fWindowList.ItemAt(index)); 1109 if (window) { 1110 AutoLock<BWindow> lock(window); 1111 if (window->ActiveOnDevice(device)) { 1112 window->PostMessage(B_QUIT_REQUESTED); 1113 closed = true; 1114 } 1115 } 1116 } 1117 lock.Unlock(); 1118 if (closed) 1119 for (int32 timeout = 30; timeout; timeout--) { 1120 // wait a bit for windows to fully close 1121 if (!QueryActiveForDevice(device)) 1122 return; 1123 snooze(100000); 1124 } 1125 } 1126 1127 1128 void 1129 TTracker::SaveAllPoseLocations() 1130 { 1131 int32 numWindows = fWindowList.CountItems(); 1132 for (int32 windowIndex = 0; windowIndex < numWindows; windowIndex++) { 1133 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1134 (fWindowList.ItemAt(windowIndex)); 1135 1136 if (window) { 1137 AutoLock<BWindow> lock(window); 1138 BDeskWindow *deskWindow = dynamic_cast<BDeskWindow *>(window); 1139 1140 if (deskWindow) 1141 deskWindow->SaveDesktopPoseLocations(); 1142 else 1143 window->PoseView()->SavePoseLocations(); 1144 } 1145 } 1146 } 1147 1148 1149 void 1150 TTracker::CloseWindowAndChildren(const node_ref *node) 1151 { 1152 BDirectory dir(node); 1153 if (dir.InitCheck() != B_OK) 1154 return; 1155 1156 AutoLock<WindowList> lock(&fWindowList); 1157 BObjectList<BContainerWindow> closeList; 1158 1159 // make a list of all windows to be closed 1160 // count from end to beginning so we can remove items safely 1161 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1162 BContainerWindow *window = dynamic_cast<BContainerWindow *> 1163 (fWindowList.ItemAt(index)); 1164 if (window && window->TargetModel()) { 1165 BEntry wind_entry; 1166 wind_entry.SetTo(window->TargetModel()->EntryRef()); 1167 1168 if ((*window->TargetModel()->NodeRef() == *node) 1169 || dir.Contains(&wind_entry)) { 1170 1171 // ToDo: 1172 // get rid of the Remove here, BContainerWindow::Quit does it 1173 fWindowList.RemoveItemAt(index); 1174 closeList.AddItem(window); 1175 } 1176 } 1177 } 1178 1179 // now really close the windows 1180 int32 numItems = closeList.CountItems(); 1181 for (int32 index = 0; index < numItems; index++) { 1182 BContainerWindow *window = closeList.ItemAt(index); 1183 window->PostMessage(B_QUIT_REQUESTED); 1184 } 1185 } 1186 1187 1188 void 1189 TTracker::CloseAllInWorkspace() 1190 { 1191 AutoLock<WindowList> lock(&fWindowList); 1192 1193 int32 currentWorkspace = 1 << current_workspace(); 1194 // count from end to beginning so we can remove items safely 1195 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1196 BWindow *window = fWindowList.ItemAt(index); 1197 if (window->Workspaces() & currentWorkspace) 1198 // avoid the desktop 1199 if (!dynamic_cast<BDeskWindow *>(window) 1200 && !dynamic_cast<BStatusWindow *>(window)) 1201 window->PostMessage(B_QUIT_REQUESTED); 1202 } 1203 } 1204 1205 1206 void 1207 TTracker::CloseAllWindows() 1208 { 1209 // this is a response to the DeskBar sending us a B_QUIT, when it really 1210 // means to say close all your windows. It might be better to have it 1211 // send a kCloseAllWindows message and have windowless apps stay running, 1212 // which is what we will do for the Tracker 1213 AutoLock<WindowList> lock(&fWindowList); 1214 1215 int32 count = CountWindows(); 1216 for (int32 index = 0; index < count; index++) { 1217 BWindow *window = WindowAt(index); 1218 // avoid the desktop 1219 if (!dynamic_cast<BDeskWindow *>(window) 1220 && !dynamic_cast<BStatusWindow *>(window)) 1221 window->PostMessage(B_QUIT_REQUESTED); 1222 } 1223 // count from end to beginning so we can remove items safely 1224 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1225 BWindow *window = fWindowList.ItemAt(index); 1226 if (!dynamic_cast<BDeskWindow *>(window) 1227 && !dynamic_cast<BStatusWindow *>(window)) 1228 // ToDo: 1229 // get rid of the Remove here, BContainerWindow::Quit does it 1230 fWindowList.RemoveItemAt(index); 1231 } 1232 } 1233 1234 1235 void 1236 TTracker::_OpenPreviouslyOpenedWindows(const char* pathFilter) 1237 { 1238 size_t filterLength = 0; 1239 if (pathFilter != NULL) 1240 filterLength = strlen(pathFilter); 1241 1242 BDirectory deskDir; 1243 attr_info attrInfo; 1244 if (FSGetDeskDir(&deskDir) != B_OK 1245 || deskDir.GetAttrInfo(kAttrOpenWindows, &attrInfo) != B_OK) 1246 return; 1247 1248 char *buffer = (char *)malloc((size_t)attrInfo.size); 1249 BMessage message; 1250 if (deskDir.ReadAttr(kAttrOpenWindows, B_MESSAGE_TYPE, 0, buffer, 1251 (size_t)attrInfo.size) != attrInfo.size 1252 || message.Unflatten(buffer) != B_OK) { 1253 free(buffer); 1254 return; 1255 } 1256 1257 free(buffer); 1258 1259 node_ref nodeRef; 1260 deskDir.GetNodeRef(&nodeRef); 1261 1262 int32 stateMessageCounter = 0; 1263 const char *path; 1264 for (int32 i = 0; message.FindString("paths", i, &path) == B_OK; i++) { 1265 if (strncmp(path, pathFilter, filterLength)) 1266 continue; 1267 1268 BEntry entry(path, true); 1269 if (entry.InitCheck() != B_OK) 1270 continue; 1271 1272 int8 flags = 0; 1273 for (int32 j = 0; message.FindInt8(path, j, &flags) == B_OK; j++) { 1274 Model *model = new Model(&entry); 1275 if (model->InitCheck() == B_OK && model->IsContainer()) { 1276 BMessage state; 1277 bool restoreStateFromMessage = false; 1278 if ((flags & kOpenWindowHasState) != 0 1279 && message.FindMessage("window state", stateMessageCounter++, 1280 &state) == B_OK) 1281 restoreStateFromMessage = true; 1282 1283 if (restoreStateFromMessage) { 1284 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1285 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1286 | kRestoreDecor, false, &state); 1287 } else { 1288 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1289 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1290 | kRestoreDecor); 1291 } 1292 } else 1293 delete model; 1294 } 1295 } 1296 1297 // Open disks window if needed 1298 1299 if (pathFilter == NULL && TrackerSettings().ShowDisksIcon() 1300 && message.HasBool("open_disks_window")) { 1301 BEntry entry("/"); 1302 Model* model = new Model(&entry); 1303 if (model->InitCheck() == B_OK) 1304 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace); 1305 else 1306 delete model; 1307 } 1308 } 1309 1310 1311 void 1312 TTracker::ReadyToRun() 1313 { 1314 gStatusWindow = new BStatusWindow(); 1315 InitMimeTypes(); 1316 InstallDefaultTemplates(); 1317 InstallIndices(); 1318 InstallTemporaryBackgroundImages(); 1319 1320 fTrashWatcher = new BTrashWatcher(); 1321 fTrashWatcher->Run(); 1322 1323 fClipboardRefsWatcher = new BClipboardRefsWatcher(); 1324 fClipboardRefsWatcher->Run(); 1325 1326 fTaskLoop = new StandAloneTaskLoop(true); 1327 1328 // open desktop window 1329 BContainerWindow *deskWindow = NULL; 1330 BDirectory deskDir; 1331 if (FSGetDeskDir(&deskDir) == B_OK) { 1332 // create desktop 1333 BEntry entry; 1334 deskDir.GetEntry(&entry); 1335 Model *model = new Model(&entry, true); 1336 if (model->InitCheck() == B_OK) { 1337 AutoLock<WindowList> lock(&fWindowList); 1338 deskWindow = new BDeskWindow(&fWindowList); 1339 AutoLock<BWindow> windowLock(deskWindow); 1340 deskWindow->CreatePoseView(model); 1341 deskWindow->Init(); 1342 1343 if (TrackerSettings().ShowDisksIcon()) { 1344 // create model for root of everything 1345 BEntry entry("/"); 1346 Model model(&entry); 1347 if (model.InitCheck() == B_OK) { 1348 // add the root icon to desktop window 1349 BMessage message; 1350 message.what = B_NODE_MONITOR; 1351 message.AddInt32("opcode", B_ENTRY_CREATED); 1352 message.AddInt32("device", model.NodeRef()->device); 1353 message.AddInt64("node", model.NodeRef()->node); 1354 message.AddInt64("directory", model.EntryRef()->directory); 1355 message.AddString("name", model.EntryRef()->name); 1356 deskWindow->PostMessage(&message, deskWindow->PoseView()); 1357 } 1358 } 1359 } else 1360 delete model; 1361 } 1362 1363 // kick off building the mime type list for find panels, etc. 1364 fMimeTypeList = new MimeTypeList(); 1365 1366 if (!BootedInSafeMode()) { 1367 // kick of transient query killer 1368 DeleteTransientQueriesTask::StartUpTransientQueryCleaner(); 1369 // the mount_server will have mounted the previous volumes already. 1370 _OpenPreviouslyOpenedWindows(); 1371 } 1372 } 1373 1374 MimeTypeList * 1375 TTracker::MimeTypes() const 1376 { 1377 return fMimeTypeList; 1378 } 1379 1380 void 1381 TTracker::SelectChildInParentSoon(const entry_ref *parent, 1382 const node_ref *child) 1383 { 1384 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1385 (&TTracker::SelectChildInParent, this, parent, child), 1386 100000, 200000, 5000000); 1387 } 1388 1389 void 1390 TTracker::CloseParentWaitingForChildSoon(const entry_ref *child, 1391 const node_ref *parent) 1392 { 1393 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1394 (&TTracker::CloseParentWaitingForChild, this, child, parent), 1395 200000, 100000, 5000000); 1396 } 1397 1398 void 1399 TTracker::SelectPoseAtLocationSoon(node_ref parent, BPoint pointInPose) 1400 { 1401 fTaskLoop->RunLater(NewMemberFunctionObject 1402 (&TTracker::SelectPoseAtLocationInParent, this, parent, pointInPose), 1403 100000); 1404 } 1405 1406 void 1407 TTracker::SelectPoseAtLocationInParent(node_ref parent, BPoint pointInPose) 1408 { 1409 AutoLock<WindowList> lock(&fWindowList); 1410 BContainerWindow *parentWindow = FindContainerWindow(&parent); 1411 if (parentWindow) { 1412 AutoLock<BWindow> lock(parentWindow); 1413 parentWindow->PoseView()->SelectPoseAtLocation(pointInPose); 1414 } 1415 } 1416 1417 bool 1418 TTracker::CloseParentWaitingForChild(const entry_ref *child, 1419 const node_ref *parent) 1420 { 1421 AutoLock<WindowList> lock(&fWindowList); 1422 1423 BContainerWindow *parentWindow = FindContainerWindow(parent); 1424 if (!parentWindow) 1425 // parent window already closed, give up 1426 return true; 1427 1428 // If child is a symbolic link, dereference it, so that 1429 // FindContainerWindow will succeed. 1430 BEntry entry(child, true); 1431 entry_ref resolvedChild; 1432 if (entry.GetRef(&resolvedChild) != B_OK) 1433 resolvedChild = *child; 1434 1435 BContainerWindow *window = FindContainerWindow(&resolvedChild); 1436 if (window) { 1437 AutoLock<BWindow> lock(window); 1438 if (!window->IsHidden()) 1439 return CloseParentWindowCommon(parentWindow); 1440 } 1441 return false; 1442 } 1443 1444 void 1445 TTracker::CloseParent(node_ref parent) 1446 { 1447 AutoLock<WindowList> lock(&fWindowList); 1448 if (!lock) 1449 return; 1450 1451 CloseParentWindowCommon(FindContainerWindow(&parent)); 1452 } 1453 1454 void 1455 TTracker::ShowSettingsWindow() 1456 { 1457 if (!fSettingsWindow) { 1458 fSettingsWindow = new TrackerSettingsWindow(); 1459 fSettingsWindow->Show(); 1460 } else { 1461 if (fSettingsWindow->Lock()) { 1462 if (fSettingsWindow->IsHidden()) 1463 fSettingsWindow->Show(); 1464 else 1465 fSettingsWindow->Activate(); 1466 fSettingsWindow->Unlock(); 1467 } 1468 } 1469 } 1470 1471 bool 1472 TTracker::CloseParentWindowCommon(BContainerWindow *window) 1473 { 1474 ASSERT(fWindowList.IsLocked()); 1475 1476 if (dynamic_cast<BDeskWindow *>(window)) 1477 // don't close the destop 1478 return false; 1479 1480 window->PostMessage(B_QUIT_REQUESTED); 1481 return true; 1482 } 1483 1484 bool 1485 TTracker::SelectChildInParent(const entry_ref *parent, const node_ref *child) 1486 { 1487 AutoLock<WindowList> lock(&fWindowList); 1488 1489 BContainerWindow *window = FindContainerWindow(parent); 1490 if (!window) 1491 // parent window already closed, give up 1492 return false; 1493 1494 AutoLock<BWindow> windowLock(window); 1495 1496 if (windowLock.IsLocked()) { 1497 BPoseView *view = window->PoseView(); 1498 int32 index; 1499 BPose *pose = view->FindPose(child, &index); 1500 if (pose) { 1501 view->SelectPose(pose, index); 1502 return true; 1503 } 1504 } 1505 return false; 1506 } 1507 1508 const int32 kNodeMonitorBumpValue = 512; 1509 1510 status_t 1511 TTracker::NeedMoreNodeMonitors() 1512 { 1513 fNodeMonitorCount += kNodeMonitorBumpValue; 1514 PRINT(("bumping nodeMonitorCount to %" B_PRId32 "\n", fNodeMonitorCount)); 1515 1516 struct rlimit rl; 1517 rl.rlim_cur = fNodeMonitorCount; 1518 rl.rlim_max = RLIM_SAVED_MAX; 1519 if (setrlimit(RLIMIT_NOVMON, &rl) < 0) { 1520 fNodeMonitorCount -= kNodeMonitorBumpValue; 1521 return errno; 1522 } 1523 return B_OK; 1524 1525 } 1526 1527 status_t 1528 TTracker::WatchNode(const node_ref *node, uint32 flags, 1529 BMessenger target) 1530 { 1531 status_t result = watch_node(node, flags, target); 1532 if (result == B_OK || result != B_NO_MEMORY) { 1533 // need to make sure this uses the same error value as 1534 // the node monitor code 1535 return result; 1536 } 1537 1538 PRINT(("failed to start monitoring, trying to allocate more " 1539 "node monitors\n")); 1540 1541 TTracker *tracker = dynamic_cast<TTracker *>(be_app); 1542 if (!tracker) { 1543 // we are the file panel only, just fail 1544 return result; 1545 } 1546 1547 result = tracker->NeedMoreNodeMonitors(); 1548 1549 if (result != B_OK) { 1550 PRINT(("failed to allocate more node monitors, %s\n", 1551 strerror(result))); 1552 return result; 1553 } 1554 1555 // try again, this time with more node monitors 1556 return watch_node(node, flags, target); 1557 } 1558 1559 1560 BMessenger 1561 TTracker::MountServer() const 1562 { 1563 return BMessenger(kMountServerSignature); 1564 } 1565 1566 1567 bool 1568 TTracker::InTrashNode(const entry_ref *node) const 1569 { 1570 return FSInTrashDir(node); 1571 } 1572 1573 1574 bool 1575 TTracker::TrashFull() const 1576 { 1577 return fTrashWatcher->CheckTrashDirs(); 1578 } 1579 1580 1581 bool 1582 TTracker::IsTrashNode(const node_ref *node) const 1583 { 1584 return fTrashWatcher->IsTrashNode(node); 1585 } 1586 1587