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