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 bool brokenLinkWithSpecificHandler = false; 821 BString brokenLinkPreferredApp; 822 823 if (result != B_OK) { 824 model = new Model(ref, false); 825 if (model->IsSymLink() && !model->LinkTo()) { 826 model->GetPreferredAppForBrokenSymLink(brokenLinkPreferredApp); 827 if (brokenLinkPreferredApp.Length() 828 && brokenLinkPreferredApp != kTrackerSignature) { 829 brokenLinkWithSpecificHandler = true; 830 } 831 } 832 833 if (!brokenLinkWithSpecificHandler) { 834 delete model; 835 BAlert* alert = new BAlert("", 836 B_TRANSLATE("There was an error resolving the link."), 837 B_TRANSLATE("Cancel"), 0, 0, B_WIDTH_AS_USUAL, 838 B_WARNING_ALERT); 839 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 840 alert->Go(); 841 842 return result; 843 } 844 } else 845 model = new Model(&entry); 846 847 result = model->InitCheck(); 848 if (result != B_OK) { 849 delete model; 850 return result; 851 } 852 853 bool openAsContainer = model->IsContainer(); 854 855 if (openAsContainer && selector != kOpenWith) { 856 // if folder or query has a preferred handler and it's not the 857 // Tracker, open it by sending refs to the handling app 858 859 // if we are responding to the final open of OpenWith, just 860 // skip this and proceed to opening the container with Tracker 861 model->OpenNode(); 862 BNodeInfo nodeInfo(model->Node()); 863 char preferredApp[B_MIME_TYPE_LENGTH]; 864 if (nodeInfo.GetPreferredApp(preferredApp) == B_OK 865 && strcasecmp(preferredApp, kTrackerSignature) != 0) { 866 openAsContainer = false; 867 } 868 model->CloseNode(); 869 } 870 871 if (openAsContainer || selector == kRunOpenWithWindow) { 872 // special case opening plain folders, queries or using open with 873 OpenContainerWindow(model, NULL, selector, kRestoreDecor); 874 // window adopts model 875 if (nodeToClose) 876 CloseParentWaitingForChildSoon(ref, nodeToClose); 877 } else if (model->IsQueryTemplate()) { 878 // query template - open new find window 879 (new FindWindow(model->EntryRef()))->Show(); 880 881 delete model; 882 if (nodeToClose) 883 CloseParentWaitingForChildSoon(ref, nodeToClose); 884 } else { 885 delete model; 886 // run Launch in a separate thread and close parent if successful 887 if (nodeToClose) { 888 Thread::Launch(new EntryAndNodeDoSoonWithMessageFunctor<TTracker, 889 bool (TTracker::*)(const entry_ref*, const node_ref*, 890 const BMessage*)>(&TTracker::LaunchAndCloseParentIfOK, this, 891 ref, nodeToClose, messageToBundle)); 892 } else { 893 BMessage refsReceived(B_REFS_RECEIVED); 894 if (messageToBundle) { 895 refsReceived = *messageToBundle; 896 refsReceived.what = B_REFS_RECEIVED; 897 } 898 refsReceived.AddRef("refs", ref); 899 if (brokenLinkWithSpecificHandler) { 900 // This cruft is to support a hacky workaround for 901 // double-clicking broken refs for cifs; should get fixed 902 // in R5 903 LaunchBrokenLink(brokenLinkPreferredApp.String(), 904 &refsReceived); 905 } else 906 TrackerLaunch(&refsReceived, true); 907 } 908 } 909 910 if (nodeToSelect) 911 SelectChildInParentSoon(ref, nodeToSelect); 912 913 return B_OK; 914 } 915 916 917 void 918 TTracker::RefsReceived(BMessage* message) 919 { 920 OpenSelector selector = kOpen; 921 if (message->HasInt32("launchUsingSelector")) 922 selector = kRunOpenWithWindow; 923 924 entry_ref handlingApp; 925 if (message->FindRef("handler", &handlingApp) == B_OK) 926 selector = kOpenWith; 927 928 int32 count; 929 uint32 type; 930 message->GetInfo("refs", &type, &count); 931 932 switch (selector) { 933 case kRunOpenWithWindow: 934 OpenContainerWindow(NULL, message, selector); 935 // window adopts model 936 break; 937 938 case kOpenWith: 939 { 940 // Open With resulted in passing refs and a handler, 941 // open the files with the handling app 942 message->RemoveName("handler"); 943 944 // have to find out if handling app is the Tracker 945 // if it is, just pass it to the active Tracker, 946 // no matter which Tracker was chosen to handle the refs 947 char signature[B_MIME_TYPE_LENGTH]; 948 signature[0] = '\0'; 949 { 950 BFile handlingNode(&handlingApp, O_RDONLY); 951 BAppFileInfo appInfo(&handlingNode); 952 appInfo.GetSignature(signature); 953 } 954 955 if (strcasecmp(signature, kTrackerSignature) != 0) { 956 // handling app not Tracker, pass entries to the apps 957 // RefsReceived 958 TrackerLaunch(&handlingApp, message, true); 959 break; 960 } 961 } 962 // fall thru, opening refs by the Tracker as if they were 963 // double-clicked 964 case kOpen: 965 { 966 // copy over "Poses" messenger so that refs received 967 // recipients know where the open came from 968 BMessage* bundleThis = NULL; 969 BMessage stackBundleThis; 970 BMessenger messenger; 971 if (message->FindMessenger("TrackerViewToken", &messenger) 972 == B_OK) { 973 bundleThis = &stackBundleThis; 974 bundleThis->AddMessenger("TrackerViewToken", messenger); 975 } else { 976 // copy over any "be:*" fields -- e.g. /bin/open may include 977 // "be:line" and "be:column" 978 for (int32 i = 0;; i++) { 979 char* name; 980 type_code type; 981 int32 count; 982 status_t error = message->GetInfo(B_ANY_TYPE, i, &name, 983 &type, &count); 984 if (error != B_OK) 985 break; 986 987 if (strncmp(name, "be:", 3) != 0) 988 continue; 989 990 for (int32 k = 0; k < count; k++) { 991 const void* data; 992 ssize_t size; 993 if (message->FindData(name, type, k, &data, &size) 994 != B_OK) { 995 break; 996 } 997 if (stackBundleThis.AddData(name, type, data, size) 998 != B_OK) { 999 break; 1000 } 1001 bundleThis = &stackBundleThis; 1002 } 1003 } 1004 } 1005 1006 for (int32 index = 0; index < count; index++) { 1007 entry_ref ref; 1008 message->FindRef("refs", index, &ref); 1009 1010 const node_ref* nodeToClose = NULL; 1011 const node_ref* nodeToSelect = NULL; 1012 ssize_t numBytes; 1013 1014 message->FindData("nodeRefsToClose", B_RAW_TYPE, index, 1015 (const void**)&nodeToClose, &numBytes); 1016 message->FindData("nodeRefToSelect", B_RAW_TYPE, index, 1017 (const void**)&nodeToSelect, &numBytes); 1018 1019 OpenRef(&ref, nodeToClose, nodeToSelect, selector, 1020 bundleThis); 1021 } 1022 1023 break; 1024 } 1025 } 1026 } 1027 1028 1029 void 1030 TTracker::ArgvReceived(int32 argc, char** argv) 1031 { 1032 BMessage* message = CurrentMessage(); 1033 const char* currentWorkingDirectoryPath = NULL; 1034 entry_ref ref; 1035 1036 if (message->FindString("cwd", ¤tWorkingDirectoryPath) == B_OK) { 1037 BDirectory workingDirectory(currentWorkingDirectoryPath); 1038 for (int32 index = 1; index < argc; index++) { 1039 BEntry entry; 1040 if (entry.SetTo(&workingDirectory, argv[index]) == B_OK 1041 && entry.GetRef(&ref) == B_OK) { 1042 OpenRef(&ref); 1043 } else if (get_ref_for_path(argv[index], &ref) == B_OK) 1044 OpenRef(&ref); 1045 } 1046 } 1047 } 1048 1049 1050 void 1051 TTracker::OpenContainerWindow(Model* model, BMessage* originalRefsList, 1052 OpenSelector openSelector, uint32 openFlags, bool checkAlreadyOpen, 1053 const BMessage* stateMessage) 1054 { 1055 AutoLock<WindowList> lock(&fWindowList); 1056 BContainerWindow* window = NULL; 1057 const node_ref* modelNodeRef = model->NodeRef(); 1058 if (checkAlreadyOpen && openSelector != kRunOpenWithWindow) { 1059 // find out if window already open 1060 window = FindContainerWindow(modelNodeRef); 1061 } 1062 1063 bool someWindowActivated = false; 1064 1065 uint32 workspace = (uint32)(1 << current_workspace()); 1066 int32 windowCount = 0; 1067 while (window != NULL) { 1068 if ((window->Workspaces() & workspace) != 0 1069 && (dynamic_cast<BDeskWindow*>(window) == NULL 1070 || !TrackerSettings().SingleWindowBrowse())) { 1071 // We found at least one window that is open and is not Desktop 1072 // or we're in spatial mode, activate it and make sure we don't 1073 // jerk the workspaces around. 1074 window->Activate(); 1075 someWindowActivated = true; 1076 } 1077 window = FindContainerWindow(model->NodeRef(), ++windowCount); 1078 } 1079 1080 if (someWindowActivated) { 1081 delete model; 1082 return; 1083 } 1084 1085 // If no window was activated (none in the current workspace), 1086 // we open a new one. 1087 1088 if (openSelector == kRunOpenWithWindow) { 1089 BMessage* refList = NULL; 1090 if (originalRefsList == NULL) { 1091 // when passing just a single model, stuff it's entry in a single 1092 // element list anyway 1093 ASSERT(model != NULL); 1094 refList = new BMessage; 1095 refList->AddRef("refs", model->EntryRef()); 1096 delete model; 1097 model = NULL; 1098 } else { 1099 // clone the message, window adopts it for it's own use 1100 refList = new BMessage(*originalRefsList); 1101 } 1102 window = new OpenWithContainerWindow(refList, &fWindowList); 1103 } else if (model->IsQuery()) { 1104 // window will adopt the model 1105 window = new BQueryContainerWindow(&fWindowList, openFlags); 1106 } else if (model->IsVirtualDirectory()) { 1107 // window will adopt the model 1108 window = new VirtualDirectoryWindow(&fWindowList, openFlags); 1109 } else { 1110 // window will adopt the model 1111 window = new BContainerWindow(&fWindowList, openFlags); 1112 } 1113 1114 if (model != NULL && window->LockLooper()) { 1115 window->CreatePoseView(model); 1116 if (window->PoseView() == NULL) { 1117 // Failed initialization. 1118 window->PostMessage(B_QUIT_REQUESTED); 1119 window->UnlockLooper(); 1120 return; 1121 } 1122 window->UnlockLooper(); 1123 } 1124 1125 BMessage restoreStateMessage(kRestoreState); 1126 1127 if (stateMessage != NULL) 1128 restoreStateMessage.AddMessage("state", stateMessage); 1129 1130 window->PostMessage(&restoreStateMessage); 1131 } 1132 1133 1134 void 1135 TTracker::EditQueries(const BMessage* message) 1136 { 1137 bool editOnlyIfTemplate; 1138 if (message->FindBool("editQueryOnPose", &editOnlyIfTemplate) != B_OK) 1139 editOnlyIfTemplate = false; 1140 1141 type_code type; 1142 int32 count; 1143 message->GetInfo("refs", &type, &count); 1144 for (int32 index = 0; index < count; index++) { 1145 entry_ref ref; 1146 message->FindRef("refs", index, &ref); 1147 BEntry entry(&ref, true); 1148 if (entry.InitCheck() == B_OK && entry.Exists()) 1149 (new FindWindow(&ref, editOnlyIfTemplate))->Show(); 1150 } 1151 } 1152 1153 1154 void 1155 TTracker::OpenInfoWindows(BMessage* message) 1156 { 1157 type_code type; 1158 int32 count; 1159 message->GetInfo("refs", &type, &count); 1160 1161 for (int32 index = 0; index < count; index++) { 1162 entry_ref ref; 1163 message->FindRef("refs", index, &ref); 1164 BEntry entry; 1165 if (entry.SetTo(&ref) == B_OK) { 1166 Model* model = new Model(&entry); 1167 if (model->InitCheck() != B_OK) { 1168 delete model; 1169 continue; 1170 } 1171 1172 AutoLock<WindowList> lock(&fWindowList); 1173 BInfoWindow* wind = FindInfoWindow(model->NodeRef()); 1174 1175 if (wind) { 1176 wind->Activate(); 1177 delete model; 1178 } else { 1179 wind = new BInfoWindow(model, index, &fWindowList); 1180 wind->PostMessage(kRestoreState); 1181 } 1182 } 1183 } 1184 } 1185 1186 1187 BDeskWindow* 1188 TTracker::GetDeskWindow() const 1189 { 1190 int32 count = fWindowList.CountItems(); 1191 for (int32 index = 0; index < count; index++) { 1192 BDeskWindow* window = dynamic_cast<BDeskWindow*>( 1193 fWindowList.ItemAt(index)); 1194 if (window != NULL) 1195 return window; 1196 } 1197 TRESPASS(); 1198 1199 return NULL; 1200 } 1201 1202 1203 BContainerWindow* 1204 TTracker::FindContainerWindow(const node_ref* node, int32 number) const 1205 { 1206 ASSERT(fWindowList.IsLocked()); 1207 1208 int32 count = fWindowList.CountItems(); 1209 int32 windowsFound = 0; 1210 for (int32 index = 0; index < count; index++) { 1211 BContainerWindow* window = dynamic_cast<BContainerWindow*>( 1212 fWindowList.ItemAt(index)); 1213 1214 if (window != NULL && window->IsShowing(node) 1215 && number == windowsFound++) { 1216 return window; 1217 } 1218 } 1219 1220 return NULL; 1221 } 1222 1223 1224 BContainerWindow* 1225 TTracker::FindContainerWindow(const entry_ref* entry, int32 number) const 1226 { 1227 ASSERT(fWindowList.IsLocked()); 1228 1229 int32 count = fWindowList.CountItems(); 1230 1231 int32 windowsFound = 0; 1232 1233 for (int32 index = 0; index < count; index++) { 1234 BContainerWindow* window = dynamic_cast<BContainerWindow*> 1235 (fWindowList.ItemAt(index)); 1236 1237 if (window && window->IsShowing(entry) && number == windowsFound++) 1238 return window; 1239 } 1240 1241 return NULL; 1242 } 1243 1244 1245 bool 1246 TTracker::EntryHasWindowOpen(const entry_ref* entry) 1247 { 1248 AutoLock<WindowList> lock(&fWindowList); 1249 return FindContainerWindow(entry) != NULL; 1250 } 1251 1252 1253 BContainerWindow* 1254 TTracker::FindParentContainerWindow(const entry_ref* ref) const 1255 { 1256 BEntry entry(ref); 1257 BEntry parent; 1258 1259 if (entry.GetParent(&parent) != B_OK) 1260 return NULL; 1261 1262 entry_ref parentRef; 1263 parent.GetRef(&parentRef); 1264 1265 ASSERT(fWindowList.IsLocked()); 1266 1267 int32 count = fWindowList.CountItems(); 1268 for (int32 index = 0; index < count; index++) { 1269 BContainerWindow* window = dynamic_cast<BContainerWindow*>( 1270 fWindowList.ItemAt(index)); 1271 if (window != NULL && window->IsShowing(&parentRef)) 1272 return window; 1273 } 1274 1275 return NULL; 1276 } 1277 1278 1279 BInfoWindow* 1280 TTracker::FindInfoWindow(const node_ref* node) const 1281 { 1282 ASSERT(fWindowList.IsLocked()); 1283 1284 int32 count = fWindowList.CountItems(); 1285 for (int32 index = 0; index < count; index++) { 1286 BInfoWindow* window = dynamic_cast<BInfoWindow*>( 1287 fWindowList.ItemAt(index)); 1288 if (window != NULL && window->IsShowing(node)) 1289 return window; 1290 } 1291 1292 return NULL; 1293 } 1294 1295 1296 bool 1297 TTracker::QueryActiveForDevice(dev_t device) 1298 { 1299 AutoLock<WindowList> lock(&fWindowList); 1300 int32 count = fWindowList.CountItems(); 1301 for (int32 index = 0; index < count; index++) { 1302 BQueryContainerWindow* window = dynamic_cast<BQueryContainerWindow*>( 1303 fWindowList.ItemAt(index)); 1304 if (window != NULL) { 1305 AutoLock<BWindow> lock(window); 1306 if (window->ActiveOnDevice(device)) 1307 return true; 1308 } 1309 } 1310 1311 return false; 1312 } 1313 1314 1315 void 1316 TTracker::CloseActiveQueryWindows(dev_t device) 1317 { 1318 // used when trying to unmount a volume - an active query would prevent 1319 // that from happening 1320 bool closed = false; 1321 AutoLock<WindowList> lock(fWindowList); 1322 for (int32 index = fWindowList.CountItems(); index >= 0; index--) { 1323 BQueryContainerWindow* window 1324 = dynamic_cast<BQueryContainerWindow*>(fWindowList.ItemAt(index)); 1325 if (window != NULL) { 1326 AutoLock<BWindow> lock(window); 1327 if (window->ActiveOnDevice(device)) { 1328 window->PostMessage(B_QUIT_REQUESTED); 1329 closed = true; 1330 } 1331 } 1332 } 1333 1334 lock.Unlock(); 1335 1336 if (closed) { 1337 for (int32 timeout = 30; timeout; timeout--) { 1338 // wait a bit for windows to fully close 1339 if (!QueryActiveForDevice(device)) 1340 return; 1341 1342 snooze(100000); 1343 } 1344 } 1345 } 1346 1347 1348 void 1349 TTracker::SaveAllPoseLocations() 1350 { 1351 int32 numWindows = fWindowList.CountItems(); 1352 for (int32 windowIndex = 0; windowIndex < numWindows; windowIndex++) { 1353 BContainerWindow* window = dynamic_cast<BContainerWindow*>( 1354 fWindowList.ItemAt(windowIndex)); 1355 if (window != NULL) { 1356 AutoLock<BWindow> lock(window); 1357 BDeskWindow* deskWindow = dynamic_cast<BDeskWindow*>(window); 1358 if (deskWindow != NULL) 1359 deskWindow->SaveDesktopPoseLocations(); 1360 else 1361 window->PoseView()->SavePoseLocations(); 1362 } 1363 } 1364 } 1365 1366 1367 void 1368 TTracker::CloseWindowAndChildren(const node_ref* node) 1369 { 1370 BDirectory dir(node); 1371 if (dir.InitCheck() != B_OK) 1372 return; 1373 1374 AutoLock<WindowList> lock(&fWindowList); 1375 BObjectList<BContainerWindow> closeList; 1376 1377 // make a list of all windows to be closed 1378 // count from end to beginning so we can remove items safely 1379 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1380 BContainerWindow* window = dynamic_cast<BContainerWindow*>( 1381 fWindowList.ItemAt(index)); 1382 if (window && window->TargetModel()) { 1383 BEntry wind_entry; 1384 wind_entry.SetTo(window->TargetModel()->EntryRef()); 1385 1386 if ((*window->TargetModel()->NodeRef() == *node) 1387 || dir.Contains(&wind_entry)) { 1388 1389 // ToDo: 1390 // get rid of the Remove here, BContainerWindow::Quit does it 1391 fWindowList.RemoveItemAt(index); 1392 closeList.AddItem(window); 1393 } 1394 } 1395 } 1396 1397 // now really close the windows 1398 int32 numItems = closeList.CountItems(); 1399 for (int32 index = 0; index < numItems; index++) { 1400 BContainerWindow* window = closeList.ItemAt(index); 1401 window->PostMessage(B_QUIT_REQUESTED); 1402 } 1403 } 1404 1405 1406 void 1407 TTracker::CloseAllInWorkspace() 1408 { 1409 AutoLock<WindowList> lock(&fWindowList); 1410 1411 int32 currentWorkspace = 1 << current_workspace(); 1412 // count from end to beginning so we can remove items safely 1413 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1414 BWindow* window = fWindowList.ItemAt(index); 1415 if (window != NULL && (window->Workspaces() & currentWorkspace) != 0) { 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 } 1424 1425 1426 void 1427 TTracker::CloseAllWindows() 1428 { 1429 // this is a response to the DeskBar sending us a B_QUIT, when it really 1430 // means to say close all your windows. It might be better to have it 1431 // send a kCloseAllWindows message and have windowless apps stay running, 1432 // which is what we will do for the Tracker 1433 AutoLock<WindowList> lock(&fWindowList); 1434 1435 int32 count = CountWindows(); 1436 for (int32 index = 0; index < count; index++) { 1437 BWindow* window = WindowAt(index); 1438 // avoid the desktop 1439 if (dynamic_cast<BDeskWindow*>(window) == NULL 1440 && dynamic_cast<BStatusWindow*>(window) == NULL) { 1441 window->PostMessage(B_QUIT_REQUESTED); 1442 } 1443 } 1444 1445 // count from end to beginning so we can remove items safely 1446 for (int32 index = fWindowList.CountItems() - 1; index >= 0; index--) { 1447 BWindow* window = fWindowList.ItemAt(index); 1448 if (dynamic_cast<BDeskWindow*>(window) == NULL 1449 && dynamic_cast<BStatusWindow*>(window) == NULL) { 1450 // ToDo: get rid of the Remove here, BContainerWindow::Quit() 1451 // does it 1452 fWindowList.RemoveItemAt(index); 1453 } 1454 } 1455 } 1456 1457 1458 void 1459 TTracker::_OpenPreviouslyOpenedWindows(const char* pathFilter) 1460 { 1461 size_t filterLength = 0; 1462 if (pathFilter != NULL) 1463 filterLength = strlen(pathFilter); 1464 1465 BDirectory deskDir; 1466 attr_info attrInfo; 1467 if (FSGetDeskDir(&deskDir) != B_OK 1468 || deskDir.GetAttrInfo(kAttrOpenWindows, &attrInfo) != B_OK) { 1469 return; 1470 } 1471 1472 char* buffer = (char*)malloc((size_t)attrInfo.size); 1473 BMessage message; 1474 if (deskDir.ReadAttr(kAttrOpenWindows, B_MESSAGE_TYPE, 0, buffer, 1475 (size_t)attrInfo.size) != attrInfo.size 1476 || message.Unflatten(buffer) != B_OK) { 1477 free(buffer); 1478 return; 1479 } 1480 1481 free(buffer); 1482 1483 node_ref nodeRef; 1484 deskDir.GetNodeRef(&nodeRef); 1485 1486 int32 stateMessageCounter = 0; 1487 const char* path; 1488 for (int32 i = 0; message.FindString("paths", i, &path) == B_OK; i++) { 1489 if (strncmp(path, pathFilter, filterLength) != 0) 1490 continue; 1491 1492 BEntry entry(path, true); 1493 if (entry.InitCheck() != B_OK) 1494 continue; 1495 1496 int8 flags = 0; 1497 for (int32 j = 0; message.FindInt8(path, j, &flags) == B_OK; j++) { 1498 Model* model = new Model(&entry); 1499 if (model->InitCheck() == B_OK && model->IsContainer()) { 1500 BMessage state; 1501 bool restoreStateFromMessage = false; 1502 if ((flags & kOpenWindowHasState) != 0 1503 && message.FindMessage("window state", 1504 stateMessageCounter++, &state) == B_OK) { 1505 restoreStateFromMessage = true; 1506 } 1507 1508 if (restoreStateFromMessage) { 1509 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1510 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1511 | kRestoreDecor, false, &state); 1512 } else { 1513 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace 1514 | (flags & kOpenWindowMinimized ? kIsHidden : 0U) 1515 | kRestoreDecor); 1516 } 1517 } else 1518 delete model; 1519 } 1520 } 1521 1522 // open disks window if needed 1523 1524 if (pathFilter == NULL && TrackerSettings().ShowDisksIcon() 1525 && message.HasBool("open_disks_window")) { 1526 BEntry entry("/"); 1527 Model* model = new Model(&entry); 1528 if (model->InitCheck() == B_OK) 1529 OpenContainerWindow(model, 0, kOpen, kRestoreWorkspace); 1530 else 1531 delete model; 1532 } 1533 } 1534 1535 1536 void 1537 TTracker::ReadyToRun() 1538 { 1539 gStatusWindow = new BStatusWindow(); 1540 InitMimeTypes(); 1541 InstallDefaultTemplates(); 1542 InstallIndices(); 1543 InstallTemporaryBackgroundImages(); 1544 1545 fTrashWatcher = new BTrashWatcher(); 1546 fTrashWatcher->Run(); 1547 1548 fClipboardRefsWatcher = new BClipboardRefsWatcher(); 1549 fClipboardRefsWatcher->Run(); 1550 1551 fTaskLoop = new StandAloneTaskLoop(true); 1552 1553 // kick off building the mime type list for find panels, etc. 1554 fMimeTypeList = new MimeTypeList(); 1555 1556 if (!BootedInSafeMode()) { 1557 // kick of transient query killer 1558 DeleteTransientQueriesTask::StartUpTransientQueryCleaner(); 1559 // the mount_server will have mounted the previous volumes already. 1560 _OpenPreviouslyOpenedWindows(); 1561 } 1562 } 1563 1564 1565 MimeTypeList* 1566 TTracker::MimeTypes() const 1567 { 1568 return fMimeTypeList; 1569 } 1570 1571 1572 void 1573 TTracker::SelectChildInParentSoon(const entry_ref* parent, 1574 const node_ref* child) 1575 { 1576 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1577 (&TTracker::SelectChildInParent, this, parent, child), 1578 100000, 200000, 5000000); 1579 } 1580 1581 1582 void 1583 TTracker::CloseParentWaitingForChildSoon(const entry_ref* child, 1584 const node_ref* parent) 1585 { 1586 fTaskLoop->RunLater(NewMemberFunctionObjectWithResult 1587 (&TTracker::CloseParentWaitingForChild, this, child, parent), 1588 200000, 100000, 5000000); 1589 } 1590 1591 1592 void 1593 TTracker::SelectPoseAtLocationSoon(node_ref parent, BPoint pointInPose) 1594 { 1595 fTaskLoop->RunLater(NewMemberFunctionObject 1596 (&TTracker::SelectPoseAtLocationInParent, this, parent, pointInPose), 1597 100000); 1598 } 1599 1600 1601 void 1602 TTracker::SelectPoseAtLocationInParent(node_ref parent, BPoint pointInPose) 1603 { 1604 AutoLock<WindowList> lock(&fWindowList); 1605 BContainerWindow* parentWindow = FindContainerWindow(&parent); 1606 if (parentWindow != NULL) { 1607 AutoLock<BWindow> lock(parentWindow); 1608 parentWindow->PoseView()->SelectPoseAtLocation(pointInPose); 1609 } 1610 } 1611 1612 1613 bool 1614 TTracker::CloseParentWaitingForChild(const entry_ref* child, 1615 const node_ref* parent) 1616 { 1617 AutoLock<WindowList> lock(&fWindowList); 1618 1619 BContainerWindow* parentWindow = FindContainerWindow(parent); 1620 if (parentWindow == NULL) { 1621 // parent window already closed, give up 1622 return true; 1623 } 1624 1625 // If child is a symbolic link, dereference it, so that 1626 // FindContainerWindow will succeed. 1627 BEntry entry(child, true); 1628 entry_ref resolvedChild; 1629 if (entry.GetRef(&resolvedChild) != B_OK) 1630 resolvedChild = *child; 1631 1632 BContainerWindow* window = FindContainerWindow(&resolvedChild); 1633 if (window != NULL) { 1634 AutoLock<BWindow> lock(window); 1635 if (!window->IsHidden()) 1636 return CloseParentWindowCommon(parentWindow); 1637 } 1638 1639 return false; 1640 } 1641 1642 1643 void 1644 TTracker::CloseParent(node_ref parent) 1645 { 1646 AutoLock<WindowList> lock(&fWindowList); 1647 if (!lock) 1648 return; 1649 1650 CloseParentWindowCommon(FindContainerWindow(&parent)); 1651 } 1652 1653 1654 void 1655 TTracker::ShowSettingsWindow() 1656 { 1657 if (fSettingsWindow == NULL) { 1658 fSettingsWindow = new TrackerSettingsWindow(); 1659 fSettingsWindow->Show(); 1660 } else { 1661 if (fSettingsWindow->Lock()) { 1662 if (fSettingsWindow->IsHidden()) 1663 fSettingsWindow->Show(); 1664 else 1665 fSettingsWindow->Activate(); 1666 1667 fSettingsWindow->Unlock(); 1668 } 1669 } 1670 } 1671 1672 1673 bool 1674 TTracker::CloseParentWindowCommon(BContainerWindow* window) 1675 { 1676 ASSERT(fWindowList.IsLocked()); 1677 1678 if (dynamic_cast<BDeskWindow*>(window) != NULL) { 1679 // don't close the desktop 1680 return false; 1681 } 1682 1683 window->PostMessage(B_QUIT_REQUESTED); 1684 return true; 1685 } 1686 1687 1688 bool 1689 TTracker::SelectChildInParent(const entry_ref* parent, const node_ref* child) 1690 { 1691 AutoLock<WindowList> lock(&fWindowList); 1692 1693 BContainerWindow* window = FindContainerWindow(parent); 1694 if (window == NULL) { 1695 // parent window already closed, give up 1696 return false; 1697 } 1698 1699 AutoLock<BWindow> windowLock(window); 1700 if (windowLock.IsLocked()) { 1701 BPoseView* view = window->PoseView(); 1702 int32 index; 1703 BPose* pose = view->FindPose(child, &index); 1704 if (pose != NULL) { 1705 view->SelectPose(pose, index); 1706 return true; 1707 } 1708 } 1709 1710 return false; 1711 } 1712 1713 1714 status_t 1715 TTracker::NeedMoreNodeMonitors() 1716 { 1717 fNodeMonitorCount += kNodeMonitorBumpValue; 1718 PRINT(("bumping nodeMonitorCount to %" B_PRId32 "\n", fNodeMonitorCount)); 1719 1720 struct rlimit rl; 1721 rl.rlim_cur = fNodeMonitorCount; 1722 rl.rlim_max = RLIM_SAVED_MAX; 1723 if (setrlimit(RLIMIT_NOVMON, &rl) < 0) { 1724 fNodeMonitorCount -= kNodeMonitorBumpValue; 1725 return errno; 1726 } 1727 1728 return B_OK; 1729 } 1730 1731 1732 status_t 1733 TTracker::WatchNode(const node_ref* node, uint32 flags, BMessenger target) 1734 { 1735 status_t result = watch_node(node, flags, target); 1736 if (result == B_OK || result != B_NO_MEMORY) { 1737 // need to make sure this uses the same error value as 1738 // the node monitor code 1739 return result; 1740 } 1741 1742 PRINT(("failed to start monitoring, trying to allocate more " 1743 "node monitors\n")); 1744 1745 TTracker* tracker = dynamic_cast<TTracker*>(be_app); 1746 if (tracker == NULL) { 1747 // we are the file panel only, just fail 1748 return result; 1749 } 1750 1751 result = tracker->NeedMoreNodeMonitors(); 1752 1753 if (result != B_OK) { 1754 PRINT(("failed to allocate more node monitors, %s\n", 1755 strerror(result))); 1756 return result; 1757 } 1758 1759 // try again, this time with more node monitors 1760 return watch_node(node, flags, target); 1761 } 1762 1763 1764 BMessenger 1765 TTracker::MountServer() const 1766 { 1767 return BMessenger(kMountServerSignature); 1768 } 1769 1770 1771 bool 1772 TTracker::TrashFull() const 1773 { 1774 return fTrashWatcher->CheckTrashDirs(); 1775 } 1776 1777 1778 bool 1779 TTracker::IsTrashNode(const node_ref* node) const 1780 { 1781 return fTrashWatcher->IsTrashNode(node); 1782 } 1783 1784 bool 1785 TTracker::InTrashNode(const entry_ref* ref) const 1786 { 1787 return FSInTrashDir(ref); 1788 } 1789