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