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 if (!visible) 270 RemoveRootPoses(); 271 else 272 AddRootPoses(true, showShared); 273 UnlockLooper(); 274 } 275 } 276 277 278 void 279 DesktopPoseView::RemoveNonBootItems() 280 { 281 AutoLock<BWindow> lock(Window()); 282 if (!lock) 283 return; 284 285 EachPoseAndModel(fPoseList, &RemoveNonBootDesktopModels, (BPoseView*)this, (dev_t)0); 286 } 287 288 289 void 290 DesktopPoseView::AddNonBootItems() 291 { 292 AutoLock<BWindow> lock(Window()); 293 if (!lock) 294 return; 295 296 BVolumeRoster volumeRoster; 297 298 BVolume boot; 299 volumeRoster.GetBootVolume(&boot); 300 301 BVolume volume; 302 while (volumeRoster.GetNextVolume(&volume) == B_OK) { 303 if (volume == boot || !ShouldIntegrateDesktop(volume)) 304 continue; 305 306 BDirectory otherDesktop; 307 BEntry entry; 308 309 if (FSGetDeskDir(&otherDesktop, volume.Device()) == B_OK 310 && otherDesktop.GetEntry(&entry) == B_OK) { 311 // place desktop items from the mounted volume onto the desktop 312 Model model(&entry); 313 if (model.InitCheck() == B_OK) 314 AddPoses(&model); 315 } 316 } 317 } 318 319 320 void 321 DesktopPoseView::StartSettingsWatch() 322 { 323 be_app->LockLooper(); 324 be_app->StartWatching(this, kShowDisksIconChanged); 325 be_app->StartWatching(this, kVolumesOnDesktopChanged); 326 be_app->StartWatching(this, kDesktopIntegrationChanged); 327 be_app->UnlockLooper(); 328 } 329 330 331 void 332 DesktopPoseView::StopSettingsWatch() 333 { 334 be_app->LockLooper(); 335 be_app->StopWatching(this, kShowDisksIconChanged); 336 be_app->StopWatching(this, kVolumesOnDesktopChanged); 337 be_app->StopWatching(this, kDesktopIntegrationChanged); 338 be_app->UnlockLooper(); 339 } 340 341 342 void 343 DesktopPoseView::AdaptToVolumeChange(BMessage *message) 344 { 345 TTracker *tracker = dynamic_cast<TTracker *>(be_app); 346 if (!tracker) 347 return; 348 349 bool showDisksIcon = false; 350 bool mountVolumesOnDesktop = true; 351 bool mountSharedVolumesOntoDesktop = false; 352 353 message->FindBool("ShowDisksIcon", &showDisksIcon); 354 message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); 355 message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); 356 357 BEntry entry("/"); 358 Model model(&entry); 359 if (model.InitCheck() == B_OK) { 360 BMessage entryMessage; 361 entryMessage.what = B_NODE_MONITOR; 362 363 if (showDisksIcon) 364 entryMessage.AddInt32("opcode", B_ENTRY_CREATED); 365 else { 366 entryMessage.AddInt32("opcode", B_ENTRY_REMOVED); 367 entry_ref ref; 368 if (entry.GetRef(&ref) == B_OK) { 369 BContainerWindow *disksWindow = tracker->FindContainerWindow(&ref); 370 if (disksWindow) { 371 disksWindow->Lock(); 372 disksWindow->Close(); 373 } 374 } 375 } 376 entryMessage.AddInt32("device", model.NodeRef()->device); 377 entryMessage.AddInt64("node", model.NodeRef()->node); 378 entryMessage.AddInt64("directory", model.EntryRef()->directory); 379 entryMessage.AddString("name", model.EntryRef()->name); 380 BContainerWindow *deskWindow = dynamic_cast<BContainerWindow*>(Window()); 381 if (deskWindow) 382 deskWindow->PostMessage(&entryMessage, deskWindow->PoseView()); 383 } 384 385 ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); 386 } 387 388 389 void 390 DesktopPoseView::AdaptToDesktopIntegrationChange(BMessage *message) 391 { 392 bool mountVolumesOnDesktop = true; 393 bool mountSharedVolumesOntoDesktop = true; 394 bool integrateNonBootBeOSDesktops = true; 395 396 message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); 397 message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); 398 message->FindBool("IntegrateNonBootBeOSDesktops", &integrateNonBootBeOSDesktops); 399 400 ShowVolumes(false, mountSharedVolumesOntoDesktop); 401 ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); 402 403 UpdateNonBootDesktopPoses(integrateNonBootBeOSDesktops); 404 } 405 406 407 void 408 DesktopPoseView::UpdateNonBootDesktopPoses(bool integrateNonBootBeOSDesktops) 409 { 410 static bool nonBootDesktopPosesAlreadyAdded = false; 411 412 BVolumeRoster volumeRoster; 413 BVolume bootVolume; 414 volumeRoster.GetBootVolume(&bootVolume); 415 416 dev_t bootDevice = bootVolume.Device(); 417 418 int32 poseCount = CountItems(); 419 420 if (!integrateNonBootBeOSDesktops) { 421 for (int32 index = 0; index < poseCount; index++) { 422 Model *model = PoseAtIndex(index)->TargetModel(); 423 if (!model->IsVolume() && model->NodeRef()->device != bootDevice){ 424 DeletePose(model->NodeRef()); 425 index--; 426 poseCount--; 427 } 428 } 429 nonBootDesktopPosesAlreadyAdded = false; 430 } else if (!nonBootDesktopPosesAlreadyAdded) { 431 for (int32 index = 0; index < poseCount; index++) { 432 Model *model = PoseAtIndex(index)->TargetModel(); 433 434 if (model->IsVolume()) { 435 BDirectory remoteDesktop; 436 BEntry entry; 437 BVolume volume(model->NodeRef()->device); 438 439 if (ShouldIntegrateDesktop(volume) 440 && FSGetDeskDir(&remoteDesktop, volume.Device()) == B_OK 441 && remoteDesktop.GetEntry(&entry) == B_OK 442 && volume != bootVolume) { 443 // place desktop items from the volume onto the desktop 444 Model model(&entry); 445 if (model.InitCheck() == B_OK) 446 AddPoses(&model); 447 } 448 } 449 } 450 nonBootDesktopPosesAlreadyAdded = true; 451 } 452 } 453 454