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