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 // DesktopPoseView adds support for displaying integrated desktops 36 // from multiple volumes to BPoseView 37 // 38 // Used by the Desktop window and by the root view in file panels 39 40 #include <NodeMonitor.h> 41 #include <Path.h> 42 #include <VolumeRoster.h> 43 #include <Volume.h> 44 45 #include "Commands.h" 46 #include "DesktopPoseView.h" 47 #include "FSUtils.h" 48 #include "PoseList.h" 49 #include "Tracker.h" 50 #include "TrackerSettings.h" 51 #include "TrackerString.h" 52 53 54 namespace BPrivate { 55 56 bool 57 ShouldShowDesktopPose(dev_t device, const Model *model, const PoseInfo *) 58 { 59 if (model->NodeRef()->device != device) { 60 // avoid having more than one Trash 61 BDirectory remoteTrash; 62 if (FSGetTrashDir(&remoteTrash, model->NodeRef()->device) == B_OK) { 63 node_ref remoteTrashNodeRef; 64 remoteTrash.GetNodeRef(&remoteTrashNodeRef); 65 if (remoteTrashNodeRef == *model->NodeRef()) 66 return false; 67 } 68 } 69 return true; 70 } 71 72 } // namespace BPrivate 73 74 75 DesktopEntryListCollection::DesktopEntryListCollection() 76 { 77 } 78 79 80 // #pragma mark - 81 82 83 DesktopPoseView::DesktopPoseView(Model *model, BRect frame, uint32 viewMode, 84 uint32 resizeMask) 85 : BPoseView(model, frame, viewMode, resizeMask) 86 { 87 SetWidgetTextOutline(true); 88 SetFlags(Flags() | B_DRAW_ON_CHILDREN); 89 } 90 91 92 EntryListBase * 93 DesktopPoseView::InitDesktopDirentIterator(BPoseView *nodeMonitoringTarget, 94 const entry_ref *ref) 95 { 96 // the desktop dirent iterator knows how to iterate over all the volumes, 97 // integrated onto the desktop 98 99 Model sourceModel(ref, false, true); 100 if (sourceModel.InitCheck() != B_OK) 101 return NULL; 102 103 CachedEntryIteratorList *result = new DesktopEntryListCollection(); 104 105 ASSERT(!sourceModel.IsQuery()); 106 ASSERT(sourceModel.Node()); 107 BDirectory *sourceDirectory = dynamic_cast<BDirectory *>(sourceModel.Node()); 108 109 dev_t sourceDevice = sourceModel.NodeRef()->device; 110 111 ASSERT(sourceDirectory); 112 113 // build an iterator list, start with boot 114 EntryListBase *perDesktopIterator = new CachedDirectoryEntryList( 115 *sourceDirectory); 116 117 result->AddItem(perDesktopIterator); 118 if (nodeMonitoringTarget) { 119 TTracker::WatchNode(sourceModel.NodeRef(), 120 B_WATCH_DIRECTORY | B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR, 121 nodeMonitoringTarget); 122 } 123 124 // add the other volumes 125 126 BVolumeRoster roster; 127 roster.Rewind(); 128 BVolume volume; 129 while (roster.GetNextVolume(&volume) == B_OK) { 130 if (volume.Device() == sourceDevice) 131 // got that already 132 continue; 133 134 if (!DesktopPoseView::ShouldIntegrateDesktop(volume)) 135 continue; 136 137 BDirectory remoteDesktop; 138 if (FSGetDeskDir(&remoteDesktop, volume.Device()) < B_OK) 139 continue; 140 141 BDirectory root; 142 if (volume.GetRootDirectory(&root) == B_OK) { 143 perDesktopIterator = new CachedDirectoryEntryList(remoteDesktop); 144 result->AddItem(perDesktopIterator); 145 146 node_ref nodeRef; 147 remoteDesktop.GetNodeRef(&nodeRef); 148 149 if (nodeMonitoringTarget) { 150 TTracker::WatchNode(&nodeRef, 151 B_WATCH_DIRECTORY | B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR, 152 nodeMonitoringTarget); 153 } 154 } 155 } 156 157 if (result->Rewind() != B_OK) { 158 delete result; 159 if (nodeMonitoringTarget) 160 nodeMonitoringTarget->HideBarberPole(); 161 162 return NULL; 163 } 164 165 return result; 166 } 167 168 169 EntryListBase * 170 DesktopPoseView::InitDirentIterator(const entry_ref *ref) 171 { 172 return InitDesktopDirentIterator(this, ref); 173 } 174 175 176 bool 177 DesktopPoseView::FSNotification(const BMessage *message) 178 { 179 switch (message->FindInt32("opcode")) { 180 case B_DEVICE_MOUNTED: 181 { 182 dev_t device; 183 if (message->FindInt32("new device", &device) != B_OK) 184 break; 185 186 ASSERT(TargetModel()); 187 TrackerSettings settings; 188 189 BVolume volume(device); 190 if (volume.InitCheck() != B_OK) 191 break; 192 193 if (settings.MountVolumesOntoDesktop() 194 && (!volume.IsShared() || settings.MountSharedVolumesOntoDesktop())) { 195 // place an icon for the volume onto the desktop 196 CreateVolumePose(&volume, true); 197 } 198 199 if (!ShouldIntegrateDesktop(volume)) 200 break; 201 202 BDirectory otherDesktop; 203 BEntry entry; 204 if (FSGetDeskDir(&otherDesktop, volume.Device()) == B_OK 205 && otherDesktop.GetEntry(&entry) == B_OK) { 206 // place desktop items from the mounted volume onto the desktop 207 Model model(&entry); 208 if (model.InitCheck() == B_OK) 209 AddPoses(&model); 210 } 211 } 212 break; 213 } 214 215 return _inherited::FSNotification(message); 216 } 217 218 219 bool 220 DesktopPoseView::AddPosesThreadValid(const entry_ref *) const 221 { 222 return true; 223 } 224 225 226 bool 227 DesktopPoseView::ShouldShowPose(const Model *model, const PoseInfo *poseInfo) 228 { 229 ASSERT(TargetModel()); 230 if (!ShouldShowDesktopPose(TargetModel()->NodeRef()->device, model, poseInfo)) 231 return false; 232 233 return _inherited::ShouldShowPose(model, poseInfo); 234 } 235 236 237 bool 238 DesktopPoseView::Represents(const node_ref *ref) const 239 { 240 // When the Tracker is set up to integrate non-boot beos volumes, 241 // it represents the home/Desktop folders of all beos volumes 242 243 if (TrackerSettings().IntegrateNonBootBeOSDesktops()) { 244 BDirectory deviceDesktop; 245 FSGetDeskDir(&deviceDesktop, ref->device); 246 node_ref nref; 247 deviceDesktop.GetNodeRef(&nref); 248 return nref == *ref; 249 } 250 251 return _inherited::Represents(ref); 252 } 253 254 255 bool 256 DesktopPoseView::Represents(const entry_ref *ref) const 257 { 258 BEntry entry(ref); 259 node_ref nref; 260 entry.GetNodeRef(&nref); 261 return Represents(&nref); 262 } 263 264 265 void 266 DesktopPoseView::ShowVolumes(bool visible, bool showShared) 267 { 268 if (LockLooper()) { 269 SavePoseLocations(); 270 if (!visible) 271 RemoveRootPoses(); 272 else 273 AddRootPoses(true, showShared); 274 UnlockLooper(); 275 } 276 } 277 278 279 void 280 DesktopPoseView::RemoveNonBootItems() 281 { 282 AutoLock<BWindow> lock(Window()); 283 if (!lock) 284 return; 285 286 EachPoseAndModel(fPoseList, &RemoveNonBootDesktopModels, (BPoseView*)this, (dev_t)0); 287 } 288 289 290 void 291 DesktopPoseView::AddNonBootItems() 292 { 293 AutoLock<BWindow> lock(Window()); 294 if (!lock) 295 return; 296 297 BVolumeRoster volumeRoster; 298 299 BVolume boot; 300 volumeRoster.GetBootVolume(&boot); 301 302 BVolume volume; 303 while (volumeRoster.GetNextVolume(&volume) == B_OK) { 304 if (volume == boot || !ShouldIntegrateDesktop(volume)) 305 continue; 306 307 BDirectory otherDesktop; 308 BEntry entry; 309 310 if (FSGetDeskDir(&otherDesktop, volume.Device()) == B_OK 311 && otherDesktop.GetEntry(&entry) == B_OK) { 312 // place desktop items from the mounted volume onto the desktop 313 Model model(&entry); 314 if (model.InitCheck() == B_OK) 315 AddPoses(&model); 316 } 317 } 318 } 319 320 321 void 322 DesktopPoseView::StartSettingsWatch() 323 { 324 be_app->LockLooper(); 325 be_app->StartWatching(this, kShowDisksIconChanged); 326 be_app->StartWatching(this, kVolumesOnDesktopChanged); 327 be_app->StartWatching(this, kDesktopIntegrationChanged); 328 be_app->UnlockLooper(); 329 } 330 331 332 void 333 DesktopPoseView::StopSettingsWatch() 334 { 335 be_app->LockLooper(); 336 be_app->StopWatching(this, kShowDisksIconChanged); 337 be_app->StopWatching(this, kVolumesOnDesktopChanged); 338 be_app->StopWatching(this, kDesktopIntegrationChanged); 339 be_app->UnlockLooper(); 340 } 341 342 343 void 344 DesktopPoseView::AdaptToVolumeChange(BMessage *message) 345 { 346 TTracker *tracker = dynamic_cast<TTracker *>(be_app); 347 if (!tracker) 348 return; 349 350 bool showDisksIcon = false; 351 bool mountVolumesOnDesktop = true; 352 bool mountSharedVolumesOntoDesktop = false; 353 354 message->FindBool("ShowDisksIcon", &showDisksIcon); 355 message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); 356 message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); 357 358 BEntry entry("/"); 359 Model model(&entry); 360 if (model.InitCheck() == B_OK) { 361 BMessage entryMessage; 362 entryMessage.what = B_NODE_MONITOR; 363 364 if (showDisksIcon) 365 entryMessage.AddInt32("opcode", B_ENTRY_CREATED); 366 else { 367 entryMessage.AddInt32("opcode", B_ENTRY_REMOVED); 368 entry_ref ref; 369 if (entry.GetRef(&ref) == B_OK) { 370 BContainerWindow *disksWindow = tracker->FindContainerWindow(&ref); 371 if (disksWindow) { 372 disksWindow->Lock(); 373 disksWindow->Close(); 374 } 375 } 376 } 377 entryMessage.AddInt32("device", model.NodeRef()->device); 378 entryMessage.AddInt64("node", model.NodeRef()->node); 379 entryMessage.AddInt64("directory", model.EntryRef()->directory); 380 entryMessage.AddString("name", model.EntryRef()->name); 381 BContainerWindow *deskWindow = dynamic_cast<BContainerWindow*>(Window()); 382 if (deskWindow) 383 deskWindow->PostMessage(&entryMessage, deskWindow->PoseView()); 384 } 385 386 ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); 387 } 388 389 390 void 391 DesktopPoseView::AdaptToDesktopIntegrationChange(BMessage *message) 392 { 393 bool mountVolumesOnDesktop = true; 394 bool mountSharedVolumesOntoDesktop = true; 395 bool integrateNonBootBeOSDesktops = true; 396 397 message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); 398 message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); 399 message->FindBool("IntegrateNonBootBeOSDesktops", &integrateNonBootBeOSDesktops); 400 401 ShowVolumes(false, mountSharedVolumesOntoDesktop); 402 ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); 403 404 UpdateNonBootDesktopPoses(integrateNonBootBeOSDesktops); 405 } 406 407 408 void 409 DesktopPoseView::UpdateNonBootDesktopPoses(bool integrateNonBootBeOSDesktops) 410 { 411 static bool nonBootDesktopPosesAlreadyAdded = false; 412 413 BVolumeRoster volumeRoster; 414 BVolume bootVolume; 415 volumeRoster.GetBootVolume(&bootVolume); 416 417 dev_t bootDevice = bootVolume.Device(); 418 419 int32 poseCount = CountItems(); 420 421 if (!integrateNonBootBeOSDesktops) { 422 for (int32 index = 0; index < poseCount; index++) { 423 Model *model = PoseAtIndex(index)->TargetModel(); 424 if (!model->IsVolume() && model->NodeRef()->device != bootDevice){ 425 DeletePose(model->NodeRef()); 426 index--; 427 poseCount--; 428 } 429 } 430 nonBootDesktopPosesAlreadyAdded = false; 431 } else if (!nonBootDesktopPosesAlreadyAdded) { 432 for (int32 index = 0; index < poseCount; index++) { 433 Model *model = PoseAtIndex(index)->TargetModel(); 434 435 if (model->IsVolume()) { 436 BDirectory remoteDesktop; 437 BEntry entry; 438 BVolume volume(model->NodeRef()->device); 439 440 if (ShouldIntegrateDesktop(volume) 441 && FSGetDeskDir(&remoteDesktop, volume.Device()) == B_OK 442 && remoteDesktop.GetEntry(&entry) == B_OK 443 && volume != bootVolume) { 444 // place desktop items from the volume onto the desktop 445 Model model(&entry); 446 if (model.InitCheck() == B_OK) 447 AddPoses(&model); 448 } 449 } 450 } 451 nonBootDesktopPosesAlreadyAdded = true; 452 } 453 } 454 455