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