xref: /haiku/src/kits/tracker/DesktopPoseView.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 
41 #include "DesktopPoseView.h"
42 
43 #include <NodeMonitor.h>
44 #include <Path.h>
45 #include <Volume.h>
46 #include <VolumeRoster.h>
47 
48 #include "Commands.h"
49 #include "FSUtils.h"
50 #include "PoseList.h"
51 #include "Tracker.h"
52 #include "TrackerSettings.h"
53 #include "TrackerString.h"
54 
55 
56 //	#pragma mark - DesktopPoseView
57 
58 
59 DesktopPoseView::DesktopPoseView(Model* model, uint32 viewMode)
60 	:
61 	BPoseView(model, viewMode)
62 {
63 	SetFlags(Flags() | B_DRAW_ON_CHILDREN);
64 }
65 
66 
67 EntryListBase*
68 DesktopPoseView::InitDesktopDirentIterator(BPoseView* nodeMonitoringTarget,
69 	const entry_ref* ref)
70 {
71 	// the desktop dirent iterator knows how to iterate over all the volumes,
72 	// integrated onto the desktop
73 
74 	Model sourceModel(ref, false, true);
75 	if (sourceModel.InitCheck() != B_OK)
76 		return NULL;
77 
78 	CachedEntryIteratorList* result = new CachedEntryIteratorList();
79 
80 	ASSERT(!sourceModel.IsQuery());
81 	ASSERT(!sourceModel.IsVirtualDirectory());
82 	ASSERT(sourceModel.Node() != NULL);
83 
84 	BDirectory* sourceDirectory = dynamic_cast<BDirectory*>(sourceModel.Node());
85 	ThrowOnAssert(sourceDirectory != NULL);
86 
87 	// build an iterator list, start with boot
88 	EntryListBase* perDesktopIterator
89 		= new CachedDirectoryEntryList(*sourceDirectory);
90 
91 	result->AddItem(perDesktopIterator);
92 	if (nodeMonitoringTarget != NULL) {
93 		TTracker::WatchNode(sourceModel.NodeRef(),
94 			B_WATCH_DIRECTORY | B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR,
95 			nodeMonitoringTarget);
96 	}
97 
98 	if (result->Rewind() != B_OK) {
99 		delete result;
100 		if (nodeMonitoringTarget != NULL)
101 			nodeMonitoringTarget->HideBarberPole();
102 
103 		return NULL;
104 	}
105 
106 	return result;
107 }
108 
109 
110 EntryListBase*
111 DesktopPoseView::InitDirentIterator(const entry_ref* ref)
112 {
113 	return InitDesktopDirentIterator(this, ref);
114 }
115 
116 
117 bool
118 DesktopPoseView::FSNotification(const BMessage* message)
119 {
120 	switch (message->FindInt32("opcode")) {
121 		case B_DEVICE_MOUNTED:
122 		{
123 			dev_t device;
124 			if (message->FindInt32("new device", &device) != B_OK)
125 				break;
126 
127 			ASSERT(TargetModel());
128 			TrackerSettings settings;
129 
130 			BVolume volume(device);
131 			if (volume.InitCheck() != B_OK)
132 				break;
133 
134 			if (settings.MountVolumesOntoDesktop()
135 				&& (!volume.IsShared()
136 					|| settings.MountSharedVolumesOntoDesktop())) {
137 				// place an icon for the volume onto the desktop
138 				CreateVolumePose(&volume, true);
139 			}
140 		}
141 		break;
142 	}
143 
144 	return _inherited::FSNotification(message);
145 }
146 
147 
148 bool
149 DesktopPoseView::AddPosesThreadValid(const entry_ref*) const
150 {
151 	return true;
152 }
153 
154 
155 void
156 DesktopPoseView::AddPosesCompleted()
157 {
158 	_inherited::AddPosesCompleted();
159 	CreateTrashPose();
160 }
161 
162 
163 bool
164 DesktopPoseView::Represents(const node_ref* ref) const
165 {
166 	// When the Tracker is set up to integrate non-boot beos volumes,
167 	// it represents the home/Desktop folders of all beos volumes
168 
169 	return _inherited::Represents(ref);
170 }
171 
172 
173 bool
174 DesktopPoseView::Represents(const entry_ref* ref) const
175 {
176 	BEntry entry(ref);
177 	node_ref nref;
178 	entry.GetNodeRef(&nref);
179 	return Represents(&nref);
180 }
181 
182 
183 void
184 DesktopPoseView::ShowVolumes(bool visible, bool showShared)
185 {
186 	if (LockLooper()) {
187 		SavePoseLocations();
188 		if (!visible)
189 			RemoveRootPoses();
190 		else
191 			AddRootPoses(true, showShared);
192 
193 		UnlockLooper();
194 	}
195 }
196 
197 
198 void
199 DesktopPoseView::StartSettingsWatch()
200 {
201 	if (be_app->LockLooper()) {
202 		be_app->StartWatching(this, kShowDisksIconChanged);
203 		be_app->StartWatching(this, kVolumesOnDesktopChanged);
204 		be_app->StartWatching(this, kDesktopIntegrationChanged);
205 		be_app->UnlockLooper();
206 	}
207 }
208 
209 
210 void
211 DesktopPoseView::StopSettingsWatch()
212 {
213 	if (be_app->LockLooper()) {
214 		be_app->StopWatching(this, kShowDisksIconChanged);
215 		be_app->StopWatching(this, kVolumesOnDesktopChanged);
216 		be_app->StopWatching(this, kDesktopIntegrationChanged);
217 		be_app->UnlockLooper();
218 	}
219 }
220 
221 
222 void
223 DesktopPoseView::AdaptToVolumeChange(BMessage* message)
224 {
225 	TTracker* tracker = dynamic_cast<TTracker*>(be_app);
226 	ThrowOnAssert(tracker != NULL);
227 
228 	bool showDisksIcon = false;
229 	bool mountVolumesOnDesktop = true;
230 	bool mountSharedVolumesOntoDesktop = false;
231 
232 	message->FindBool("ShowDisksIcon", &showDisksIcon);
233 	message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop);
234 	message->FindBool("MountSharedVolumesOntoDesktop",
235 		&mountSharedVolumesOntoDesktop);
236 
237 	BEntry entry("/");
238 	Model model(&entry);
239 	if (model.InitCheck() == B_OK) {
240 		BMessage entryMessage;
241 		entryMessage.what = B_NODE_MONITOR;
242 
243 		if (showDisksIcon)
244 			entryMessage.AddInt32("opcode", B_ENTRY_CREATED);
245 		else {
246 			entryMessage.AddInt32("opcode", B_ENTRY_REMOVED);
247 			entry_ref ref;
248 			if (entry.GetRef(&ref) == B_OK) {
249 				BContainerWindow* disksWindow
250 					= tracker->FindContainerWindow(&ref);
251 				if (disksWindow != NULL) {
252 					disksWindow->Lock();
253 					disksWindow->Close();
254 				}
255 			}
256 		}
257 		entryMessage.AddInt32("device", model.NodeRef()->device);
258 		entryMessage.AddInt64("node", model.NodeRef()->node);
259 		entryMessage.AddInt64("directory", model.EntryRef()->directory);
260 		entryMessage.AddString("name", model.EntryRef()->name);
261 		BContainerWindow* deskWindow
262 			= dynamic_cast<BContainerWindow*>(Window());
263 		if (deskWindow != NULL)
264 			deskWindow->PostMessage(&entryMessage, deskWindow->PoseView());
265 	}
266 
267 	ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop);
268 }
269 
270 
271 void
272 DesktopPoseView::AdaptToDesktopIntegrationChange(BMessage* message)
273 {
274 	bool mountVolumesOnDesktop = true;
275 	bool mountSharedVolumesOntoDesktop = true;
276 
277 	message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop);
278 	message->FindBool("MountSharedVolumesOntoDesktop",
279 		&mountSharedVolumesOntoDesktop);
280 
281 	ShowVolumes(false, mountSharedVolumesOntoDesktop);
282 	ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop);
283 }
284 
285 
286 rgb_color
287 DesktopPoseView::TextColor(bool selected) const
288 {
289 	// The desktop color is chosen independently for the desktop.
290 	// The text color is chosen globally for all directories.
291 	// It's fairly easy to get something unreadable (even with the default
292 	// settings, it's expected that text will be black on white in Tracker
293 	// folders, but white on blue on the desktop).
294 	// So here we check if the colors are different enough, and otherwise,
295 	// force the text to be either white or black.
296 	rgb_color textColor = HighColor();
297 	rgb_color viewColor = ViewColor();
298 
299 	// The colors are different enough, we can use them as is
300 	if (rgb_color::Contrast(viewColor, textColor) > 127)
301 		return textColor;
302 
303 	return viewColor.IsLight() ? kBlack : kWhite;
304 }
305 
306 
307 rgb_color
308 DesktopPoseView::BackColor(bool selected) const
309 {
310 	// returns black or white color depending on the desktop background
311 	int32 thresh = 0;
312 	rgb_color color = LowColor();
313 
314 	if (color.red > 150)
315 		thresh++;
316 
317 	if (color.green > 150)
318 		thresh++;
319 
320 	if (color.blue > 150)
321 		thresh++;
322 
323 	if (thresh > 1) {
324 		color.red = 255;
325 		color.green = 255;
326 		color.blue = 255;
327 	} else {
328 		color.red = 0;
329 		color.green = 0;
330 		color.blue = 0;
331 	}
332 
333 	return color;
334 }
335