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