xref: /haiku/src/kits/interface/DecorInfo.cpp (revision bff26905875330ea486e316f9c4279556917bfb5)
1 /*
2  * Public domain source code.
3  *
4  * Author:
5  *		Joseph "looncraz" Groover <looncraz@satx.rr.com>
6  */
7 
8 
9 #include <DecorInfo.h>
10 
11 #include <new>
12 #include <stdio.h>
13 
14 #include <Autolock.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <Resources.h>
18 
19 #include <DecoratorPrivate.h>
20 
21 
22 namespace BPrivate {
23 
24 
25 DecorInfo::DecorInfo()
26 	:
27 	fVersion(0),
28 	fModificationTime(0),
29 	fInitStatus(B_NO_INIT)
30 {
31 }
32 
33 
34 DecorInfo::DecorInfo(const BString& path)
35 	:
36 	fPath(path),
37 	fVersion(0),
38 	fModificationTime(0),
39 	fInitStatus(B_NO_INIT)
40 {
41 	BEntry entry(path.String(), true);
42 	entry.GetRef(&fRef);
43 
44 	_Init();
45 }
46 
47 
48 DecorInfo::DecorInfo(const entry_ref& ref)
49 	:
50 	fRef(ref),
51 	fVersion(0),
52 	fModificationTime(0),
53 	fInitStatus(B_NO_INIT)
54 {
55 	BPath path(&ref);
56 	fPath = path.Path();
57 
58 	_Init();
59 }
60 
61 
62 DecorInfo::~DecorInfo()
63 {
64 }
65 
66 
67 status_t
68 DecorInfo::SetTo(const entry_ref& ref)
69 {
70 	Unset();
71 
72 	BPath path(&ref);
73 	fPath = path.Path();
74 	fRef = ref;
75 	_Init();
76 
77 	return InitCheck();
78 }
79 
80 
81 status_t
82 DecorInfo::SetTo(BString path)
83 {
84 	BEntry entry(path.String(), true);
85 	entry_ref ref;
86 	entry.GetRef(&ref);
87 	return SetTo(ref);
88 }
89 
90 
91 status_t
92 DecorInfo::InitCheck()	const
93 {
94 	return fInitStatus;
95 }
96 
97 
98 void
99 DecorInfo::Unset()
100 {
101 	fRef = entry_ref();
102 	fPath = "";
103 	fName = "";
104 	fAuthors = "";
105 	fShortDescription = "";
106 	fLicenseURL = "";
107 	fLicenseName = "";
108 	fSupportURL = "";
109 	fVersion = 0;
110 	fModificationTime = 0;
111 	fInitStatus = B_NO_INIT;
112 }
113 
114 
115 bool
116 DecorInfo::IsDefault() const
117 {
118 	return fInitStatus == B_OK && fPath == "Default";
119 }
120 
121 
122 BString
123 DecorInfo::Path() const
124 {
125 	return fPath;
126 }
127 
128 
129 const entry_ref*
130 DecorInfo::Ref() const
131 {
132 	if (InitCheck() != B_OK || IsDefault())
133 		return NULL;
134 	return &fRef;
135 }
136 
137 
138 BString
139 DecorInfo::Name() const
140 {
141 	return fName;
142 }
143 
144 
145 BString
146 DecorInfo::ShortcutName() const
147 {
148 	if (Ref())
149 		return fRef.name;
150 	return Name();
151 }
152 
153 
154 BString
155 DecorInfo::Authors() const
156 {
157 	return fAuthors;
158 }
159 
160 
161 BString
162 DecorInfo::ShortDescription() const
163 {
164 	return fShortDescription;
165 }
166 
167 
168 BString
169 DecorInfo::LongDescription() const
170 {
171 	return fLongDescription;
172 }
173 
174 
175 BString
176 DecorInfo::LicenseURL() const
177 {
178 	return fLicenseURL;
179 }
180 
181 
182 BString
183 DecorInfo::LicenseName() const
184 {
185 	return fLicenseName;
186 }
187 
188 
189 BString
190 DecorInfo::SupportURL() const
191 {
192 	return fSupportURL;
193 }
194 
195 
196 float
197 DecorInfo::Version() const
198 {
199 	return fVersion;
200 }
201 
202 
203 time_t
204 DecorInfo::ModificationTime() const
205 {
206 	return fModificationTime;
207 }
208 
209 
210 bool
211 DecorInfo::CheckForChanges(bool& deleted)
212 {
213 	if (InitCheck() != B_OK)
214 		return false;
215 
216 	BEntry entry(&fRef);
217 
218 	if (entry.InitCheck() != B_OK)
219 		return false;
220 
221 	if (!entry.Exists()) {
222 		deleted = true;
223 		return true;
224 	}
225 
226 	time_t modtime = 0;
227 	if (entry.GetModificationTime(&modtime) != B_OK) {
228 		fprintf(stderr, "DecorInfo::CheckForChanges()\tERROR: "
229 			"BEntry:GetModificationTime() failed\n");
230 		return false;
231 	}
232 
233 	if (fModificationTime != modtime) {
234 		_Init(true);
235 		return true;
236 	}
237 
238 	return false;
239 }
240 
241 
242 void
243 DecorInfo::_Init(bool isUpdate)
244 {
245 	if (!isUpdate && InitCheck() != B_NO_INIT) {
246 		// TODO: remove after validation
247 		fprintf(stderr, "DecorInfo::_Init()\tImproper init state\n");
248 		return;
249 	}
250 
251 	BEntry entry;
252 
253 	if (fPath == "Default") {
254 		if (isUpdate){
255 			// should never happen
256 			fprintf(stderr, "DecorInfo::_Init(true)\tBUG BUG updating default"
257 				"decorator!?!?!\n");
258 			return;
259 		}
260 
261 		fName = "Default";
262 		fAuthors = "DarkWyrm, Stephan Aßmus, Clemens Zeidler, Ingo Weinhold";
263 		fShortDescription = "Default Haiku window decorator.";
264 		fLongDescription = fShortDescription;
265 		fLicenseURL = "http://";
266 		fLicenseName = "MIT";
267 		fSupportURL = "http://www.haiku-os.org/";
268 		fVersion = 0.5;
269 		fInitStatus = B_OK;
270 
271 		// The following is to get the modification time of the app_server
272 		// and, thusly, the Default decorator...
273 		// If you can make it more simple, please do!
274 		BPath path;
275 		find_directory(B_SYSTEM_SERVERS_DIRECTORY, &path);
276 		path.Append("app_server");
277 		entry.SetTo(path.Path(), true);
278 		if (!entry.Exists()) {
279 			fprintf(stderr, "Server MIA the world has become its slave! "
280 				"Call the CIA!\n");
281 			return;
282 		}
283 
284 		entry.GetModificationTime(&fModificationTime);
285 		return;
286 	}
287 
288 	// Is a file system object...
289 
290 	entry.SetTo(&fRef, true);	// follow link
291 	if (entry.InitCheck() != B_OK) {
292 		fInitStatus = entry.InitCheck();
293 		return;
294 	}
295 
296 	if (!entry.Exists()) {
297 		if (isUpdate) {
298 			fprintf(stderr, "DecorInfo::_Init()\tERROR: decorator deleted"
299 					" after CheckForChanges() found it!\n");
300 			fprintf(stderr, "DecorInfo::_Init()\tERROR: DecorInfo will "
301 					"Unset\n");
302 			Unset();
303 		}
304 		return;
305 	}
306 
307 	// update fRef to match file system object
308 	entry.GetRef(&fRef);
309 	entry.GetModificationTime(&fModificationTime);
310 
311 	BResources resources(&fRef);
312 	if (resources.InitCheck() != B_OK) {
313 		fprintf(stderr, "DecorInfo::_Init()\t BResource InitCheck() failure\n");
314 		return;
315 	}
316 
317 	size_t infoSize = 0;
318 	const void* infoData = resources.LoadResource(B_MESSAGE_TYPE,
319 		"be:decor:info", &infoSize);
320 	BMessage infoMessage;
321 
322 	if (infoData == NULL || infoSize == 0
323 		|| infoMessage.Unflatten((const char*)infoData) != B_OK) {
324 		fprintf(stderr, "DecorInfo::_init()\tNo extended information found for"
325 			" \"%s\"\n", fRef.name);
326 	} else {
327 		infoMessage.FindString("name", &fName);
328 		infoMessage.FindString("authors", &fAuthors);
329 		infoMessage.FindString("short_descr", &fShortDescription);
330 		infoMessage.FindString("long_descr", &fLongDescription);
331 		infoMessage.FindString("lic_url", &fLicenseURL);
332 		infoMessage.FindString("lic_name", &fLicenseName);
333 		infoMessage.FindString("support_url", &fSupportURL);
334 		infoMessage.FindFloat ("version", &fVersion);
335 	}
336 
337 	fInitStatus = B_OK;
338 	fName = fRef.name;
339 }
340 
341 
342 // #pragma mark - DecorInfoUtility
343 
344 
345 DecorInfoUtility::DecorInfoUtility(bool scanNow)
346 	:
347 	fHasScanned(false)
348 {
349 	// get default decorator from app_server
350 	DecorInfo* info = new(std::nothrow) DecorInfo("Default");
351 	if (info == NULL || info->InitCheck() != B_OK)	{
352 		delete info;
353 		fprintf(stderr, "DecorInfoUtility::constructor\tdefault decorator's "
354 			"DecorInfo failed InitCheck()\n");
355 		return;
356 	}
357 
358 	fList.AddItem(info);
359 
360 	if (scanNow)
361 		ScanDecorators();
362 }
363 
364 
365 DecorInfoUtility::~DecorInfoUtility()
366 {
367 	BAutolock _(fLock);
368 	for	(int i = fList.CountItems() - 1; i >= 0; --i)
369 		delete fList.ItemAt(i);
370 }
371 
372 
373 status_t
374 DecorInfoUtility::ScanDecorators()
375 {
376 	status_t result;
377 
378 	BPath systemPath;
379 	result = find_directory(B_SYSTEM_ADDONS_DIRECTORY, &systemPath);
380 	if (result == B_OK)
381 		result = systemPath.Append("decorators");
382 
383 	if (result == B_OK) {
384 		BDirectory systemDirectory(systemPath.Path());
385 		result = systemDirectory.InitCheck();
386 		if (result == B_OK) {
387 			result = _ScanDecorators(systemDirectory);
388 			if (result != B_OK) {
389 				fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n",
390 					strerror(result));
391 				return result;
392 			}
393 		}
394 	}
395 
396 	BPath systemNonPackagedPath;
397 	result = find_directory(B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
398 		&systemNonPackagedPath);
399 	if (result == B_OK)
400 		result = systemNonPackagedPath.Append("decorators");
401 
402 	if (result == B_OK) {
403 		BDirectory systemNonPackagedDirectory(systemNonPackagedPath.Path());
404 		result = systemNonPackagedDirectory.InitCheck();
405 		if (result == B_OK) {
406 			result = _ScanDecorators(systemNonPackagedDirectory);
407 			if (result != B_OK) {
408 				fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n",
409 					strerror(result));
410 				return result;
411 			}
412 		}
413 	}
414 
415 	BPath userPath;
416 	result = find_directory(B_USER_ADDONS_DIRECTORY, &userPath);
417 	if (result == B_OK)
418 		result = userPath.Append("decorators");
419 
420 	if (result == B_OK) {
421 		BDirectory userDirectory(userPath.Path());
422 		result = userDirectory.InitCheck();
423 		if (result == B_OK) {
424 			result = _ScanDecorators(userDirectory);
425 			if (result != B_OK) {
426 				fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n",
427 					strerror(result));
428 				return result;
429 			}
430 		}
431 	}
432 
433 	BPath userNonPackagedPath;
434 	result = find_directory(B_USER_NONPACKAGED_ADDONS_DIRECTORY,
435 		&userNonPackagedPath);
436 	if (result == B_OK)
437 		result = userNonPackagedPath.Append("decorators");
438 
439 	if (result == B_OK) {
440 		BDirectory userNonPackagedDirectory(userNonPackagedPath.Path());
441 		result = userNonPackagedDirectory.InitCheck();
442 		if (result == B_OK) {
443 			result = _ScanDecorators(userNonPackagedDirectory);
444 			if (result != B_OK) {
445 				fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n",
446 					strerror(result));
447 				return result;
448 			}
449 		}
450 	}
451 
452 	fHasScanned = true;
453 
454 	return B_OK;
455 }
456 
457 
458 int32
459 DecorInfoUtility::CountDecorators()
460 {
461 	BAutolock _(fLock);
462 	if (!fHasScanned)
463 		ScanDecorators();
464 
465 	return fList.CountItems();
466 }
467 
468 
469 DecorInfo*
470 DecorInfoUtility::DecoratorAt(int32 index)
471 {
472 	BAutolock _(fLock);
473 	return fList.ItemAt(index);
474 }
475 
476 
477 DecorInfo*
478 DecorInfoUtility::FindDecorator(const BString& string)
479 {
480 	if (string.Length() == 0)
481 		return CurrentDecorator();
482 
483 	if (string.ICompare("default") == 0)
484 		return DefaultDecorator();
485 
486 	BAutolock _(fLock);
487 	if (!fHasScanned)
488 		ScanDecorators();
489 
490 	// search by path
491 	DecorInfo* decor = _FindDecor(string);
492 	if (decor != NULL)
493 		return decor;
494 
495 	// search by name or short cut name
496 	for (int i = 1; i < fList.CountItems(); ++i) {
497 		decor = fList.ItemAt(i);
498 		if (string.ICompare(decor->ShortcutName()) == 0
499 			|| string.ICompare(decor->Name()) == 0) {
500 			return decor;
501 		}
502 	}
503 
504 	return NULL;
505 }
506 
507 
508 DecorInfo*
509 DecorInfoUtility::CurrentDecorator()
510 {
511 	BAutolock _(fLock);
512 	if (!fHasScanned)
513 		ScanDecorators();
514 
515 	BString name;
516 	get_decorator(name);
517 	return FindDecorator(name);
518 }
519 
520 
521 DecorInfo*
522 DecorInfoUtility::DefaultDecorator()
523 {
524 	BAutolock _(fLock);
525 	return fList.ItemAt(0);
526 }
527 
528 
529 bool
530 DecorInfoUtility::IsCurrentDecorator(DecorInfo* decor)
531 {
532 	BAutolock _(fLock);
533 	if (decor == NULL)
534 		 return false;
535 	return decor->Path() == CurrentDecorator()->Path();
536 }
537 
538 
539 status_t
540 DecorInfoUtility::SetDecorator(DecorInfo* decor)
541 {
542 	if (decor == NULL)
543 		return B_BAD_VALUE;
544 
545 	BAutolock _(fLock);
546 	if (decor->IsDefault())
547 		return set_decorator("Default");
548 
549 	return set_decorator(decor->Path());
550 }
551 
552 
553 status_t
554 DecorInfoUtility::SetDecorator(int32 index)
555 {
556 	BAutolock _(fLock);
557 	if (!fHasScanned)
558 		return B_ERROR;
559 
560 	DecorInfo* decor = DecoratorAt(index);
561 	if (decor == NULL)
562 		return B_BAD_INDEX;
563 
564 	return SetDecorator(decor);
565 }
566 
567 
568 status_t
569 DecorInfoUtility::Preview(DecorInfo* decor, BWindow* window)
570 {
571 	if (decor == NULL)
572 		return B_BAD_VALUE;
573 
574 	return preview_decorator(decor->Path(), window);
575 }
576 
577 
578 // #pargma mark - private
579 
580 
581 DecorInfo*
582 DecorInfoUtility::_FindDecor(const BString& pathString)
583 {
584 	// find decor by path and path alone!
585 	if (!fLock.IsLocked()) {
586 		fprintf(stderr, "DecorInfoUtility::_find_decor()\tfailure to lock! - "
587 			"BUG BUG BUG\n");
588 		return NULL;
589 	}
590 
591 	if (pathString == "Default")
592 		return fList.ItemAt(0);
593 
594 	for (int i = 1; i < fList.CountItems(); ++i) {
595 		DecorInfo* decor = fList.ItemAt(i);
596 		// Find the DecoratorInfo either by its true current location or by
597 		// what we still think the location is (before we had a chance to
598 		// update). NOTE: This will only catch the case when the user moved the
599 		// folder in which the add-on file lives. It will not work when the user
600 		// moves the add-on file itself or renames it.
601 		BPath path(decor->Ref());
602 		if (path.Path() == pathString || decor->Path() == pathString)
603 			return decor;
604 	}
605 
606 	return NULL;
607 }
608 
609 
610 status_t
611 DecorInfoUtility::_ScanDecorators(BDirectory decoratorDirectory)
612 {
613 	BAutolock _(fLock);
614 
615 	// First, run through our list and DecorInfos CheckForChanges()
616 	if (fHasScanned) {
617 		for (int i = fList.CountItems() - 1; i > 0; --i) {
618 			DecorInfo* decorInfo = fList.ItemAt(i);
619 
620 			bool deleted = false;
621 			decorInfo->CheckForChanges(deleted);
622 
623 			if (deleted) {
624 				fList.RemoveItem(decorInfo);
625 				delete decorInfo;
626 			}
627 		}
628 	}
629 
630 	entry_ref ref;
631 	// Now, look at file system, skip the entries for which we already have
632 	// a DecorInfo in the list.
633 	while (decoratorDirectory.GetNextRef(&ref) == B_OK) {
634 		BPath path(&decoratorDirectory);
635 		status_t result = path.Append(ref.name);
636 		if (result != B_OK) {
637 			fprintf(stderr, "DecorInfoUtility::_ScanDecorators()\tFailed to"
638 				"append decorator file to path, skipping: %s.\n", strerror(result));
639 			continue;
640 		}
641 		if (_FindDecor(path.Path()) != NULL)
642 			continue;
643 
644 		DecorInfo* decorInfo = new(std::nothrow) DecorInfo(ref);
645 		if (decorInfo == NULL || decorInfo->InitCheck() != B_OK) {
646 			fprintf(stderr, "DecorInfoUtility::_ScanDecorators()\tInitCheck() "
647 				"failure on decorator, skipping.\n");
648 			delete decorInfo;
649 			continue;
650 		}
651 
652 		fList.AddItem(decorInfo);
653 	}
654 
655 	return B_OK;
656 }
657 
658 
659 }	// namespace BPrivate
660