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