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