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