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