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