xref: /haiku/src/kits/tracker/DesktopPoseView.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
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