xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2005-2022 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Augustin Cavalier <waddlesplash>
7  *		DarkWyrm <bpmagic@columbus.rr.com>
8  *		René Gollent
9  *		John Scipione, jscipione@gmail.com
10  *		Wim van der Meer <WPJvanderMeer@gmail.com>
11  */
12 
13 
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <time.h>
17 #include <unistd.h>
18 
19 #include <algorithm>
20 #include <map>
21 #include <string>
22 
23 #include <AboutWindow.h>
24 #include <AppFileInfo.h>
25 #include <Application.h>
26 #include <Bitmap.h>
27 #include <ColorConversion.h>
28 #include <ControlLook.h>
29 #include <DateTimeFormat.h>
30 #include <Dragger.h>
31 #include <DurationFormat.h>
32 #include <File.h>
33 #include <FindDirectory.h>
34 #include <Font.h>
35 #include <fs_attr.h>
36 #include <LayoutBuilder.h>
37 #include <MessageRunner.h>
38 #include <Messenger.h>
39 #include <ObjectList.h>
40 #include <OS.h>
41 #include <Path.h>
42 #include <PathFinder.h>
43 #include <PopUpMenu.h>
44 #include <Resources.h>
45 #include <Screen.h>
46 #include <ScrollView.h>
47 #include <String.h>
48 #include <StringFormat.h>
49 #include <StringList.h>
50 #include <StringView.h>
51 #include <TextView.h>
52 #include <TranslationUtils.h>
53 #include <TranslatorFormats.h>
54 #include <View.h>
55 #include <ViewPrivate.h>
56 #include <Volume.h>
57 #include <VolumeRoster.h>
58 #include <Window.h>
59 #include <WindowPrivate.h>
60 
61 #include <AppMisc.h>
62 #include <AutoDeleter.h>
63 #include <AutoDeleterPosix.h>
64 #include <cpu_type.h>
65 #include <parsedate.h>
66 #include <system_revision.h>
67 
68 #include <Catalog.h>
69 #include <Language.h>
70 #include <Locale.h>
71 #include <LocaleRoster.h>
72 
73 #include "HyperTextActions.h"
74 #include "HyperTextView.h"
75 #include "Utilities.h"
76 
77 #include "Credits.h"
78 
79 
80 #ifndef LINE_MAX
81 #define LINE_MAX 2048
82 #endif
83 
84 
85 #undef B_TRANSLATION_CONTEXT
86 #define B_TRANSLATION_CONTEXT "AboutWindow"
87 
88 
89 static const char* kSignature = "application/x-vnd.Haiku-About";
90 
91 static const float kWindowWidth = 500.0f;
92 static const float kWindowHeight = 300.0f;
93 
94 static const float kSysInfoMinWidth = 163.0f;
95 static const float kSysInfoMinHeight = 193.0f;
96 
97 static const int32 kMsgScrollCreditsView = 'mviv';
98 
99 static int ignored_pages(system_info*);
100 static int max_pages(system_info*);
101 static int max_and_ignored_pages(system_info*);
102 static int used_pages(system_info*);
103 
104 static const rgb_color kIdealHaikuGreen = { 42, 131, 36, 255 };
105 static const rgb_color kIdealHaikuOrange = { 255, 69, 0, 255 };
106 static const rgb_color kIdealHaikuYellow = { 255, 176, 0, 255 };
107 static const rgb_color kIdealBeOSBlue = { 0, 0, 200, 255 };
108 static const rgb_color kIdealBeOSRed = { 200, 0, 0, 255 };
109 
110 static const char* kBSDTwoClause = B_TRANSLATE_MARK("BSD (2-clause)");
111 static const char* kBSDThreeClause = B_TRANSLATE_MARK("BSD (3-clause)");
112 static const char* kBSDFourClause = B_TRANSLATE_MARK("BSD (4-clause)");
113 static const char* kGPLv2 = B_TRANSLATE_MARK("GNU GPL v2");
114 static const char* kGPLv3 = B_TRANSLATE_MARK("GNU GPL v3");
115 static const char* kLGPLv2 = B_TRANSLATE_MARK("GNU LGPL v2");
116 static const char* kLGPLv21 = B_TRANSLATE_MARK("GNU LGPL v2.1");
117 #if 0
118 static const char* kPublicDomain = B_TRANSLATE_MARK("Public Domain");
119 #endif
120 #ifdef __i386__
121 static const char* kIntel2xxxFirmware = B_TRANSLATE_MARK("Intel (2xxx firmware)");
122 static const char* kIntelFirmware = B_TRANSLATE_MARK("Intel WiFi Firmware");
123 static const char* kMarvellFirmware = B_TRANSLATE_MARK("Marvell (firmware)");
124 static const char* kRalinkFirmware = B_TRANSLATE_MARK("Ralink WiFi Firmware");
125 #endif
126 
127 
128 //	#pragma mark - TranslationComparator function
129 
130 
131 static int
132 TranslationComparator(const void* left, const void* right)
133 {
134 	const Translation* leftTranslation = *(const Translation**)left;
135 	const Translation* rightTranslation = *(const Translation**)right;
136 
137 	BLanguage* language;
138 	BString leftName;
139 	if (BLocaleRoster::Default()->GetLanguage(leftTranslation->languageCode,
140 			&language) == B_OK) {
141 		language->GetName(leftName);
142 		delete language;
143 	} else
144 		leftName = leftTranslation->languageCode;
145 
146 	BString rightName;
147 	if (BLocaleRoster::Default()->GetLanguage(rightTranslation->languageCode,
148 			&language) == B_OK) {
149 		language->GetName(rightName);
150 		delete language;
151 	} else
152 		rightName = rightTranslation->languageCode;
153 
154 	BCollator collator;
155 	BLocale::Default()->GetCollator(&collator);
156 	return collator.Compare(leftName.String(), rightName.String());
157 }
158 
159 
160 //	#pragma mark - class definitions
161 
162 
163 class AboutApp : public BApplication {
164 public:
165 							AboutApp();
166 			void			MessageReceived(BMessage* message);
167 };
168 
169 
170 class AboutView;
171 
172 class AboutWindow : public BWindow {
173 public:
174 							AboutWindow();
175 
176 	virtual	bool			QuitRequested();
177 
178 			AboutView*		fAboutView;
179 };
180 
181 
182 class LogoView : public BView {
183 public:
184 							LogoView();
185 	virtual					~LogoView();
186 
187 	virtual	BSize			MinSize();
188 	virtual	BSize			MaxSize();
189 
190 	virtual void			Draw(BRect updateRect);
191 
192 private:
193 			BBitmap*		fLogo;
194 };
195 
196 
197 class CropView : public BView {
198 public:
199 							CropView(BView* target, int32 left, int32 top,
200 								int32 right, int32 bottom);
201 	virtual					~CropView();
202 
203 	virtual	BSize			MinSize();
204 	virtual	BSize			MaxSize();
205 
206 	virtual void			DoLayout();
207 
208 private:
209 			BView*			fTarget;
210 			int32			fCropLeft;
211 			int32			fCropTop;
212 			int32			fCropRight;
213 			int32			fCropBottom;
214 };
215 
216 
217 class SysInfoView : public BView {
218 public:
219 							SysInfoView();
220 							SysInfoView(BMessage* archive);
221 	virtual					~SysInfoView();
222 
223 	virtual	status_t		Archive(BMessage* archive, bool deep = true) const;
224 	static	BArchivable*	Instantiate(BMessage* archive);
225 
226 	virtual	void			AttachedToWindow();
227 	virtual	void			AllAttached();
228 	virtual	void			Draw(BRect);
229 	virtual void			MessageReceived(BMessage* message);
230 	virtual void			Pulse();
231 
232 			void			CacheInitialSize();
233 
234 			float			MinWidth() const { return fCachedMinWidth; };
235 			float			MinHeight() const { return fCachedMinHeight; };
236 
237 private:
238 			void			_AdjustColors();
239 			void			_AdjustTextColors() const;
240 			rgb_color		_DesktopTextColor(int32 workspace = -1) const;
241 			bool			_OnDesktop() const;
242 
243 			BStringView*	_CreateLabel(const char*, const char*);
244 			void			_UpdateLabel(BStringView*);
245 			BStringView*	_CreateSubtext(const char*, const char*);
246 			void			_UpdateSubtext(BStringView*);
247 			void			_UpdateText(BTextView*);
248 			void			_CreateDragger();
249 
250 			float			_BaseWidth();
251 			float			_BaseHeight();
252 
253 			const char*		_GetOSVersion();
254 			const char*		_GetRamSize(system_info*);
255 			const char*		_GetRamUsage(system_info*);
256 			const char*		_GetUptime();
257 
258 			float			_UptimeHeight();
259 
260 private:
261 			BString			fText;
262 			rgb_color		fDesktopTextColor;
263 
264 			BStringView*	fOSVersionView;
265 			BStringView*	fMemSizeView;
266 			BStringView*	fMemUsageView;
267 			BTextView*		fUptimeView;
268 
269 			BDragger*		fDragger;
270 
271 			float			fCachedBaseWidth;
272 			float			fCachedMinWidth;
273 			float			fCachedBaseHeight;
274 			float			fCachedMinHeight;
275 
276 			bool			fIsReplicant : 1;
277 
278 	static const uint8		kLabelCount = 5;
279 	static const uint8		kSubtextCount = 7;
280 };
281 
282 
283 class AboutView : public BView {
284 public:
285 							AboutView();
286 							~AboutView();
287 
288 	virtual void			AttachedToWindow();
289 	virtual void			Pulse();
290 	virtual void			MessageReceived(BMessage* message);
291 	virtual void			MouseDown(BPoint where);
292 
293 			void			AddCopyrightEntry(const char* name,
294 								const char* text,
295 								const StringVector& licenses,
296 								const StringVector& sources,
297 								const char* url);
298 			void			AddCopyrightEntry(const char* name,
299 								const char* text, const char* url = NULL);
300 			void			PickRandomHaiku();
301 
302 private:
303 	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
304 
305 			void			_CreateScrollRunner();
306 			LogoView*		_CreateLogoView();
307 			SysInfoView*	_CreateSysInfoView();
308 			CropView*		_CreateCreditsView();
309 			status_t		_GetLicensePath(const char* license,
310 								BPath& path);
311 			void			_AddCopyrightsFromAttribute();
312 			void			_AddPackageCredit(const PackageCredit& package);
313 			void			_AddPackageCreditEntries();
314 
315 
316 private:
317 			LogoView*		fLogoView;
318 			SysInfoView*	fSysInfoView;
319 			HyperTextView*	fCreditsView;
320 
321 			bigtime_t		fLastActionTime;
322 			BMessageRunner*	fScrollRunner;
323 
324 			float			fCachedMinWidth;
325 			float			fCachedMinHeight;
326 
327 			PackageCreditMap fPackageCredits;
328 
329 private:
330 			rgb_color		fTextColor;
331 			rgb_color		fLinkColor;
332 			rgb_color		fHaikuOrangeColor;
333 			rgb_color		fHaikuGreenColor;
334 			rgb_color		fHaikuYellowColor;
335 			rgb_color		fBeOSRedColor;
336 			rgb_color		fBeOSBlueColor;
337 };
338 
339 
340 //	#pragma mark - AboutApp
341 
342 
343 AboutApp::AboutApp()
344 	:
345 	BApplication(kSignature)
346 {
347 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("AboutSystem");
348 
349 	AboutWindow* window = new(std::nothrow) AboutWindow();
350 	if (window != NULL)
351 		window->Show();
352 }
353 
354 
355 void
356 AboutApp::MessageReceived(BMessage* message)
357 {
358 	switch (message->what) {
359 		case B_SILENT_RELAUNCH:
360 			WindowAt(0)->Activate();
361 			break;
362 	}
363 
364 	BApplication::MessageReceived(message);
365 }
366 
367 
368 //	#pragma mark - AboutWindow
369 
370 
371 AboutWindow::AboutWindow()
372 	:
373 	BWindow(BRect(0, 0, kWindowWidth, kWindowHeight),
374 		B_TRANSLATE("About this system"), B_TITLED_WINDOW,
375 		B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
376 {
377 	SetLayout(new BGroupLayout(B_VERTICAL, 0));
378 
379 	fAboutView = new AboutView();
380 	AddChild(fAboutView);
381 
382 	CenterOnScreen();
383 }
384 
385 
386 bool
387 AboutWindow::QuitRequested()
388 {
389 	be_app->PostMessage(B_QUIT_REQUESTED);
390 	return true;
391 }
392 
393 
394 #undef B_TRANSLATION_CONTEXT
395 #define B_TRANSLATION_CONTEXT "AboutView"
396 
397 
398 //	#pragma mark - LogoView
399 
400 
401 LogoView::LogoView()
402 	:
403 	BView("logo", B_WILL_DRAW),
404 	fLogo(BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png"))
405 {
406 	// Set view color to panel background color when fLogo is NULL
407 	// to prevent a white pixel from being drawn.
408 	if (fLogo != NULL)
409 		SetViewColor(255, 255, 255);
410 	else
411 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
412 }
413 
414 
415 LogoView::~LogoView()
416 {
417 	delete fLogo;
418 }
419 
420 
421 BSize
422 LogoView::MinSize()
423 {
424 	if (fLogo == NULL)
425 		return BSize(0, 0);
426 
427 	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
428 }
429 
430 
431 BSize
432 LogoView::MaxSize()
433 {
434 	if (fLogo == NULL)
435 		return BSize(0, 0);
436 
437 	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
438 }
439 
440 
441 void
442 LogoView::Draw(BRect updateRect)
443 {
444 	if (fLogo == NULL)
445 		return;
446 
447 	DrawBitmap(fLogo, BPoint((Bounds().Width() - fLogo->Bounds().Width()) / 2, 0));
448 }
449 
450 
451 //	#pragma mark - CropView
452 
453 
454 CropView::CropView(BView* target, int32 left, int32 top, int32 right,
455 	int32 bottom)
456 	:
457 	BView("crop view", 0),
458 	fTarget(target),
459 	fCropLeft(left),
460 	fCropTop(top),
461 	fCropRight(right),
462 	fCropBottom(bottom)
463 {
464 	AddChild(target);
465 }
466 
467 
468 CropView::~CropView()
469 {
470 }
471 
472 
473 BSize
474 CropView::MinSize()
475 {
476 	if (fTarget == NULL)
477 		return BSize();
478 
479 	BSize size = fTarget->MinSize();
480 	if (size.width != B_SIZE_UNSET)
481 		size.width -= fCropLeft + fCropRight;
482 	if (size.height != B_SIZE_UNSET)
483 		size.height -= fCropTop + fCropBottom;
484 
485 	return size;
486 }
487 
488 
489 BSize
490 CropView::MaxSize()
491 {
492 	if (fTarget == NULL)
493 		return BSize();
494 
495 	BSize size = fTarget->MaxSize();
496 	if (size.width != B_SIZE_UNSET)
497 		size.width -= fCropLeft + fCropRight;
498 	if (size.height != B_SIZE_UNSET)
499 		size.height -= fCropTop + fCropBottom;
500 
501 	return size;
502 }
503 
504 
505 void
506 CropView::DoLayout()
507 {
508 	BView::DoLayout();
509 
510 	if (fTarget == NULL)
511 		return;
512 
513 	fTarget->MoveTo(-fCropLeft, -fCropTop);
514 	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
515 		Bounds().Height() + fCropTop + fCropBottom);
516 }
517 
518 
519 //	#pragma mark - SysInfoView
520 
521 
522 SysInfoView::SysInfoView()
523 	:
524 	BView("AboutSystem", B_WILL_DRAW | B_PULSE_NEEDED),
525 	fOSVersionView(NULL),
526 	fMemSizeView(NULL),
527 	fMemUsageView(NULL),
528 	fUptimeView(NULL),
529 	fDragger(NULL),
530 	fCachedBaseWidth(kSysInfoMinWidth),
531 	fCachedMinWidth(kSysInfoMinWidth),
532 	fCachedBaseHeight(kSysInfoMinHeight),
533 	fCachedMinHeight(kSysInfoMinHeight),
534 	fIsReplicant(false)
535 {
536 	// Begin construction of system information controls.
537 	system_info sysInfo;
538 	get_system_info(&sysInfo);
539 
540 	// Create all the various labels for system infomation.
541 
542 	/* labels */
543 
544 	// OS Version
545 	BStringView* osLabel = _CreateLabel("oslabel", B_TRANSLATE("Version:"));
546 	fOSVersionView = _CreateSubtext("ostext", _GetOSVersion());
547 
548 	// CPU count
549 	static BStringFormat format(B_TRANSLATE_COMMENT(
550 		"{0, plural, one{Processor:} other{# Processors:}}",
551 		"\"Processor:\" or \"2 Processors:\""));
552 	BString processorLabel;
553 	format.Format(processorLabel, sysInfo.cpu_count);
554 	BStringView* cpuLabel = _CreateLabel("cpulabel", processorLabel.String());
555 
556 	// Memory
557 	BStringView* memoryLabel = _CreateLabel("memlabel", B_TRANSLATE("Memory:"));
558 
559 	// Kernel
560 	BStringView* kernelLabel = _CreateLabel("kernellabel", B_TRANSLATE("Kernel:"));
561 
562 	// Time running
563 	BStringView* uptimeLabel = _CreateLabel("uptimelabel", B_TRANSLATE("Time running:"));
564 
565 	// x86_gcc2 or x86_64
566 	BStringView* abiText = _CreateSubtext("abitext", B_HAIKU_ABI_NAME);
567 
568 	// CPU count, type and clock speed
569 	uint32 topologyNodeCount = 0;
570 	cpu_topology_node_info* topology = NULL;
571 	get_cpu_topology_info(NULL, &topologyNodeCount);
572 	if (topologyNodeCount != 0)
573 		topology = new cpu_topology_node_info[topologyNodeCount];
574 	get_cpu_topology_info(topology, &topologyNodeCount);
575 
576 	enum cpu_platform platform = B_CPU_UNKNOWN;
577 	enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
578 	uint32 cpuModel = 0;
579 	for (uint32 i = 0; i < topologyNodeCount; i++) {
580 		switch (topology[i].type) {
581 			case B_TOPOLOGY_ROOT:
582 				platform = topology[i].data.root.platform;
583 				break;
584 
585 			case B_TOPOLOGY_PACKAGE:
586 				cpuVendor = topology[i].data.package.vendor;
587 				break;
588 
589 			case B_TOPOLOGY_CORE:
590 				cpuModel = topology[i].data.core.model;
591 				break;
592 
593 			default:
594 				break;
595 		}
596 	}
597 
598 	delete[] topology;
599 
600 	BString cpuType;
601 	cpuType << get_cpu_vendor_string(cpuVendor) << " "
602 		<< get_cpu_model_string(platform, cpuVendor, cpuModel);
603 	BStringView* cpuText = _CreateSubtext("cputext", cpuType.String());
604 
605 	BString clockSpeed;
606 	int32 frequency = get_rounded_cpu_speed();
607 	if (frequency < 1000)
608 		clockSpeed.SetToFormat(B_TRANSLATE("%ld MHz"), frequency);
609 	else
610 		clockSpeed.SetToFormat(B_TRANSLATE("%.2f GHz"), frequency / 1000.0f);
611 
612 	BStringView* frequencyText = _CreateSubtext("frequencytext", clockSpeed);
613 
614 	// Memory size and usage
615 	fMemSizeView = _CreateSubtext("ramsizetext", _GetRamSize(&sysInfo));
616 	fMemUsageView = _CreateSubtext("ramusagetext", _GetRamUsage(&sysInfo));
617 
618 	// Kernel build time/date
619 	BString kernelTimeDate;
620 	kernelTimeDate << sysInfo.kernel_build_date << " "
621 		<< sysInfo.kernel_build_time;
622 	BString buildTimeDate;
623 
624 	time_t buildTimeDateStamp = parsedate(kernelTimeDate, -1);
625 	if (buildTimeDateStamp > 0) {
626 		if (BDateTimeFormat().Format(buildTimeDate, buildTimeDateStamp,
627 			B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT) != B_OK)
628 			buildTimeDate.SetTo(kernelTimeDate);
629 	} else
630 		buildTimeDate.SetTo(kernelTimeDate);
631 
632 	BStringView* kernelText = _CreateSubtext("kerneltext", buildTimeDate.String());
633 
634 	// Uptime
635 	fUptimeView = new BTextView("uptimetext");
636 	fUptimeView->SetText(_GetUptime());
637 	_UpdateText(fUptimeView);
638 
639 	/* layout */
640 
641 	const float offset = be_control_look->DefaultLabelSpacing();
642 	const float inset = offset;
643 
644 	SetLayout(new BGroupLayout(B_VERTICAL, 0));
645 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
646 		// Version:
647 		.Add(osLabel)
648 		.Add(fOSVersionView)
649 		.Add(abiText)
650 		.AddStrut(offset)
651 		// Processors:
652 		.Add(cpuLabel)
653 		.Add(cpuText)
654 		.Add(frequencyText)
655 		.AddStrut(offset)
656 		// Memory:
657 		.Add(memoryLabel)
658 		.Add(fMemSizeView)
659 		.Add(fMemUsageView)
660 		.AddStrut(offset)
661 		// Kernel:
662 		.Add(kernelLabel)
663 		.Add(kernelText)
664 		.AddStrut(offset)
665 		// Time running:
666 		.Add(uptimeLabel)
667 		.Add(fUptimeView)
668 		.AddGlue()
669 		.SetInsets(inset)
670 		.End();
671 
672 	_CreateDragger();
673 }
674 
675 
676 SysInfoView::SysInfoView(BMessage* archive)
677 	:
678 	BView(archive),
679 	fOSVersionView(NULL),
680 	fMemSizeView(NULL),
681 	fMemUsageView(NULL),
682 	fUptimeView(NULL),
683 	fDragger(NULL),
684 	fCachedBaseWidth(kSysInfoMinWidth),
685 	fCachedMinWidth(kSysInfoMinWidth),
686 	fCachedBaseHeight(kSysInfoMinHeight),
687 	fCachedMinHeight(kSysInfoMinHeight),
688 	fIsReplicant(true)
689 {
690 	BLayout* layout = GetLayout();
691 	int32 itemCount = layout->CountItems() - 1;
692 		// leave out dragger
693 
694 	for (int32 index = 0; index < itemCount; index++) {
695 		BView* view = layout->ItemAt(index)->View();
696 		if (view == NULL)
697 			continue;
698 
699 		BString name(view->Name());
700 		if (name == "uptimetext") {
701 			fUptimeView = dynamic_cast<BTextView*>(view);
702 			_UpdateText(fUptimeView);
703 		} else if (name.IEndsWith("text")) {
704 			_UpdateSubtext(dynamic_cast<BStringView*>(view));
705 			if (name == "ostext")
706 				fOSVersionView = dynamic_cast<BStringView*>(view);
707 			else if (name == "ramsizetext")
708 				fMemSizeView = dynamic_cast<BStringView*>(view);
709 			else if (name == "ramusagetext")
710 				fMemUsageView = dynamic_cast<BStringView*>(view);
711 		} else if (name.IEndsWith("label"))
712 			_UpdateLabel(dynamic_cast<BStringView*>(view));
713 	}
714 
715 	// This might have changed after an update/reboot cycle;
716 	fOSVersionView->SetText(_GetOSVersion());
717 
718 	fDragger = dynamic_cast<BDragger*>(ChildAt(0));
719 }
720 
721 
722 SysInfoView::~SysInfoView()
723 {
724 }
725 
726 
727 status_t
728 SysInfoView::Archive(BMessage* archive, bool deep) const
729 {
730 	// record inherited class members
731 	status_t result = BView::Archive(archive, deep);
732 
733 	// record app signature for replicant add-on loading
734 	if (result == B_OK)
735 		result = archive->AddString("add_on", kSignature);
736 
737 	// record class last
738 	if (result == B_OK)
739 		result = archive->AddString("class", "SysInfoView");
740 
741 	return result;
742 }
743 
744 
745 BArchivable*
746 SysInfoView::Instantiate(BMessage* archive)
747 {
748 	if (!validate_instantiation(archive, "SysInfoView"))
749 		return NULL;
750 
751 	return new SysInfoView(archive);
752 }
753 
754 
755 void
756 SysInfoView::AttachedToWindow()
757 {
758 	BView::AttachedToWindow();
759 
760 	Window()->SetPulseRate(500000);
761 	DoLayout();
762 }
763 
764 
765 void
766 SysInfoView::AllAttached()
767 {
768 	BView::AllAttached();
769 
770 	if (fIsReplicant) {
771 		CacheInitialSize();
772 			// if replicant the parent view doesn't do this for us
773 		fDesktopTextColor = _DesktopTextColor();
774 	}
775 
776 	// Update colors here to override system colors for replicant,
777 	// this works when the view is in AboutView too.
778 	_AdjustColors();
779 }
780 
781 
782 void
783 SysInfoView::CacheInitialSize()
784 {
785 	fCachedBaseWidth = _BaseWidth();
786 	// memory size is too wide in Greek, account for this here
787 	float insets = be_control_look->DefaultLabelSpacing() * 2;
788 	fCachedMinWidth = ceilf(std::max(fCachedBaseWidth,
789 		fMemSizeView->StringWidth(fMemSizeView->Text()) + insets));
790 
791 	// width is fixed, height can grow in Pulse()
792 	fCachedBaseHeight = _BaseHeight();
793 
794 	// determine initial line count using current font
795 	float lineCount = ceilf(be_plain_font->StringWidth(fUptimeView->Text())
796 		/ (fCachedMinWidth - insets));
797 	float uptimeHeight = fUptimeView->LineHeight(0) * lineCount;
798 	fCachedMinHeight = fCachedBaseHeight + uptimeHeight;
799 
800 	// set view size
801 	SetExplicitMinSize(BSize(fCachedMinWidth, B_SIZE_UNSET));
802 	SetExplicitMaxSize(BSize(fCachedMinWidth, fCachedMinHeight));
803 	fUptimeView->SetExplicitMaxSize(BSize(fCachedMinWidth - insets,
804 		uptimeHeight));
805 }
806 
807 
808 void
809 SysInfoView::Draw(BRect updateRect)
810 {
811 	BView::Draw(updateRect);
812 
813 	if (_OnDesktop()) {
814 		// stroke a line around the view
815 		SetHighColor(fDesktopTextColor);
816 		StrokeRect(Bounds());
817 	}
818 }
819 
820 
821 void
822 SysInfoView::MessageReceived(BMessage* message)
823 {
824 	switch (message->what) {
825 		case B_COLORS_UPDATED:
826 		{
827 			if (_OnDesktop())
828 				break;
829 
830 			if (message->HasColor(ui_color_name(B_PANEL_TEXT_COLOR))) {
831 				_AdjustTextColors();
832 				Invalidate();
833 			}
834 
835 			break;
836 		}
837 
838 		case B_WORKSPACE_ACTIVATED:
839 		{
840 			if (!_OnDesktop())
841 				break;
842 
843 			bool active;
844 			int32 workspace;
845 			if (message->FindBool("active", &active) == B_OK && active
846 				&& message->FindInt32("workspace", &workspace) == B_OK) {
847 				BLayout* layout = GetLayout();
848 				int32 itemCount = layout->CountItems() - 2;
849 					// leave out dragger and uptime
850 
851 				fDesktopTextColor = _DesktopTextColor(workspace);
852 				SetHighColor(fDesktopTextColor);
853 
854 				for (int32 index = 0; index < itemCount; index++) {
855 					BView* view = layout->ItemAt(index)->View();
856 					if (view == NULL)
857 						continue;
858 
859 					view->SetDrawingMode(B_OP_ALPHA);
860 					view->SetHighColor(fDesktopTextColor);
861 				}
862 
863 				fUptimeView->SetDrawingMode(B_OP_ALPHA);
864 				fUptimeView->SetFontAndColor(NULL, 0, &fDesktopTextColor);
865 
866 				Invalidate();
867 			}
868 
869 			break;
870 		}
871 
872 		default:
873 			BView::MessageReceived(message);
874 			break;
875 	}
876 }
877 
878 
879 void
880 SysInfoView::Pulse()
881 {
882 	system_info sysInfo;
883 	get_system_info(&sysInfo);
884 
885 	fMemUsageView->SetText(_GetRamUsage(&sysInfo));
886 	fUptimeView->SetText(_GetUptime());
887 
888 	float newHeight = fCachedBaseHeight + _UptimeHeight();
889 	float difference = newHeight - fCachedMinHeight;
890 	if (difference != 0) {
891 		if (_OnDesktop()) {
892 			// move view to keep the bottom in place
893 			// so that the dragger is not pushed off screen
894 			ResizeBy(0, difference);
895 			MoveBy(0, -difference);
896 			Invalidate();
897 		}
898 		fCachedMinHeight = newHeight;
899 	}
900 
901 	SetExplicitMinSize(BSize(fCachedMinWidth, B_SIZE_UNSET));
902 	SetExplicitMaxSize(BSize(fCachedMinWidth, fCachedMinHeight));
903 }
904 
905 
906 void
907 SysInfoView::_AdjustColors()
908 {
909 	if (_OnDesktop()) {
910 		// SetColor
911 		SetFlags(Flags() | B_TRANSPARENT_BACKGROUND);
912 		SetDrawingMode(B_OP_ALPHA);
913 
914 		SetViewColor(B_TRANSPARENT_COLOR);
915 		SetLowColor(B_TRANSPARENT_COLOR);
916 		SetHighColor(fDesktopTextColor);
917 	} else {
918 		// SetUIColor
919 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
920 		SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
921 		SetHighUIColor(B_PANEL_TEXT_COLOR);
922 	}
923 
924 	_AdjustTextColors();
925 	Invalidate();
926 }
927 
928 
929 void
930 SysInfoView::_AdjustTextColors() const
931 {
932 	BLayout* layout = GetLayout();
933 	int32 itemCount = layout->CountItems() - 2;
934 		// leave out dragger and uptime
935 
936 	if (_OnDesktop()) {
937 		// SetColor
938 		for (int32 index = 0; index < itemCount; index++) {
939 			BView* view = layout->ItemAt(index)->View();
940 			if (view == NULL)
941 				continue;
942 
943 			view->SetFlags(view->Flags() | B_TRANSPARENT_BACKGROUND);
944 			view->SetDrawingMode(B_OP_ALPHA);
945 
946 			view->SetViewColor(B_TRANSPARENT_COLOR);
947 			view->SetLowColor(blend_color(B_TRANSPARENT_COLOR,
948 				fDesktopTextColor, 192));
949 			view->SetHighColor(fDesktopTextColor);
950 		}
951 
952 		fUptimeView->SetFlags(fUptimeView->Flags() | B_TRANSPARENT_BACKGROUND);
953 		fUptimeView->SetDrawingMode(B_OP_ALPHA);
954 
955 		fUptimeView->SetViewColor(B_TRANSPARENT_COLOR);
956 		fUptimeView->SetLowColor(blend_color(B_TRANSPARENT_COLOR,
957 			fDesktopTextColor, 192));
958 		fUptimeView->SetFontAndColor(NULL, 0, &fDesktopTextColor);
959 	} else {
960 		// SetUIColor
961 		for (int32 index = 0; index < itemCount; index++) {
962 			BView* view = layout->ItemAt(index)->View();
963 			if (view == NULL)
964 				continue;
965 
966 			view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
967 			view->SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
968 			view->SetHighUIColor(B_PANEL_TEXT_COLOR);
969 		}
970 
971 		fUptimeView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
972 		fUptimeView->SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
973 		rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
974 		fUptimeView->SetFontAndColor(NULL, 0, &textColor);
975 	}
976 }
977 
978 
979 rgb_color
980 SysInfoView::_DesktopTextColor(int32 workspace) const
981 {
982 	// set text color to black or white depending on desktop background color
983 	rgb_color textColor;
984 	BScreen screen(Window());
985 	if (workspace < 0)
986 		workspace = current_workspace();
987 
988 	rgb_color viewColor = screen.DesktopColor(workspace);
989 	int viewBrightness = BPrivate::perceptual_brightness(viewColor);
990 	textColor.blue = textColor.green = textColor.red = viewBrightness > 127
991 		? 0 : 255;
992 	textColor.alpha = 255;
993 
994 	return textColor;
995 }
996 
997 
998 bool
999 SysInfoView::_OnDesktop() const
1000 {
1001 	return fIsReplicant && Window() != NULL
1002 		&& Window()->Look() == kDesktopWindowLook
1003 		&& Window()->Feel() == kDesktopWindowFeel;
1004 }
1005 
1006 
1007 BStringView*
1008 SysInfoView::_CreateLabel(const char* name, const char* text)
1009 {
1010 	BStringView* label = new BStringView(name, text);
1011 	_UpdateLabel(label);
1012 
1013 	return label;
1014 }
1015 
1016 
1017 void
1018 SysInfoView::_UpdateLabel(BStringView* label)
1019 {
1020 	label->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
1021 		B_ALIGN_VERTICAL_UNSET));
1022 	label->SetFont(be_bold_font, B_FONT_FAMILY_AND_STYLE);
1023 }
1024 
1025 
1026 BStringView*
1027 SysInfoView::_CreateSubtext(const char* name, const char* text)
1028 {
1029 	BStringView* subtext = new BStringView(name, text);
1030 	_UpdateSubtext(subtext);
1031 
1032 	return subtext;
1033 }
1034 
1035 
1036 void
1037 SysInfoView::_UpdateSubtext(BStringView* subtext)
1038 {
1039 	subtext->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
1040 		B_ALIGN_VERTICAL_UNSET));
1041 	subtext->SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE);
1042 }
1043 
1044 
1045 void
1046 SysInfoView::_UpdateText(BTextView* textView)
1047 {
1048 	textView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
1049 	textView->SetFontAndColor(be_plain_font, B_FONT_FAMILY_AND_STYLE);
1050 	textView->SetColorSpace(B_RGBA32);
1051 	textView->MakeResizable(false);
1052 	textView->MakeEditable(false);
1053 	textView->MakeSelectable(false);
1054 	textView->SetWordWrap(true);
1055 	textView->SetDoesUndo(false);
1056 	textView->SetInsets(0, 0, 0, 0);
1057 }
1058 
1059 
1060 void
1061 SysInfoView::_CreateDragger()
1062 {
1063 	// create replicant dragger and add it as the new child 0
1064 	fDragger = new BDragger(BRect(0, 0, 7, 7), this,
1065 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
1066 	BPopUpMenu* popUp = new BPopUpMenu("Shelf", false, false, B_ITEMS_IN_COLUMN);
1067 	popUp->AddItem(new BMenuItem(B_TRANSLATE("Remove replicant"),
1068 		new BMessage(kDeleteReplicant)));
1069 	fDragger->SetPopUp(popUp);
1070 	AddChild(fDragger, ChildAt(0));
1071 }
1072 
1073 
1074 float
1075 SysInfoView::_BaseWidth()
1076 {
1077 	// based on font size
1078 	return be_plain_font->StringWidth("M") * 24;
1079 }
1080 
1081 
1082 float
1083 SysInfoView::_BaseHeight()
1084 {
1085 	// based on line heights
1086 	font_height plainFH;
1087 	be_plain_font->GetHeight(&plainFH);
1088 	font_height boldFH;
1089 	be_bold_font->GetHeight(&boldFH);
1090 
1091 	return ceilf(((boldFH.ascent + boldFH.descent) * kLabelCount
1092 		+ (plainFH.ascent + plainFH.descent) * (kSubtextCount + 1) // extra for fUptimeView
1093 		+ be_control_look->DefaultLabelSpacing() * kLabelCount));
1094 }
1095 
1096 
1097 const char*
1098 SysInfoView::_GetOSVersion()
1099 {
1100 	BString osVersion;
1101 
1102 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
1103 	BPath path;
1104 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
1105 		path.Append("libbe.so");
1106 
1107 		BAppFileInfo appFileInfo;
1108 		version_info versionInfo;
1109 		BFile file;
1110 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
1111 			&& appFileInfo.SetTo(&file) == B_OK
1112 			&& appFileInfo.GetVersionInfo(&versionInfo,
1113 				B_APP_VERSION_KIND) == B_OK
1114 			&& versionInfo.short_info[0] != '\0')
1115 			osVersion = versionInfo.short_info;
1116 	}
1117 
1118 	if (osVersion.IsEmpty())
1119 		osVersion = B_TRANSLATE("Unknown");
1120 
1121 	// add system revision to os version
1122 	const char* hrev = __get_haiku_revision();
1123 	if (hrev != NULL)
1124 		osVersion << " (" << B_TRANSLATE("Revision") << " " << hrev << ")";
1125 
1126 	return osVersion.String();
1127 }
1128 
1129 
1130 const char*
1131 SysInfoView::_GetRamSize(system_info* sysInfo)
1132 {
1133 	int inaccessibleMemory = ignored_pages(sysInfo);
1134 
1135 	if (inaccessibleMemory <= 0)
1136 		fText.SetToFormat(B_TRANSLATE("%d MiB total"), max_pages(sysInfo));
1137 	else {
1138 		BString temp;
1139 		fText = B_TRANSLATE("%total MiB total, %inaccessible MiB inaccessible");
1140 		temp << max_and_ignored_pages(sysInfo);
1141 		fText.ReplaceFirst("%total", temp);
1142 		temp.SetTo("");
1143 		temp << inaccessibleMemory;
1144 		fText.ReplaceFirst("%inaccessible", temp);
1145 	}
1146 
1147 	return fText.String();
1148 }
1149 
1150 
1151 const char*
1152 SysInfoView::_GetRamUsage(system_info* sysInfo)
1153 {
1154 	fText.SetToFormat(B_TRANSLATE("%d MiB used (%d%%)"), used_pages(sysInfo),
1155 		(int)(100 * sysInfo->used_pages / sysInfo->max_pages));
1156 
1157 	return fText.String();
1158 }
1159 
1160 
1161 const char*
1162 SysInfoView::_GetUptime()
1163 {
1164 	BDurationFormat formatter;
1165 	BString uptimeText;
1166 
1167 	bigtime_t uptime = system_time();
1168 	bigtime_t now = (bigtime_t)time(NULL) * 1000000;
1169 	formatter.Format(uptimeText, now - uptime, now);
1170 
1171 	return uptimeText.String();
1172 }
1173 
1174 
1175 float
1176 SysInfoView::_UptimeHeight()
1177 {
1178 	return fUptimeView->LineHeight(0) * fUptimeView->CountLines();
1179 }
1180 
1181 
1182 //	#pragma mark - AboutView
1183 
1184 
1185 AboutView::AboutView()
1186 	:
1187 	BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
1188 	fLogoView(NULL),
1189 	fSysInfoView(NULL),
1190 	fCreditsView(NULL),
1191 	fLastActionTime(system_time()),
1192 	fScrollRunner(NULL),
1193 	fCachedMinWidth(kSysInfoMinWidth),
1194 	fCachedMinHeight(kSysInfoMinHeight)
1195 {
1196 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1197 
1198 	// Assign the colors, sadly this does not respect live color updates
1199 	fTextColor = ui_color(B_DOCUMENT_TEXT_COLOR);
1200 	fLinkColor = ui_color(B_LINK_TEXT_COLOR);
1201 	fHaikuOrangeColor = mix_color(fTextColor, kIdealHaikuOrange, 191);
1202 	fHaikuGreenColor = mix_color(fTextColor, kIdealHaikuGreen, 191);
1203 	fHaikuYellowColor = mix_color(fTextColor, kIdealHaikuYellow, 191);
1204 	fBeOSRedColor = mix_color(fTextColor, kIdealBeOSRed, 191);
1205 	fBeOSBlueColor = mix_color(fTextColor, kIdealBeOSBlue, 191);
1206 
1207 	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
1208 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
1209 		.AddGroup(B_VERTICAL, 0)
1210 			.Add(_CreateLogoView())
1211 			.Add(_CreateSysInfoView())
1212 			.AddGlue()
1213 			.End()
1214 		.Add(_CreateCreditsView())
1215 		.End();
1216 }
1217 
1218 
1219 AboutView::~AboutView()
1220 {
1221 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1222 		it != fPackageCredits.end(); it++) {
1223 
1224 		delete it->second;
1225 	}
1226 
1227 	delete fScrollRunner;
1228 	delete fCreditsView;
1229 	delete fSysInfoView;
1230 	delete fLogoView;
1231 }
1232 
1233 
1234 void
1235 AboutView::AttachedToWindow()
1236 {
1237 	BView::AttachedToWindow();
1238 
1239 	fSysInfoView->CacheInitialSize();
1240 
1241 	float insets = be_control_look->DefaultLabelSpacing() * 2;
1242 	float infoWidth = fSysInfoView->MinWidth() + insets;
1243 	float creditsWidth = roundf(infoWidth * 1.25f);
1244 	fCachedMinWidth = std::max(infoWidth + creditsWidth,
1245 		fCachedMinWidth);
1246 		// set once
1247 	float logoViewHeight = fLogoView->Bounds().Height();
1248 	float sysInfoViewHeight = fSysInfoView->MinHeight() + insets;
1249 	fCachedMinHeight = std::max(logoViewHeight + sysInfoViewHeight,
1250 		fCachedMinHeight);
1251 		// updated when height changes in pulse
1252 	fCreditsView->SetExplicitMinSize(BSize(creditsWidth, fCachedMinHeight));
1253 		// set credits min height to logo height + sys-info height
1254 
1255 	SetEventMask(B_POINTER_EVENTS);
1256 	DoLayout();
1257 }
1258 
1259 
1260 void
1261 AboutView::MouseDown(BPoint where)
1262 {
1263 	BRect rect(92, 26, 105, 31);
1264 	if (rect.Contains(where))
1265 		BMessenger(this).SendMessage('eegg');
1266 
1267 	if (Bounds().Contains(where)) {
1268 		fLastActionTime = system_time();
1269 		delete fScrollRunner;
1270 		fScrollRunner = NULL;
1271 	}
1272 }
1273 
1274 
1275 void
1276 AboutView::Pulse()
1277 {
1278 	// sys-info handles height because it may be a replicant
1279 	float insets = be_control_look->DefaultLabelSpacing() * 2;
1280 	float logoViewHeight = fLogoView->Bounds().Height();
1281 	float sysInfoViewHeight = fSysInfoView->MinHeight() + insets;
1282 	float newHeight = logoViewHeight + sysInfoViewHeight;
1283 	if (newHeight != fCachedMinHeight) {
1284 		fCreditsView->SetExplicitMinSize(BSize(
1285 			fCachedMinWidth - (fSysInfoView->MinWidth() + insets), newHeight));
1286 		fCachedMinHeight = newHeight;
1287 	}
1288 
1289 	if (fScrollRunner == NULL && system_time() > fLastActionTime + 10000000)
1290 		_CreateScrollRunner();
1291 }
1292 
1293 
1294 void
1295 AboutView::MessageReceived(BMessage* message)
1296 {
1297 	switch (message->what) {
1298 		case kMsgScrollCreditsView:
1299 		{
1300 			BScrollBar* scrollBar = fCreditsView->ScrollBar(B_VERTICAL);
1301 			if (scrollBar == NULL)
1302 				break;
1303 			float min;
1304 			float max;
1305 			scrollBar->GetRange(&min, &max);
1306 			if (scrollBar->Value() < max)
1307 				fCreditsView->ScrollBy(0, 1);
1308 
1309 			break;
1310 		}
1311 
1312 		case 'eegg':
1313 		{
1314 			printf("Easter egg\n");
1315 			PickRandomHaiku();
1316 			break;
1317 		}
1318 
1319 		default:
1320 			BView::MessageReceived(message);
1321 			break;
1322 	}
1323 }
1324 
1325 
1326 void
1327 AboutView::AddCopyrightEntry(const char* name, const char* text,
1328 	const char* url)
1329 {
1330 	AddCopyrightEntry(name, text, StringVector(), StringVector(), url);
1331 }
1332 
1333 
1334 void
1335 AboutView::AddCopyrightEntry(const char* name, const char* text,
1336 	const StringVector& licenses, const StringVector& sources,
1337 	const char* url)
1338 {
1339 	BFont font(be_bold_font);
1340 	//font.SetSize(be_bold_font->Size());
1341 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1342 
1343 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuYellowColor);
1344 	fCreditsView->Insert(name);
1345 	fCreditsView->Insert("\n");
1346 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1347 	fCreditsView->Insert(text);
1348 	fCreditsView->Insert("\n");
1349 
1350 	if (licenses.CountStrings() > 0) {
1351 		if (licenses.CountStrings() > 1)
1352 			fCreditsView->Insert(B_TRANSLATE("Licenses: "));
1353 		else
1354 			fCreditsView->Insert(B_TRANSLATE("License: "));
1355 
1356 		for (int32 i = 0; i < licenses.CountStrings(); i++) {
1357 			const char* license = licenses.StringAt(i);
1358 
1359 			if (i > 0)
1360 				fCreditsView->Insert(", ");
1361 
1362 			BString licenseName;
1363 			BString licenseURL;
1364 			parse_named_url(license, licenseName, licenseURL);
1365 
1366 			BPath licensePath;
1367 			if (_GetLicensePath(licenseURL, licensePath) == B_OK) {
1368 				fCreditsView->InsertHyperText(B_TRANSLATE_NOCOLLECT(licenseName),
1369 					new OpenFileAction(licensePath.Path()));
1370 			} else
1371 				fCreditsView->Insert(licenseName);
1372 		}
1373 
1374 		fCreditsView->Insert("\n");
1375 	}
1376 
1377 	if (sources.CountStrings() > 0) {
1378 		fCreditsView->Insert(B_TRANSLATE("Source Code: "));
1379 
1380 		for (int32 i = 0; i < sources.CountStrings(); i++) {
1381 			const char* source = sources.StringAt(i);
1382 
1383 			if (i > 0)
1384 				fCreditsView->Insert(", ");
1385 
1386 			BString urlName;
1387 			BString urlAddress;
1388 			parse_named_url(source, urlName, urlAddress);
1389 
1390 			fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
1391 				&fLinkColor);
1392 			fCreditsView->InsertHyperText(urlName,
1393 				new URLAction(urlAddress));
1394 		}
1395 
1396 		fCreditsView->Insert("\n");
1397 	}
1398 
1399 	if (url) {
1400 		BString urlName;
1401 		BString urlAddress;
1402 		parse_named_url(url, urlName, urlAddress);
1403 
1404 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
1405 			&fLinkColor);
1406 		fCreditsView->InsertHyperText(urlName,
1407 			new URLAction(urlAddress));
1408 		fCreditsView->Insert("\n");
1409 	}
1410 	fCreditsView->Insert("\n");
1411 }
1412 
1413 
1414 void
1415 AboutView::PickRandomHaiku()
1416 {
1417 	BPath path;
1418 	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
1419 		path = "/system/data";
1420 	path.Append("fortunes");
1421 	path.Append("Haiku");
1422 
1423 	BFile fortunes(path.Path(), B_READ_ONLY);
1424 	struct stat st;
1425 	if (fortunes.InitCheck() < B_OK)
1426 		return;
1427 	if (fortunes.GetStat(&st) < B_OK)
1428 		return;
1429 
1430 	char* buff = (char*)malloc((size_t)st.st_size + 1);
1431 	if (buff == NULL)
1432 		return;
1433 
1434 	buff[(size_t)st.st_size] = '\0';
1435 	BList haikuList;
1436 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
1437 		char* p = buff;
1438 		while (p && *p) {
1439 			char* e = strchr(p, '%');
1440 			BString* s = new BString(p, e ? (e - p) : -1);
1441 			haikuList.AddItem(s);
1442 			p = e;
1443 			if (p && (*p == '%'))
1444 				p++;
1445 			if (p && (*p == '\n'))
1446 				p++;
1447 		}
1448 	}
1449 	free(buff);
1450 
1451 	if (haikuList.CountItems() < 1)
1452 		return;
1453 
1454 	BString* s = (BString*)haikuList.ItemAt(rand() % haikuList.CountItems());
1455 	BFont font(be_bold_font);
1456 	font.SetSize(be_bold_font->Size());
1457 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1458 	fCreditsView->SelectAll();
1459 	fCreditsView->Delete();
1460 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fTextColor);
1461 	fCreditsView->Insert(s->String());
1462 	fCreditsView->Insert("\n");
1463 	while ((s = (BString*)haikuList.RemoveItem((int32)0)))
1464 		delete s;
1465 }
1466 
1467 
1468 void
1469 AboutView::_CreateScrollRunner()
1470 {
1471 #if 0
1472 	BMessage scroll(kMsgScrollCreditsView);
1473 	fScrollRunner = new(std::nothrow) BMessageRunner(this, &scroll, 25000, -1);
1474 #endif
1475 }
1476 
1477 
1478 LogoView*
1479 AboutView::_CreateLogoView()
1480 {
1481 	fLogoView = new(std::nothrow) LogoView();
1482 
1483 	return fLogoView;
1484 }
1485 
1486 
1487 SysInfoView*
1488 AboutView::_CreateSysInfoView()
1489 {
1490 	fSysInfoView = new(std::nothrow) SysInfoView();
1491 
1492 	return fSysInfoView;
1493 }
1494 
1495 
1496 CropView*
1497 AboutView::_CreateCreditsView()
1498 {
1499 	// Begin construction of the credits view
1500 	fCreditsView = new HyperTextView("credits");
1501 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
1502 	fCreditsView->SetStylable(true);
1503 	fCreditsView->MakeEditable(false);
1504 	fCreditsView->SetWordWrap(true);
1505 	fCreditsView->SetInsets(5, 5, 5, 5);
1506 	fCreditsView->SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
1507 
1508 	BScrollView* creditsScroller = new BScrollView("creditsScroller",
1509 		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
1510 		B_PLAIN_BORDER);
1511 
1512 	// Haiku copyright
1513 	BFont font(be_bold_font);
1514 	font.SetSize(font.Size() + 4);
1515 
1516 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1517 	fCreditsView->Insert("Haiku\n");
1518 
1519 	time_t time = ::time(NULL);
1520 	struct tm* tm = localtime(&time);
1521 	int32 year = tm->tm_year + 1900;
1522 	if (year < 2008)
1523 		year = 2008;
1524 	BString text;
1525 	text.SetToFormat(
1526 		B_TRANSLATE(COPYRIGHT_STRING "2001-%" B_PRId32 " The Haiku project. "),
1527 		year);
1528 
1529 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1530 	fCreditsView->Insert(text.String());
1531 
1532 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1533 	fCreditsView->Insert(B_TRANSLATE("The copyright to the Haiku code is "
1534 		"property of Haiku, Inc. or of the respective authors where expressly "
1535 		"noted in the source. Haiku" B_UTF8_REGISTERED
1536 		" and the HAIKU logo" B_UTF8_REGISTERED
1537 		" are registered trademarks of Haiku, Inc."
1538 		"\n\n"));
1539 
1540 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1541 	fCreditsView->InsertHyperText("https://www.haiku-os.org",
1542 		new URLAction("https://www.haiku-os.org"));
1543 	fCreditsView->Insert("\n\n");
1544 
1545 	font.SetSize(be_bold_font->Size());
1546 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1547 
1548 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1549 	fCreditsView->Insert(B_TRANSLATE("Current maintainers:\n"));
1550 
1551 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1552 	fCreditsView->Insert(kCurrentMaintainers);
1553 
1554 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1555 	fCreditsView->Insert(B_TRANSLATE("Past maintainers:\n"));
1556 
1557 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1558 	fCreditsView->Insert(kPastMaintainers);
1559 
1560 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1561 	fCreditsView->Insert(B_TRANSLATE("Website & marketing:\n"));
1562 
1563 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1564 	fCreditsView->Insert(kWebsiteTeam);
1565 
1566 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1567 	fCreditsView->Insert(B_TRANSLATE("Past website & marketing:\n"));
1568 
1569 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1570 	fCreditsView->Insert(kPastWebsiteTeam);
1571 
1572 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1573 	fCreditsView->Insert(B_TRANSLATE("Testing and bug triaging:\n"));
1574 
1575 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1576 	fCreditsView->Insert(kTestingTeam);
1577 
1578 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1579 	fCreditsView->Insert(B_TRANSLATE("Contributors:\n"));
1580 
1581 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1582 	fCreditsView->Insert(kContributors);
1583 	fCreditsView->Insert(
1584 		B_TRANSLATE("\n" B_UTF8_ELLIPSIS
1585 			"and probably some more we forgot to mention (sorry!)"
1586 			"\n\n"));
1587 
1588 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1589 	fCreditsView->Insert(B_TRANSLATE("Translations:\n"));
1590 
1591 	BLanguage* lang;
1592 	BString langName;
1593 
1594 	BList sortedTranslations;
1595 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1596 		const Translation* translation = &kTranslations[i];
1597 		sortedTranslations.AddItem((void*)translation);
1598 	}
1599 	sortedTranslations.SortItems(TranslationComparator);
1600 
1601 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1602 		const Translation& translation
1603 			= *(const Translation*)sortedTranslations.ItemAt(i);
1604 
1605 		langName.Truncate(0);
1606 		if (BLocaleRoster::Default()->GetLanguage(translation.languageCode,
1607 				&lang) == B_OK) {
1608 			lang->GetName(langName);
1609 			delete lang;
1610 		} else {
1611 			// We failed to get the localized readable name,
1612 			// go with what we have.
1613 			langName.Append(translation.languageCode);
1614 		}
1615 
1616 		fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1617 		fCreditsView->Insert("\n");
1618 		fCreditsView->Insert(langName);
1619 		fCreditsView->Insert("\n");
1620 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1621 		fCreditsView->Insert(translation.names);
1622 	}
1623 
1624 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1625 	fCreditsView->Insert(B_TRANSLATE("\n\nSpecial thanks to:\n"));
1626 
1627 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1628 	BString beosCredits(B_TRANSLATE(
1629 		"Be Inc. and its developer team, for having created BeOS!\n\n"));
1630 	int32 beosOffset = beosCredits.FindFirst("BeOS");
1631 	fCreditsView->Insert(beosCredits.String(),
1632 		(beosOffset < 0) ? beosCredits.Length() : beosOffset);
1633 	if (beosOffset > -1) {
1634 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fBeOSBlueColor);
1635 		fCreditsView->Insert("B");
1636 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fBeOSRedColor);
1637 		fCreditsView->Insert("e");
1638 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1639 		beosCredits.Remove(0, beosOffset + 2);
1640 		fCreditsView->Insert(beosCredits.String(), beosCredits.Length());
1641 	}
1642 	fCreditsView->Insert(
1643 		B_TRANSLATE("Travis Geiselbrecht (and his NewOS kernel)\n"));
1644 	fCreditsView->Insert(
1645 		B_TRANSLATE("Michael Phipps (project founder)\n\n"));
1646 	fCreditsView->Insert(
1647 		B_TRANSLATE("The HaikuPorts team\n"));
1648 	fCreditsView->Insert(
1649 		B_TRANSLATE("The Haikuware team and their bounty program\n"));
1650 	fCreditsView->Insert(
1651 		B_TRANSLATE("The BeGeistert team\n"));
1652 	fCreditsView->Insert(
1653 		B_TRANSLATE("Google and their Google Summer of Code and Google Code In "
1654 			"programs\n"));
1655 	fCreditsView->Insert(
1656 		B_TRANSLATE("The University of Auckland and Christof Lutteroth\n\n"));
1657 	fCreditsView->Insert(
1658 		B_TRANSLATE(B_UTF8_ELLIPSIS "and the many people making donations!\n\n"));
1659 
1660 	// copyrights for various projects we use
1661 
1662 	BPath mitPath;
1663 	_GetLicensePath("MIT", mitPath);
1664 	BPath lgplPath;
1665 	_GetLicensePath("GNU LGPL v2.1", lgplPath);
1666 
1667 	font.SetSize(be_bold_font->Size() + 4);
1668 	font.SetFace(B_BOLD_FACE);
1669 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1670 	fCreditsView->Insert(B_TRANSLATE("\nCopyrights\n\n"));
1671 
1672 	// Haiku license
1673 	BString haikuLicense = B_TRANSLATE_COMMENT("The code that is unique to "
1674 		"Haiku, especially the kernel and all code that applications may link "
1675 		"against, is distributed under the terms of the <MIT license>. "
1676 		"Some system libraries contain third party code distributed under the "
1677 		"<LGPL license>. You can find the copyrights to third party code below."
1678 		"\n\n", "<MIT license> and <LGPL license> aren't variables and can be "
1679 		"translated. However, please, don't remove < and > as they're needed "
1680 		"as placeholders for proper hypertext functionality.");
1681 	int32 licensePart1 = haikuLicense.FindFirst("<");
1682 	int32 licensePart2 = haikuLicense.FindFirst(">");
1683 	int32 licensePart3 = haikuLicense.FindLast("<");
1684 	int32 licensePart4 = haikuLicense.FindLast(">");
1685 	BString part;
1686 	haikuLicense.CopyInto(part, 0, licensePart1);
1687 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1688 	fCreditsView->Insert(part);
1689 
1690 	part.Truncate(0);
1691 	haikuLicense.CopyInto(part, licensePart1 + 1, licensePart2 - 1
1692 		- licensePart1);
1693 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1694 	fCreditsView->InsertHyperText(part, new OpenFileAction(mitPath.Path()));
1695 
1696 	part.Truncate(0);
1697 	haikuLicense.CopyInto(part, licensePart2 + 1, licensePart3 - 1
1698 		- licensePart2);
1699 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1700 	fCreditsView->Insert(part);
1701 
1702 	part.Truncate(0);
1703 	haikuLicense.CopyInto(part, licensePart3 + 1, licensePart4 - 1
1704 		- licensePart3);
1705 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1706 	fCreditsView->InsertHyperText(part, new OpenFileAction(lgplPath.Path()));
1707 
1708 	part.Truncate(0);
1709 	haikuLicense.CopyInto(part, licensePart4 + 1, haikuLicense.Length() - 1
1710 		- licensePart4);
1711 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1712 	fCreditsView->Insert(part);
1713 
1714 	// GNU copyrights
1715 	AddCopyrightEntry("The GNU Project",
1716 		B_TRANSLATE("Contains software from the GNU Project, "
1717 		"released under the GPL and LGPL licenses:\n"
1718 		"GNU C Library, "
1719 		"GNU coretools, diffutils, findutils, "
1720 		"sharutils, gawk, bison, m4, make, "
1721 		"wget, ncurses, termcap, "
1722 		"Bourne Again Shell.\n"
1723 		COPYRIGHT_STRING "The Free Software Foundation."),
1724 		StringVector(kLGPLv21, kGPLv2, kGPLv3, NULL),
1725 		StringVector(),
1726 		"https://www.gnu.org");
1727 
1728 	// FreeBSD copyrights
1729 	AddCopyrightEntry("The FreeBSD Project",
1730 		B_TRANSLATE("Contains software from the FreeBSD Project, "
1731 		"released under the BSD license:\n"
1732 		"ftpd, ping, telnet, telnetd, traceroute\n"
1733 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project. "
1734 		"All rights reserved."),
1735 		StringVector(kBSDTwoClause, kBSDThreeClause, kBSDFourClause,
1736 			NULL),
1737 		StringVector(),
1738 		"https://www.freebsd.org");
1739 
1740 	// FFmpeg copyrights
1741 	_AddPackageCredit(PackageCredit("FFmpeg")
1742 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000-2019 Fabrice "
1743 			"Bellard, et al."))
1744 		.SetLicenses(kLGPLv21, kLGPLv2, NULL)
1745 		.SetURL("https://www.ffmpeg.org"));
1746 
1747 	// AGG copyrights
1748 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
1749 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2006 Maxim "
1750 			"Shemanarev (McSeem)."))
1751 		.SetLicenses("Anti-Grain Geometry", kBSDThreeClause, NULL)
1752 		.SetURL("http://www.antigrain.com"));
1753 
1754 	// FreeType copyrights
1755 	_AddPackageCredit(PackageCredit("FreeType2")
1756 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1996-2002, 2006 "
1757 			"David Turner, Robert Wilhelm and Werner Lemberg."),
1758 			COPYRIGHT_STRING "2014 The FreeType Project. "
1759 			"All rights reserved.",
1760 			NULL)
1761 		.SetLicense("FreeType")
1762 		.SetURL("http://www.freetype.org"));
1763 
1764 	// Mesa3D (http://www.mesa3d.org) copyrights
1765 	_AddPackageCredit(PackageCredit("Mesa")
1766 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2006 Brian Paul. "
1767 			"Mesa3D Project. All rights reserved."))
1768 		.SetLicense("MIT")
1769 		.SetURL("http://www.mesa3d.org"));
1770 
1771 	// SGI's GLU implementation copyrights
1772 	_AddPackageCredit(PackageCredit("GLU")
1773 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1991-2000 "
1774 			"Silicon Graphics, Inc. All rights reserved."))
1775 		.SetLicense("SGI Free B")
1776 		.SetURL("http://www.sgi.com/products/software/opengl"));
1777 
1778 	// GLUT implementation copyrights
1779 	_AddPackageCredit(PackageCredit("GLUT")
1780 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
1781 			"All rights reserved."),
1782 			COPYRIGHT_STRING "1997 Be Inc.",
1783 			COPYRIGHT_STRING "1999 Jake Hamby.",
1784 			NULL)
1785 		.SetLicense("MIT")
1786 		.SetURL("http://www.opengl.org/resources/libraries/glut"));
1787 
1788 	// OpenGroup & DEC (BRegion backend) copyright
1789 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
1790 		.SetCopyrights(COPYRIGHT_STRING "1987-1988, 1998 The Open Group.",
1791 			B_TRANSLATE(COPYRIGHT_STRING "1987-1988 Digital Equipment "
1792 			"Corporation, Maynard, Massachusetts.\n"
1793 			"All rights reserved."),
1794 			NULL)
1795 		.SetLicenses("OpenGroup", "DEC", NULL)
1796 		.SetURL("https://xfree86.org"));
1797 
1798 	// Bitstream Charter font
1799 	_AddPackageCredit(PackageCredit("Bitstream Charter font")
1800 		.SetCopyrights(COPYRIGHT_STRING "1989-1992 Bitstream Inc.,"
1801 			"Cambridge, MA.",
1802 			B_TRANSLATE("BITSTREAM CHARTER is a registered trademark of "
1803 				"Bitstream Inc."),
1804 			NULL)
1805 		.SetLicense("Bitstream Charter")
1806 		.SetURL("http://www.bitstream.com/"));
1807 
1808 	// Noto fonts copyright
1809 	_AddPackageCredit(PackageCredit("Noto fonts")
1810 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING
1811 			"2012-2016 Google Internationalization team."),
1812 			NULL)
1813 		.SetLicense("SIL Open Font Licence v1.1")
1814 		.SetURL("http://www.google.com/get/noto/"));
1815 
1816 	// expat copyrights
1817 	_AddPackageCredit(PackageCredit("expat")
1818 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1998-2000 Thai "
1819 			"Open Source Software Center Ltd and Clark Cooper."),
1820 			B_TRANSLATE(COPYRIGHT_STRING "2001-2003 Expat maintainers."),
1821 			NULL)
1822 		.SetLicense("Expat")
1823 		.SetURL("http://expat.sourceforge.net"));
1824 
1825 	// zlib copyrights
1826 	_AddPackageCredit(PackageCredit("zlib")
1827 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2004 Jean-loup "
1828 			"Gailly and Mark Adler."))
1829 		.SetLicense("Zlib")
1830 		.SetURL("http://www.zlib.net"));
1831 
1832 	// zip copyrights
1833 	_AddPackageCredit(PackageCredit("Info-ZIP")
1834 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1990-2002 Info-ZIP. "
1835 			"All rights reserved."))
1836 		.SetLicense("Info-ZIP")
1837 		.SetURL("http://www.info-zip.org"));
1838 
1839 	// bzip2 copyrights
1840 	_AddPackageCredit(PackageCredit("bzip2")
1841 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-2005 Julian R "
1842 			"Seward. All rights reserved."))
1843 		.SetLicense(kBSDFourClause)
1844 		.SetURL("http://bzip.org"));
1845 
1846 	// OpenEXR copyrights
1847 	_AddPackageCredit(PackageCredit("OpenEXR")
1848 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2014 Industrial "
1849 			"Light & Magic, a division of Lucas Digital Ltd. LLC."))
1850 		.SetLicense(kBSDThreeClause)
1851 		.SetURL("http://www.openexr.com"));
1852 
1853 	// acpica copyrights
1854 	_AddPackageCredit(PackageCredit("ACPI Component Architecture (ACPICA)")
1855 		.SetCopyright(COPYRIGHT_STRING "1999-2018 Intel Corp.")
1856 		.SetLicense("Intel (ACPICA)")
1857 		.SetURL("https://www.acpica.org"));
1858 
1859 	// libpng copyrights
1860 	_AddPackageCredit(PackageCredit("libpng")
1861 		.SetCopyright(COPYRIGHT_STRING "1995-2017 libpng authors")
1862 		.SetLicense("LibPNG")
1863 		.SetURL("http://www.libpng.org"));
1864 
1865 	// libjpeg copyrights
1866 	_AddPackageCredit(PackageCredit("libjpeg")
1867 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1994-2009, Thomas G. "
1868 			"Lane, Guido Vollbeding. This software is based in part on the "
1869 			"work of the Independent JPEG Group."))
1870 		.SetLicense("LibJPEG")
1871 		.SetURL("http://www.ijg.org"));
1872 
1873 	// libprint copyrights
1874 	_AddPackageCredit(PackageCredit("libprint")
1875 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2000 Y.Takagi. "
1876 			"All rights reserved.")));
1877 			// TODO: License!
1878 
1879 	// cortex copyrights
1880 	_AddPackageCredit(PackageCredit("Cortex")
1881 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon.")
1882 		.SetLicense(kBSDThreeClause)
1883 		.SetURL("http://cortex.sourceforge.net/documentation"));
1884 
1885 	// FluidSynth copyrights
1886 	_AddPackageCredit(PackageCredit("FluidSynth")
1887 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003 Peter Hanappe "
1888 			"and others."))
1889 		.SetLicense(kLGPLv2)
1890 		.SetURL("http://www.fluidsynth.org"));
1891 
1892 	// Xiph.org Foundation copyrights
1893 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1894 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1895 			B_TRANSLATE(COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1896 			"All rights reserved."), NULL)
1897 		.SetLicense(kBSDThreeClause)
1898 		.SetURL("http://www.xiph.org"));
1899 
1900 	// Matroska
1901 	_AddPackageCredit(PackageCredit("libmatroska")
1902 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1903 			"All rights reserved."))
1904 		.SetLicense(kLGPLv21)
1905 		.SetURL("http://www.matroska.org"));
1906 
1907 	// BColorQuantizer (originally CQuantizer code)
1908 	_AddPackageCredit(PackageCredit("CQuantizer")
1909 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1910 			"All rights reserved."))
1911 		.SetLicense("CQuantizer")
1912 		.SetURL("http://www.xdp.it"));
1913 
1914 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1915 	_AddPackageCredit(PackageCredit("MAPM")
1916 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2007 Michael C. "
1917 			"Ring. All rights reserved."))
1918 		.SetLicense("MAPM")
1919 		.SetURL("http://tc.umn.edu/~ringx004"));
1920 
1921 	// MkDepend 1.7 copyright (Makefile dependency generator)
1922 	_AddPackageCredit(PackageCredit("MkDepend")
1923 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1924 			"All rights reserved."))
1925 		.SetLicense("MIT")
1926 		.SetURL("http://bearnip.com/lars/be"));
1927 
1928 	// libhttpd copyright (used as Poorman backend)
1929 	_AddPackageCredit(PackageCredit("libhttpd")
1930 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995, 1998-2001 "
1931 			"Jef Poskanzer. All rights reserved."))
1932 		.SetLicense(kBSDTwoClause)
1933 		.SetURL("http://www.acme.com/software/thttpd/"));
1934 
1935 #ifdef __i386__
1936 	// Udis86 copyrights
1937 	_AddPackageCredit(PackageCredit("Udis86")
1938 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2004 "
1939 			"Vivek Mohan. All rights reserved."))
1940 		.SetLicense(kBSDTwoClause)
1941 		.SetURL("http://udis86.sourceforge.net"));
1942 
1943 	// Intel PRO/Wireless 2100 & 2200BG firmwares
1944 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2100 & 2200BG firmwares")
1945 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003-2006 "
1946 			"Intel Corporation. All rights reserved."))
1947 		.SetLicense(kIntel2xxxFirmware)
1948 		.SetURL("http://www.intellinuxwireless.org/"));
1949 
1950 	// Intel wireless firmwares
1951 	_AddPackageCredit(
1952 		PackageCredit("Intel PRO/Wireless network adapter firmwares")
1953 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2015 "
1954 			"Intel Corporation. All rights reserved."))
1955 		.SetLicense(kIntelFirmware)
1956 		.SetURL("http://www.intellinuxwireless.org/"));
1957 
1958 	// Marvell 88w8363
1959 	_AddPackageCredit(PackageCredit("Marvell 88w8363")
1960 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007-2009 "
1961 			"Marvell Semiconductor, Inc. All rights reserved."))
1962 		.SetLicense(kMarvellFirmware)
1963 		.SetURL("http://www.marvell.com/"));
1964 
1965 	// Ralink Firmware RT2501/RT2561/RT2661
1966 	_AddPackageCredit(PackageCredit("Ralink Firmware RT2501/RT2561/RT2661")
1967 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007 "
1968 			"Ralink Technology Corporation. All rights reserved."))
1969 		.SetLicense(kRalinkFirmware)
1970 		.SetURL("http://www.ralinktech.com/"));
1971 #endif
1972 
1973 	// Gutenprint
1974 	_AddPackageCredit(PackageCredit("Gutenprint")
1975 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1976 			"1999-2010 by the authors of Gutenprint. All rights reserved."))
1977 		.SetLicense(kGPLv2)
1978 		.SetURL("http://gutenprint.sourceforge.net/"));
1979 
1980 	// libwebp
1981 	_AddPackageCredit(PackageCredit("libwebp")
1982 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1983 			"2010-2011 Google Inc. All rights reserved."))
1984 		.SetLicense(kBSDThreeClause)
1985 		.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
1986 
1987 	// libavif
1988 	_AddPackageCredit(PackageCredit("libavif")
1989 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1990 			"2019 Joe Drago. All rights reserved."))
1991 		.SetLicense(kBSDThreeClause)
1992 		.SetURL("https://github.com/AOMediaCodec/libavif"));
1993 
1994 	// GTF
1995 	_AddPackageCredit(PackageCredit("GTF")
1996 		.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
1997 			"Generalized Timing Formula"))
1998 		.SetLicense(kBSDThreeClause)
1999 		.SetURL("http://gtf.sourceforge.net/"));
2000 
2001 	// libqrencode
2002 	_AddPackageCredit(PackageCredit("libqrencode")
2003 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi"))
2004 		.SetLicense(kLGPLv21)
2005 		.SetURL("http://fukuchi.org/works/qrencode/"));
2006 
2007 	// scrypt
2008 	_AddPackageCredit(PackageCredit("scrypt")
2009 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2009 Colin Percival"))
2010 		.SetLicense(kBSDTwoClause)
2011 		.SetURL("https://tarsnap.com/scrypt.html"));
2012 
2013 	_AddCopyrightsFromAttribute();
2014 	_AddPackageCreditEntries();
2015 
2016 	return new CropView(creditsScroller, 0, 1, 1, 1);
2017 }
2018 
2019 
2020 status_t
2021 AboutView::_GetLicensePath(const char* license, BPath& path)
2022 {
2023 	BPathFinder pathFinder;
2024 	BStringList paths;
2025 	struct stat st;
2026 
2027 	status_t error = pathFinder.FindPaths(B_FIND_PATH_DATA_DIRECTORY,
2028 		"licenses", paths);
2029 
2030 	for (int i = 0; i < paths.CountStrings(); ++i) {
2031 		if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
2032 			&& path.Append(license) == B_OK
2033 			&& lstat(path.Path(), &st) == 0) {
2034 			return B_OK;
2035 		}
2036 	}
2037 
2038 	path.Unset();
2039 	return B_ENTRY_NOT_FOUND;
2040 }
2041 
2042 
2043 void
2044 AboutView::_AddCopyrightsFromAttribute()
2045 {
2046 #ifdef __HAIKU__
2047 	// open the app executable file
2048 	char appPath[B_PATH_NAME_LENGTH];
2049 	int appFD;
2050 	if (BPrivate::get_app_path(appPath) != B_OK
2051 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
2052 		return;
2053 	}
2054 
2055 	// open the attribute
2056 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
2057 	close(appFD);
2058 	if (attrFD < 0)
2059 		return;
2060 
2061 	// attach it to a FILE
2062 	FileCloser attrFile(fdopen(attrFD, "r"));
2063 	if (!attrFile.IsSet()) {
2064 		close(attrFD);
2065 		return;
2066 	}
2067 
2068 	// read and parse the copyrights
2069 	BMessage package;
2070 	BString fieldName;
2071 	BString fieldValue;
2072 	char lineBuffer[LINE_MAX];
2073 	while (char* line
2074 		= fgets(lineBuffer, sizeof(lineBuffer), attrFile.Get())) {
2075 		// chop off line break
2076 		size_t lineLen = strlen(line);
2077 		if (lineLen > 0 && line[lineLen - 1] == '\n')
2078 			line[--lineLen] = '\0';
2079 
2080 		// flush previous field, if a new field begins, otherwise append
2081 		if (lineLen == 0 || !isspace(line[0])) {
2082 			// new field -- flush the previous one
2083 			if (fieldName.Length() > 0) {
2084 				fieldValue = trim_string(fieldValue.String(),
2085 					fieldValue.Length());
2086 				package.AddString(fieldName.String(), fieldValue);
2087 				fieldName = "";
2088 			}
2089 		} else if (fieldName.Length() > 0) {
2090 			// append to current field
2091 			fieldValue += line;
2092 			continue;
2093 		} else {
2094 			// bogus line -- ignore
2095 			continue;
2096 		}
2097 
2098 		if (lineLen == 0)
2099 			continue;
2100 
2101 		// parse new field
2102 		char* colon = strchr(line, ':');
2103 		if (colon == NULL) {
2104 			// bogus line -- ignore
2105 			continue;
2106 		}
2107 
2108 		fieldName.SetTo(line, colon - line);
2109 		fieldName = trim_string(line, colon - line);
2110 		if (fieldName.Length() == 0) {
2111 			// invalid field name
2112 			continue;
2113 		}
2114 
2115 		fieldValue = colon + 1;
2116 
2117 		if (fieldName == "Package") {
2118 			// flush the current package
2119 			_AddPackageCredit(PackageCredit(package));
2120 			package.MakeEmpty();
2121 		}
2122 	}
2123 
2124 	// flush current package
2125 	_AddPackageCredit(PackageCredit(package));
2126 #endif
2127 }
2128 
2129 
2130 void
2131 AboutView::_AddPackageCreditEntries()
2132 {
2133 	// sort the packages case-insensitively
2134 	PackageCredit* packages[fPackageCredits.size()];
2135 	int32 count = 0;
2136 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
2137 			it != fPackageCredits.end(); ++it) {
2138 		packages[count++] = it->second;
2139 	}
2140 
2141 	if (count > 1) {
2142 		std::sort(packages, packages + count,
2143 			&PackageCredit::NameLessInsensitive);
2144 	}
2145 
2146 	// add the credits
2147 	BString text;
2148 	for (int32 i = 0; i < count; i++) {
2149 		PackageCredit* package = packages[i];
2150 
2151 		text.SetTo(package->CopyrightAt(0));
2152 		int32 count = package->CountCopyrights();
2153 		for (int32 i = 1; i < count; i++)
2154 			text << "\n" << package->CopyrightAt(i);
2155 
2156 		AddCopyrightEntry(package->PackageName(), text.String(),
2157 			package->Licenses(), package->Sources(), package->URL());
2158 	}
2159 }
2160 
2161 
2162 void
2163 AboutView::_AddPackageCredit(const PackageCredit& package)
2164 {
2165 	if (!package.IsValid())
2166 		return;
2167 
2168 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
2169 	if (it != fPackageCredits.end()) {
2170 		// If the new package credit isn't "better" than the old one, ignore it.
2171 		PackageCredit* oldPackage = it->second;
2172 		if (!package.IsBetterThan(*oldPackage))
2173 			return;
2174 
2175 		// replace the old credit
2176 		fPackageCredits.erase(it);
2177 		delete oldPackage;
2178 	}
2179 
2180 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
2181 }
2182 
2183 
2184 //	#pragma mark - static functions
2185 
2186 
2187 static int
2188 ignored_pages(system_info* sysInfo)
2189 {
2190 	return (int)round(sysInfo->ignored_pages * B_PAGE_SIZE / 1048576.0);
2191 }
2192 
2193 
2194 static int
2195 max_pages(system_info* sysInfo)
2196 {
2197 	return (int)round(sysInfo->max_pages * B_PAGE_SIZE / 1048576.0);
2198 }
2199 
2200 
2201 static int
2202 max_and_ignored_pages(system_info* sysInfo)
2203 {
2204 	return (int)round((sysInfo->max_pages + sysInfo->ignored_pages)
2205 		* B_PAGE_SIZE / 1048576.0);
2206 }
2207 
2208 
2209 static int
2210 used_pages(system_info* sysInfo)
2211 {
2212 	return (int)round(sysInfo->used_pages * B_PAGE_SIZE / 1048576.0);
2213 }
2214 
2215 
2216 //	#pragma mark - main
2217 
2218 
2219 int
2220 main()
2221 {
2222 	AboutApp app;
2223 	app.Run();
2224 
2225 	return 0;
2226 }
2227