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