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
DecorInfo()29 DecorInfo::DecorInfo()
30 :
31 fVersion(0),
32 fModificationTime(0),
33 fInitStatus(B_NO_INIT)
34 {
35 }
36
37
DecorInfo(const BString & path)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
DecorInfo(const entry_ref & ref)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
~DecorInfo()66 DecorInfo::~DecorInfo()
67 {
68 }
69
70
71 status_t
SetTo(const entry_ref & ref)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
SetTo(BString path)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
InitCheck() const96 DecorInfo::InitCheck() const
97 {
98 return fInitStatus;
99 }
100
101
102 void
Unset()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
IsDefault() const120 DecorInfo::IsDefault() const
121 {
122 return fPath == "Default";
123 }
124
125
126 BString
Path() const127 DecorInfo::Path() const
128 {
129 return fPath;
130 }
131
132
133 const entry_ref*
Ref() const134 DecorInfo::Ref() const
135 {
136 if (InitCheck() != B_OK || IsDefault())
137 return NULL;
138 return &fRef;
139 }
140
141
142 BString
Name() const143 DecorInfo::Name() const
144 {
145 return fName;
146 }
147
148
149 BString
ShortcutName() const150 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
Authors() const162 DecorInfo::Authors() const
163 {
164 return fAuthors;
165 }
166
167
168 BString
ShortDescription() const169 DecorInfo::ShortDescription() const
170 {
171 return fShortDescription;
172 }
173
174
175 BString
LongDescription() const176 DecorInfo::LongDescription() const
177 {
178 return fLongDescription;
179 }
180
181
182 BString
LicenseURL() const183 DecorInfo::LicenseURL() const
184 {
185 return fLicenseURL;
186 }
187
188
189 BString
LicenseName() const190 DecorInfo::LicenseName() const
191 {
192 return fLicenseName;
193 }
194
195
196 BString
SupportURL() const197 DecorInfo::SupportURL() const
198 {
199 return fSupportURL;
200 }
201
202
203 float
Version() const204 DecorInfo::Version() const
205 {
206 return fVersion;
207 }
208
209
210 time_t
ModificationTime() const211 DecorInfo::ModificationTime() const
212 {
213 return fModificationTime;
214 }
215
216
217 bool
CheckForChanges(bool & deleted)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
_Init(bool isUpdate)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
DecorInfoUtility(bool scanNow)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
~DecorInfoUtility()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
ScanDecorators()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
CountDecorators()470 DecorInfoUtility::CountDecorators()
471 {
472 BAutolock _(fLock);
473 if (!fHasScanned)
474 ScanDecorators();
475
476 return fList.CountItems();
477 }
478
479
480 DecorInfo*
DecoratorAt(int32 index)481 DecorInfoUtility::DecoratorAt(int32 index)
482 {
483 BAutolock _(fLock);
484 return fList.ItemAt(index);
485 }
486
487
488 DecorInfo*
FindDecorator(const BString & string)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*
CurrentDecorator()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*
DefaultDecorator()531 DecorInfoUtility::DefaultDecorator()
532 {
533 BAutolock _(fLock);
534 return fList.ItemAt(0);
535 }
536
537
538 bool
IsCurrentDecorator(DecorInfo * decor)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
SetDecorator(DecorInfo * decor)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
SetDecorator(int32 index)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
Preview(DecorInfo * decor,BWindow * window)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*
_FindDecor(const BString & pathString)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
_ScanDecorators(BDirectory decoratorDirectory)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