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