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