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