xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2005-2018, Haiku, Inc.
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  *		Wim van der Meer <WPJvanderMeer@gmail.com>
10  */
11 
12 
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <time.h>
16 #include <unistd.h>
17 
18 #include <algorithm>
19 #include <map>
20 #include <string>
21 
22 #include <AppFileInfo.h>
23 #include <Application.h>
24 #include <Bitmap.h>
25 #include <DateTimeFormat.h>
26 #include <DurationFormat.h>
27 #include <File.h>
28 #include <FindDirectory.h>
29 #include <Font.h>
30 #include <fs_attr.h>
31 #include <LayoutBuilder.h>
32 #include <MessageRunner.h>
33 #include <Messenger.h>
34 #include <ObjectList.h>
35 #include <OS.h>
36 #include <Path.h>
37 #include <PathFinder.h>
38 #include <Resources.h>
39 #include <Screen.h>
40 #include <ScrollView.h>
41 #include <String.h>
42 #include <StringFormat.h>
43 #include <StringList.h>
44 #include <StringView.h>
45 #include <TranslationUtils.h>
46 #include <TranslatorFormats.h>
47 #include <View.h>
48 #include <Volume.h>
49 #include <VolumeRoster.h>
50 #include <Window.h>
51 
52 #include <AppMisc.h>
53 #include <AutoDeleter.h>
54 #include <cpu_type.h>
55 #include <parsedate.h>
56 #include <system_revision.h>
57 
58 #include <Catalog.h>
59 #include <Language.h>
60 #include <Locale.h>
61 #include <LocaleRoster.h>
62 
63 #include "HyperTextActions.h"
64 #include "HyperTextView.h"
65 #include "Utilities.h"
66 
67 #include "Credits.h"
68 
69 #ifndef LINE_MAX
70 #define LINE_MAX 2048
71 #endif
72 
73 #define SCROLL_CREDITS_VIEW 'mviv'
74 
75 #undef B_TRANSLATION_CONTEXT
76 #define B_TRANSLATION_CONTEXT "AboutWindow"
77 
78 
79 
80 static const char* UptimeToString(char string[], size_t size);
81 static const char* MemSizeToString(char string[], size_t size,
82 	system_info* info);
83 static const char* MemUsageToString(char string[], size_t size,
84 	system_info* info);
85 
86 
87 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
88 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
89 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
90 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
91 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
92 static const rgb_color kBeOSBlue = { 0, 0, 200, 255 };
93 static const rgb_color kBeOSRed = { 200, 0, 0, 255 };
94 
95 static const char* kBerkeley = B_TRANSLATE_MARK("Berkeley");
96 static const char* kBSDTwoClause = B_TRANSLATE_MARK("BSD (2-clause)");
97 static const char* kBSDThreeClause = B_TRANSLATE_MARK("BSD (3-clause)");
98 static const char* kBSDFourClause = B_TRANSLATE_MARK("BSD (4-clause)");
99 static const char* kGPLv2 = B_TRANSLATE_MARK("GNU GPL v2");
100 static const char* kGPLv3 = B_TRANSLATE_MARK("GNU GPL v3");
101 static const char* kLGPLv2 = B_TRANSLATE_MARK("GNU LGPL v2");
102 static const char* kLGPLv21 = B_TRANSLATE_MARK("GNU LGPL v2.1");
103 #if 0
104 static const char* kPublicDomain = B_TRANSLATE_MARK("Public Domain");
105 #endif
106 #ifdef __INTEL__
107 static const char* kIntel2xxxFirmware = B_TRANSLATE_MARK("Intel (2xxx firmware)");
108 static const char* kIntelFirmware = B_TRANSLATE_MARK("Intel (firmware)");
109 static const char* kMarvellFirmware = B_TRANSLATE_MARK("Marvell (firmware)");
110 static const char* kRalinkFirmware = B_TRANSLATE_MARK("Ralink (firmware)");
111 #endif
112 
113 
114 static int
115 TranslationComparator(const void* left, const void* right)
116 {
117 	const Translation* leftTranslation = *(const Translation**)left;
118 	const Translation* rightTranslation = *(const Translation**)right;
119 
120 	BLanguage* language;
121 	BString leftName;
122 	if (BLocaleRoster::Default()->GetLanguage(leftTranslation->languageCode,
123 			&language) == B_OK) {
124 		language->GetName(leftName);
125 		delete language;
126 	} else
127 		leftName = leftTranslation->languageCode;
128 
129 	BString rightName;
130 	if (BLocaleRoster::Default()->GetLanguage(rightTranslation->languageCode,
131 			&language) == B_OK) {
132 		language->GetName(rightName);
133 		delete language;
134 	} else
135 		rightName = rightTranslation->languageCode;
136 
137 	BCollator collator;
138 	BLocale::Default()->GetCollator(&collator);
139 	return collator.Compare(leftName.String(), rightName.String());
140 }
141 
142 
143 class AboutApp : public BApplication {
144 public:
145 							AboutApp();
146 			void			MessageReceived(BMessage* message);
147 };
148 
149 
150 class AboutView;
151 
152 class AboutWindow : public BWindow {
153 public:
154 							AboutWindow();
155 
156 	virtual	bool			QuitRequested();
157 
158 			AboutView*		fAboutView;
159 };
160 
161 
162 class LogoView : public BView {
163 public:
164 							LogoView();
165 	virtual					~LogoView();
166 
167 	virtual	BSize			MinSize();
168 	virtual	BSize			MaxSize();
169 
170 	virtual void			Draw(BRect updateRect);
171 
172 private:
173 			BBitmap*		fLogo;
174 };
175 
176 
177 class CropView : public BView {
178 public:
179 							CropView(BView* target, int32 left, int32 top,
180 								int32 right, int32 bottom);
181 	virtual					~CropView();
182 
183 	virtual	BSize			MinSize();
184 	virtual	BSize			MaxSize();
185 
186 	virtual void			DoLayout();
187 
188 private:
189 			BView*			fTarget;
190 			int32			fCropLeft;
191 			int32			fCropTop;
192 			int32			fCropRight;
193 			int32			fCropBottom;
194 };
195 
196 
197 class AboutView : public BView {
198 public:
199 							AboutView();
200 							~AboutView();
201 
202 	virtual void			AttachedToWindow();
203 	virtual	void			AllAttached();
204 	virtual void			Pulse();
205 
206 	virtual void			MessageReceived(BMessage* msg);
207 	virtual void			MouseDown(BPoint point);
208 
209 			void			AddCopyrightEntry(const char* name,
210 								const char* text,
211 								const StringVector& licenses,
212 								const StringVector& sources,
213 								const char* url);
214 			void			AddCopyrightEntry(const char* name,
215 								const char* text, const char* url = NULL);
216 			void			PickRandomHaiku();
217 
218 
219 			void			_AdjustTextColors();
220 private:
221 	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
222 
223 private:
224 			BView*			_CreateLabel(const char* name, const char* label);
225 			BView*			_CreateCreditsView();
226 			status_t		_GetLicensePath(const char* license,
227 								BPath& path);
228 			void			_AddCopyrightsFromAttribute();
229 			void			_AddPackageCredit(const PackageCredit& package);
230 			void			_AddPackageCreditEntries();
231 
232 			BStringView*	fMemView;
233 			BStringView*	fUptimeView;
234 			BView*			fInfoView;
235 			HyperTextView*	fCreditsView;
236 
237 			BObjectList<BView> fTextViews;
238 			BObjectList<BView> fSubTextViews;
239 
240 			BBitmap*		fLogo;
241 
242 			bigtime_t		fLastActionTime;
243 			BMessageRunner*	fScrollRunner;
244 			PackageCreditMap fPackageCredits;
245 };
246 
247 
248 //	#pragma mark -
249 
250 
251 AboutApp::AboutApp()
252 	: BApplication("application/x-vnd.Haiku-About")
253 {
254 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("AboutSystem");
255 
256 	AboutWindow *window = new(std::nothrow) AboutWindow();
257 	if (window)
258 		window->Show();
259 }
260 
261 
262 void
263 AboutApp::MessageReceived(BMessage* message)
264 {
265 	switch (message->what) {
266 		case B_SILENT_RELAUNCH:
267 			WindowAt(0)->Activate();
268 			break;
269 	}
270 
271 	BApplication::MessageReceived(message);
272 }
273 
274 
275 //	#pragma mark -
276 
277 
278 AboutWindow::AboutWindow()
279 	: BWindow(BRect(0, 0, 500, 300), B_TRANSLATE("About this system"),
280 		B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
281 {
282 	SetLayout(new BGroupLayout(B_VERTICAL));
283 	fAboutView = new AboutView();
284 	AddChild(fAboutView);
285 
286 	// Make sure we take the minimal window size into account when centering
287 	BSize size = GetLayout()->MinSize();
288 	ResizeTo(max_c(size.width, Bounds().Width()),
289 		max_c(size.height, Bounds().Height()));
290 
291 	CenterOnScreen();
292 }
293 
294 
295 bool
296 AboutWindow::QuitRequested()
297 {
298 	be_app->PostMessage(B_QUIT_REQUESTED);
299 	return true;
300 }
301 
302 
303 //	#pragma mark - LogoView
304 
305 
306 LogoView::LogoView()
307 	: BView("logo", B_WILL_DRAW)
308 {
309 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png");
310 	SetViewColor(255, 255, 255);
311 }
312 
313 
314 LogoView::~LogoView()
315 {
316 	delete fLogo;
317 }
318 
319 
320 BSize
321 LogoView::MinSize()
322 {
323 	if (fLogo == NULL)
324 		return BSize(0, 0);
325 
326 	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
327 }
328 
329 
330 BSize
331 LogoView::MaxSize()
332 {
333 	if (fLogo == NULL)
334 		return BSize(0, 0);
335 
336 	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
337 }
338 
339 
340 void
341 LogoView::Draw(BRect updateRect)
342 {
343 	if (fLogo != NULL) {
344 		DrawBitmap(fLogo,
345 			BPoint((Bounds().Width() - fLogo->Bounds().Width()) / 2, 0));
346 	}
347 }
348 
349 
350 //	#pragma mark - CropView
351 
352 
353 CropView::CropView(BView* target, int32 left, int32 top, int32 right,
354 		int32 bottom)
355 	: BView("crop view", 0),
356 	fTarget(target),
357 	fCropLeft(left),
358 	fCropTop(top),
359 	fCropRight(right),
360 	fCropBottom(bottom)
361 {
362 	AddChild(target);
363 }
364 
365 
366 CropView::~CropView()
367 {
368 }
369 
370 
371 BSize
372 CropView::MinSize()
373 {
374 	if (fTarget == NULL)
375 		return BSize();
376 
377 	BSize size = fTarget->MinSize();
378 	if (size.width != B_SIZE_UNSET)
379 		size.width -= fCropLeft + fCropRight;
380 	if (size.height != B_SIZE_UNSET)
381 		size.height -= fCropTop + fCropBottom;
382 
383 	return size;
384 }
385 
386 
387 BSize
388 CropView::MaxSize()
389 {
390 	if (fTarget == NULL)
391 		return BSize();
392 
393 	BSize size = fTarget->MaxSize();
394 	if (size.width != B_SIZE_UNSET)
395 		size.width -= fCropLeft + fCropRight;
396 	if (size.height != B_SIZE_UNSET)
397 		size.height -= fCropTop + fCropBottom;
398 
399 	return size;
400 }
401 
402 
403 void
404 CropView::DoLayout()
405 {
406 	BView::DoLayout();
407 
408 	if (fTarget == NULL)
409 		return;
410 
411 	fTarget->MoveTo(-fCropLeft, -fCropTop);
412 	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
413 		Bounds().Height() + fCropTop + fCropBottom);
414 }
415 
416 
417 //	#pragma mark - AboutView
418 
419 #undef B_TRANSLATION_CONTEXT
420 #define B_TRANSLATION_CONTEXT "AboutView"
421 
422 AboutView::AboutView()
423 	: BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
424 	fLastActionTime(system_time()),
425 	fScrollRunner(NULL)
426 {
427 	// Begin Construction of System Information controls
428 	system_info systemInfo;
429 	get_system_info(&systemInfo);
430 
431 	// Create all the various labels for system infomation
432 
433 	// OS Version
434 
435 	char string[1024];
436 	strlcpy(string, B_TRANSLATE("Unknown"), sizeof(string));
437 
438 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
439 	BPath path;
440 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
441 		path.Append("libbe.so");
442 
443 		BAppFileInfo appFileInfo;
444 		version_info versionInfo;
445 		BFile file;
446 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
447 			&& appFileInfo.SetTo(&file) == B_OK
448 			&& appFileInfo.GetVersionInfo(&versionInfo,
449 				B_APP_VERSION_KIND) == B_OK
450 			&& versionInfo.short_info[0] != '\0')
451 			strlcpy(string, versionInfo.short_info, sizeof(string));
452 	}
453 
454 	// Add system revision
455 	const char* haikuRevision = __get_haiku_revision();
456 	if (haikuRevision != NULL) {
457 		strlcat(string, " (", sizeof(string));
458 		strlcat(string, B_TRANSLATE("Revision"), sizeof(string));
459 		strlcat(string, " ", sizeof(string));
460 		strlcat(string, haikuRevision, sizeof(string));
461 		strlcat(string, ")", sizeof(string));
462 	}
463 
464 	BStringView* versionView = new BStringView("ostext", string);
465 	fSubTextViews.AddItem(versionView);
466 	versionView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
467 		B_ALIGN_VERTICAL_UNSET));
468 
469 	BStringView* abiView = new BStringView("abitext", B_HAIKU_ABI_NAME);
470 	fSubTextViews.AddItem(abiView);
471 	abiView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
472 		B_ALIGN_VERTICAL_UNSET));
473 
474 	// CPU count, type and clock speed
475 	static BStringFormat format(B_TRANSLATE_COMMENT(
476 		"{0, plural, one{Processor:} other{# Processors:}}",
477 		"\"Processor:\" or \"2 Processors:\""));
478 
479 	BString processorLabel;
480 	format.Format(processorLabel, systemInfo.cpu_count);
481 
482 	uint32 topologyNodeCount = 0;
483 	cpu_topology_node_info* topology = NULL;
484 	get_cpu_topology_info(NULL, &topologyNodeCount);
485 	if (topologyNodeCount != 0)
486 		topology = new cpu_topology_node_info[topologyNodeCount];
487 	get_cpu_topology_info(topology, &topologyNodeCount);
488 
489 	enum cpu_platform platform = B_CPU_UNKNOWN;
490 	enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
491 	uint32 cpuModel = 0;
492 	for (uint32 i = 0; i < topologyNodeCount; i++) {
493 		switch (topology[i].type) {
494 			case B_TOPOLOGY_ROOT:
495 				platform = topology[i].data.root.platform;
496 				break;
497 
498 			case B_TOPOLOGY_PACKAGE:
499 				cpuVendor = topology[i].data.package.vendor;
500 				break;
501 
502 			case B_TOPOLOGY_CORE:
503 				cpuModel = topology[i].data.core.model;
504 				break;
505 
506 			default:
507 				break;
508 		}
509 	}
510 
511 	delete[] topology;
512 
513 	BString cpuType;
514 	cpuType << get_cpu_vendor_string(cpuVendor)
515 		<< " " << get_cpu_model_string(platform, cpuVendor, cpuModel);
516 
517 	BStringView* cpuView = new BStringView("cputext", cpuType.String());
518 	fSubTextViews.AddItem(cpuView);
519 	cpuView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
520 		B_ALIGN_VERTICAL_UNSET));
521 
522 	int32 clockSpeed = get_rounded_cpu_speed();
523 	if (clockSpeed < 1000)
524 		snprintf(string, sizeof(string), B_TRANSLATE("%ld MHz"), clockSpeed);
525 	else
526 		snprintf(string, sizeof(string), B_TRANSLATE("%.2f GHz"),
527 			clockSpeed / 1000.0f);
528 
529 	BStringView* frequencyView = new BStringView("frequencytext", string);
530 	fSubTextViews.AddItem(frequencyView);
531 	frequencyView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
532 		B_ALIGN_VERTICAL_UNSET));
533 
534 	// RAM
535 	BStringView *memSizeView = new BStringView("ramsizetext",
536 		MemSizeToString(string, sizeof(string), &systemInfo));
537 	fSubTextViews.AddItem(memSizeView);
538 	memSizeView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
539 		B_ALIGN_VERTICAL_UNSET));
540 
541 	fMemView = new BStringView("ramtext",
542 		MemUsageToString(string, sizeof(string), &systemInfo));
543 	fSubTextViews.AddItem(fMemView);
544 	fMemView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
545 		B_ALIGN_VERTICAL_UNSET));
546 
547 	// Kernel build time/date
548 	BString kernelTimeDate;
549 	kernelTimeDate << systemInfo.kernel_build_date
550 		<< " " << systemInfo.kernel_build_time;
551 	BString buildTimeDate;
552 
553 	time_t buildTimeDateStamp = parsedate(kernelTimeDate, -1);
554 	if (buildTimeDateStamp > 0) {
555 		if (BDateTimeFormat().Format(buildTimeDate, buildTimeDateStamp,
556 			B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT) != B_OK)
557 			buildTimeDate.SetTo(kernelTimeDate);
558 	} else
559 		buildTimeDate.SetTo(kernelTimeDate);
560 
561 	BStringView* kernelView = new BStringView("kerneltext", buildTimeDate);
562 	fSubTextViews.AddItem(kernelView);
563 	kernelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
564 		B_ALIGN_VERTICAL_UNSET));
565 
566 	// Uptime
567 	fUptimeView = new BStringView("uptimetext", "...");
568 	fSubTextViews.AddItem(fUptimeView);
569 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
570 
571 	const float offset = 5;
572 
573 	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
574 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
575 
576 	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
577 		.AddGroup(B_VERTICAL, 0)
578 			.Add(new LogoView())
579 			.AddGroup(B_VERTICAL, 0)
580 				.Add(_CreateLabel("oslabel", B_TRANSLATE("Version:")))
581 				.Add(versionView)
582 				.Add(abiView)
583 				.AddStrut(offset)
584 				.Add(_CreateLabel("cpulabel", processorLabel.String()))
585 				.Add(cpuView)
586 				.Add(frequencyView)
587 				.AddStrut(offset)
588 				.Add(_CreateLabel("memlabel", B_TRANSLATE("Memory:")))
589 				.Add(memSizeView)
590 				.Add(fMemView)
591 				.AddStrut(offset)
592 				.Add(_CreateLabel("kernellabel", B_TRANSLATE("Kernel:")))
593 				.Add(kernelView)
594 				.AddStrut(offset)
595 				.Add(_CreateLabel("uptimelabel",
596 					B_TRANSLATE("Time running:")))
597 				.Add(fUptimeView)
598 				.SetInsets(5, 5, 5, 5)
599 			.End()
600 			// TODO: investigate: adding this causes the time to be cut
601 			//.AddGlue()
602 		.End()
603 		.Add(_CreateCreditsView());
604 
605 	float min = fMemView->MinSize().width * 1.1f;
606 	fCreditsView->SetExplicitMinSize(BSize(min, min));
607 }
608 
609 
610 AboutView::~AboutView()
611 {
612 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
613 		it != fPackageCredits.end(); it++) {
614 
615 		delete it->second;
616 	}
617 
618 	delete fScrollRunner;
619 }
620 
621 
622 void
623 AboutView::AttachedToWindow()
624 {
625 	BView::AttachedToWindow();
626 	Window()->SetPulseRate(500000);
627 	SetEventMask(B_POINTER_EVENTS);
628 	DoLayout();
629 }
630 
631 
632 void
633 AboutView::AllAttached()
634 {
635 	_AdjustTextColors();
636 }
637 
638 
639 void
640 AboutView::MouseDown(BPoint point)
641 {
642 	BRect r(92, 26, 105, 31);
643 	if (r.Contains(point))
644 		BMessenger(this).SendMessage('eegg');
645 
646 	if (Bounds().Contains(point)) {
647 		fLastActionTime = system_time();
648 		delete fScrollRunner;
649 		fScrollRunner = NULL;
650 	}
651 }
652 
653 
654 void
655 AboutView::Pulse()
656 {
657 	char string[255];
658 	system_info info;
659 	get_system_info(&info);
660 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
661 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
662 
663 	if (fScrollRunner == NULL
664 		&& system_time() > fLastActionTime + 10000000) {
665 		BMessage message(SCROLL_CREDITS_VIEW);
666 		//fScrollRunner = new BMessageRunner(this, &message, 25000, -1);
667 	}
668 }
669 
670 
671 void
672 AboutView::MessageReceived(BMessage* msg)
673 {
674 	switch (msg->what) {
675 		case B_COLORS_UPDATED:
676 		{
677 			if (msg->HasColor(ui_color_name(B_PANEL_TEXT_COLOR)))
678 				_AdjustTextColors();
679 
680 			break;
681 		}
682 		case SCROLL_CREDITS_VIEW:
683 		{
684 			BScrollBar* scrollBar =
685 				fCreditsView->ScrollBar(B_VERTICAL);
686 			if (scrollBar == NULL)
687 				break;
688 			float max, min;
689 			scrollBar->GetRange(&min, &max);
690 			if (scrollBar->Value() < max)
691 				fCreditsView->ScrollBy(0, 1);
692 
693 			break;
694 		}
695 
696 		case 'eegg':
697 		{
698 			printf("Easter egg\n");
699 			PickRandomHaiku();
700 			break;
701 		}
702 
703 		default:
704 			BView::MessageReceived(msg);
705 			break;
706 	}
707 }
708 
709 
710 void
711 AboutView::AddCopyrightEntry(const char* name, const char* text,
712 	const char* url)
713 {
714 	AddCopyrightEntry(name, text, StringVector(), StringVector(), url);
715 }
716 
717 
718 void
719 AboutView::AddCopyrightEntry(const char* name, const char* text,
720 	const StringVector& licenses, const StringVector& sources,
721 	const char* url)
722 {
723 	BFont font(be_bold_font);
724 	//font.SetSize(be_bold_font->Size());
725 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
726 
727 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
728 	fCreditsView->Insert(name);
729 	fCreditsView->Insert("\n");
730 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
731 	fCreditsView->Insert(text);
732 	fCreditsView->Insert("\n");
733 
734 	if (licenses.CountStrings() > 0) {
735 		if (licenses.CountStrings() > 1)
736 			fCreditsView->Insert(B_TRANSLATE("Licenses: "));
737 		else
738 			fCreditsView->Insert(B_TRANSLATE("License: "));
739 
740 		for (int32 i = 0; i < licenses.CountStrings(); i++) {
741 			const char* license = licenses.StringAt(i);
742 
743 			if (i > 0)
744 				fCreditsView->Insert(", ");
745 
746 			BString licenseName;
747 			BString licenseURL;
748 			parse_named_url(license, licenseName, licenseURL);
749 
750 			BPath licensePath;
751 			if (_GetLicensePath(licenseURL, licensePath) == B_OK) {
752 				fCreditsView->InsertHyperText(B_TRANSLATE_NOCOLLECT(licenseName),
753 					new OpenFileAction(licensePath.Path()));
754 			} else
755 				fCreditsView->Insert(licenseName);
756 		}
757 
758 		fCreditsView->Insert("\n");
759 	}
760 
761 	if (sources.CountStrings() > 0) {
762 		fCreditsView->Insert(B_TRANSLATE("Source Code: "));
763 
764 		for (int32 i = 0; i < sources.CountStrings(); i++) {
765 			const char* source = sources.StringAt(i);
766 
767 			if (i > 0)
768 				fCreditsView->Insert(", ");
769 
770 			BString urlName;
771 			BString urlAddress;
772 			parse_named_url(source, urlName, urlAddress);
773 
774 			fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
775 				&kLinkBlue);
776 			fCreditsView->InsertHyperText(urlName,
777 				new URLAction(urlAddress));
778 		}
779 
780 		fCreditsView->Insert("\n");
781 	}
782 
783 	if (url) {
784 		BString urlName;
785 		BString urlAddress;
786 		parse_named_url(url, urlName, urlAddress);
787 
788 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
789 			&kLinkBlue);
790 		fCreditsView->InsertHyperText(urlName,
791 			new URLAction(urlAddress));
792 		fCreditsView->Insert("\n");
793 	}
794 	fCreditsView->Insert("\n");
795 }
796 
797 
798 void
799 AboutView::PickRandomHaiku()
800 {
801 	BPath path;
802 	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
803 		path = "/system/data";
804 	path.Append("fortunes");
805 	path.Append("Haiku");
806 
807 	BFile fortunes(path.Path(), B_READ_ONLY);
808 	struct stat st;
809 	if (fortunes.InitCheck() < B_OK)
810 		return;
811 	if (fortunes.GetStat(&st) < B_OK)
812 		return;
813 
814 	char* buff = (char*)malloc((size_t)st.st_size + 1);
815 	if (!buff)
816 		return;
817 	buff[(size_t)st.st_size] = '\0';
818 	BList haikuList;
819 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
820 		char* p = buff;
821 		while (p && *p) {
822 			char* e = strchr(p, '%');
823 			BString* s = new BString(p, e ? (e - p) : -1);
824 			haikuList.AddItem(s);
825 			p = e;
826 			if (p && (*p == '%'))
827 				p++;
828 			if (p && (*p == '\n'))
829 				p++;
830 		}
831 	}
832 	free(buff);
833 	if (haikuList.CountItems() < 1)
834 		return;
835 
836 	BString* s = (BString*)haikuList.ItemAt(rand() % haikuList.CountItems());
837 	BFont font(be_bold_font);
838 	font.SetSize(be_bold_font->Size());
839 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
840 	fCreditsView->SelectAll();
841 	fCreditsView->Delete();
842 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
843 	fCreditsView->Insert(s->String());
844 	fCreditsView->Insert("\n");
845 	while ((s = (BString*)haikuList.RemoveItem((int32)0))) {
846 		delete s;
847 	}
848 }
849 
850 
851 void
852 AboutView::_AdjustTextColors()
853 {
854 	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
855 	rgb_color color = mix_color(ViewColor(), textColor, 192);
856 
857 	BView* view = NULL;
858 	for (int32 index = 0; index < fSubTextViews.CountItems(); ++index) {
859 		view = fSubTextViews.ItemAt(index);
860 		view->SetHighColor(color);
861 		view->Invalidate();
862 	}
863 
864 	// Labels
865 	for (int32 index = 0; index < fTextViews.CountItems(); ++index) {
866 		view = fTextViews.ItemAt(index);
867 		view->SetHighColor(textColor);
868 		view->Invalidate();
869 	}
870 }
871 
872 
873 BView*
874 AboutView::_CreateLabel(const char* name, const char* label)
875 {
876 	BStringView* labelView = new BStringView(name, label);
877 	labelView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
878 		B_ALIGN_VERTICAL_UNSET));
879 	labelView->SetFont(be_bold_font);
880 	fTextViews.AddItem(labelView);
881 	return labelView;
882 }
883 
884 
885 BView*
886 AboutView::_CreateCreditsView()
887 {
888 	// Begin construction of the credits view
889 	fCreditsView = new HyperTextView("credits");
890 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
891 	fCreditsView->SetStylable(true);
892 	fCreditsView->MakeEditable(false);
893 	fCreditsView->SetWordWrap(true);
894 	fCreditsView->SetInsets(5, 5, 5, 5);
895 	fCreditsView->SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
896 
897 	BScrollView* creditsScroller = new BScrollView("creditsScroller",
898 		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
899 		B_PLAIN_BORDER);
900 
901 	// Haiku copyright
902 	BFont font(be_bold_font);
903 	font.SetSize(font.Size() + 4);
904 
905 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
906 	fCreditsView->Insert("Haiku\n");
907 
908 	char string[1024];
909 	time_t time = ::time(NULL);
910 	struct tm* tm = localtime(&time);
911 	int32 year = tm->tm_year + 1900;
912 	if (year < 2008)
913 		year = 2008;
914 	snprintf(string, sizeof(string),
915 		COPYRIGHT_STRING "2001-%" B_PRId32 " The Haiku project. ", year);
916 
917 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
918 	fCreditsView->Insert(string);
919 
920 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
921 	fCreditsView->Insert(B_TRANSLATE("The copyright to the Haiku code is "
922 		"property of Haiku, Inc. or of the respective authors where expressly "
923 		"noted in the source. Haiku" B_UTF8_REGISTERED
924 		" and the HAIKU logo" B_UTF8_REGISTERED
925 		" are registered trademarks of Haiku, Inc."
926 		"\n\n"));
927 
928 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
929 	fCreditsView->InsertHyperText("https://www.haiku-os.org",
930 		new URLAction("https://www.haiku-os.org"));
931 	fCreditsView->Insert("\n\n");
932 
933 	font.SetSize(be_bold_font->Size());
934 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
935 
936 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
937 	fCreditsView->Insert(B_TRANSLATE("Current maintainers:\n"));
938 
939 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
940 	fCreditsView->Insert(kCurrentMaintainers);
941 
942 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
943 	fCreditsView->Insert(B_TRANSLATE("Past maintainers:\n"));
944 
945 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
946 	fCreditsView->Insert(kPastMaintainers);
947 
948 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
949 	fCreditsView->Insert(B_TRANSLATE("Website & marketing:\n"));
950 
951 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
952 	fCreditsView->Insert(kWebsiteTeam);
953 
954 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
955 	fCreditsView->Insert(B_TRANSLATE("Past website & marketing:\n"));
956 
957 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
958 	fCreditsView->Insert(kPastWebsiteTeam);
959 
960 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
961 	fCreditsView->Insert(B_TRANSLATE("Contributors:\n"));
962 
963 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
964 	fCreditsView->Insert(kContributors);
965 	fCreditsView->Insert(
966 		B_TRANSLATE("\n" B_UTF8_ELLIPSIS
967 			"and probably some more we forgot to mention (sorry!)"
968 			"\n\n"));
969 
970 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
971 	fCreditsView->Insert(B_TRANSLATE("Translations:\n"));
972 
973 	BLanguage* lang;
974 	BString langName;
975 
976 	BList sortedTranslations;
977 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
978 		const Translation* translation = &kTranslations[i];
979 		sortedTranslations.AddItem((void*)translation);
980 	}
981 	sortedTranslations.SortItems(TranslationComparator);
982 
983 	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
984 		const Translation& translation
985 			= *(const Translation*)sortedTranslations.ItemAt(i);
986 
987 		langName.Truncate(0);
988 		if (BLocaleRoster::Default()->GetLanguage(translation.languageCode,
989 				&lang) == B_OK) {
990 			lang->GetName(langName);
991 			delete lang;
992 		} else {
993 			// We failed to get the localized readable name,
994 			// go with what we have.
995 			langName.Append(translation.languageCode);
996 		}
997 
998 		fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
999 		fCreditsView->Insert("\n");
1000 		fCreditsView->Insert(langName);
1001 		fCreditsView->Insert("\n");
1002 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1003 		fCreditsView->Insert(translation.names);
1004 	}
1005 
1006 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
1007 	fCreditsView->Insert(B_TRANSLATE("\n\nSpecial thanks to:\n"));
1008 
1009 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1010 	BString beosCredits(B_TRANSLATE(
1011 		"Be Inc. and its developer team, for having created BeOS!\n\n"));
1012 	int32 beosOffset = beosCredits.FindFirst("BeOS");
1013 	fCreditsView->Insert(beosCredits.String(),
1014 		(beosOffset < 0) ? beosCredits.Length() : beosOffset);
1015 	if (beosOffset > -1) {
1016 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSBlue);
1017 		fCreditsView->Insert("B");
1018 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBeOSRed);
1019 		fCreditsView->Insert("e");
1020 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1021 		beosCredits.Remove(0, beosOffset + 2);
1022 		fCreditsView->Insert(beosCredits.String(), beosCredits.Length());
1023 	}
1024 	fCreditsView->Insert(
1025 		B_TRANSLATE("Travis Geiselbrecht (and his NewOS kernel)\n"));
1026 	fCreditsView->Insert(
1027 		B_TRANSLATE("Michael Phipps (project founder)\n\n"));
1028 	fCreditsView->Insert(
1029 		B_TRANSLATE("The HaikuPorts team\n"));
1030 	fCreditsView->Insert(
1031 		B_TRANSLATE("The Haikuware team and their bounty program\n"));
1032 	fCreditsView->Insert(
1033 		B_TRANSLATE("The BeGeistert team\n"));
1034 	fCreditsView->Insert(
1035 		B_TRANSLATE("Google and their Google Summer of Code and Google Code In "
1036 			"programs\n"));
1037 	fCreditsView->Insert(
1038 		B_TRANSLATE("The University of Auckland and Christof Lutteroth\n\n"));
1039 	fCreditsView->Insert(
1040 		B_TRANSLATE(B_UTF8_ELLIPSIS "and the many people making donations!\n\n"));
1041 
1042 	// copyrights for various projects we use
1043 
1044 	BPath mitPath;
1045 	_GetLicensePath("MIT", mitPath);
1046 	BPath lgplPath;
1047 	_GetLicensePath("GNU LGPL v2.1", lgplPath);
1048 
1049 	font.SetSize(be_bold_font->Size() + 4);
1050 	font.SetFace(B_BOLD_FACE);
1051 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
1052 	fCreditsView->Insert(B_TRANSLATE("\nCopyrights\n\n"));
1053 
1054 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
1055 	fCreditsView->Insert(B_TRANSLATE("[Click a license name to read the "
1056 		"respective license.]\n\n"));
1057 
1058 	// Haiku license
1059 	BString haikuLicense = B_TRANSLATE_COMMENT("The code that is unique to "
1060 		"Haiku, especially the kernel and all code that applications may link "
1061 		"against, is distributed under the terms of the <MIT license>. "
1062 		"Some system libraries contain third party code distributed under the "
1063 		"<LGPL license>. You can find the copyrights to third party code below."
1064 		"\n\n", "<MIT license> and <LGPL license> aren't variables and can be "
1065 		"translated. However, please, don't remove < and > as they're needed "
1066 		"as placeholders for proper hypertext functionality.");
1067 	int32 licensePart1 = haikuLicense.FindFirst("<");
1068 	int32 licensePart2 = haikuLicense.FindFirst(">");
1069 	int32 licensePart3 = haikuLicense.FindLast("<");
1070 	int32 licensePart4 = haikuLicense.FindLast(">");
1071 	BString part;
1072 	haikuLicense.CopyInto(part, 0, licensePart1);
1073 	fCreditsView->Insert(part);
1074 
1075 	part.Truncate(0);
1076 	haikuLicense.CopyInto(part, licensePart1 + 1, licensePart2 - 1
1077 		- licensePart1);
1078 	fCreditsView->InsertHyperText(part, new OpenFileAction(mitPath.Path()));
1079 
1080 	part.Truncate(0);
1081 	haikuLicense.CopyInto(part, licensePart2 + 1, licensePart3 - 1
1082 		- licensePart2);
1083 	fCreditsView->Insert(part);
1084 
1085 	part.Truncate(0);
1086 	haikuLicense.CopyInto(part, licensePart3 + 1, licensePart4 - 1
1087 		- licensePart3);
1088 	fCreditsView->InsertHyperText(part, new OpenFileAction(lgplPath.Path()));
1089 
1090 	part.Truncate(0);
1091 	haikuLicense.CopyInto(part, licensePart4 + 1, haikuLicense.Length() - 1
1092 		- licensePart4);
1093 	fCreditsView->Insert(part);
1094 
1095 	// GNU copyrights
1096 	AddCopyrightEntry("The GNU Project",
1097 		B_TRANSLATE("Contains software from the GNU Project, "
1098 		"released under the GPL and LGPL licenses:\n"
1099 		"GNU C Library, "
1100 		"GNU coretools, diffutils, findutils, "
1101 		"sharutils, gawk, bison, m4, make, "
1102 		"wget, ncurses, termcap, "
1103 		"Bourne Again Shell.\n"
1104 		COPYRIGHT_STRING "The Free Software Foundation."),
1105 		StringVector(kLGPLv21, kGPLv2, kGPLv3, NULL),
1106 		StringVector(),
1107 		"https://www.gnu.org");
1108 
1109 	// FreeBSD copyrights
1110 	AddCopyrightEntry("The FreeBSD Project",
1111 		B_TRANSLATE("Contains software from the FreeBSD Project, "
1112 		"released under the BSD license:\n"
1113 		"ftpd, ping, telnet, telnetd, traceroute\n"
1114 		COPYRIGHT_STRING "1994-2008 The FreeBSD Project. "
1115 		"All rights reserved."),
1116 		StringVector(kBSDTwoClause, kBSDThreeClause, kBSDFourClause,
1117 			NULL),
1118 		StringVector(),
1119 		"https://www.freebsd.org");
1120 
1121 	// NetBSD copyrights
1122 	AddCopyrightEntry("The NetBSD Project",
1123 		B_TRANSLATE("Contains software developed by the NetBSD "
1124 		"Foundation, Inc. and its contributors:\n"
1125 		"ftp, tput\n"
1126 		COPYRIGHT_STRING "1996-2008 The NetBSD Foundation, Inc. "
1127 		"All rights reserved."),
1128 		StringVector(kBerkeley, kBSDFourClause, NULL),
1129 		StringVector(),
1130 		"https://www.netbsd.org");
1131 
1132 	// FFmpeg copyrights
1133 	_AddPackageCredit(PackageCredit("FFmpeg")
1134 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000-2014 Fabrice "
1135 			"Bellard, et al."))
1136 		.SetLicenses(kLGPLv21, kLGPLv2, NULL)
1137 		.SetURL("https://www.ffmpeg.org"));
1138 
1139 	// AGG copyrights
1140 	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
1141 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2006 Maxim "
1142 			"Shemanarev (McSeem)."))
1143 		.SetLicenses("Anti-Grain Geometry", kBSDThreeClause, NULL)
1144 		.SetURL("http://www.antigrain.com"));
1145 
1146 	// FreeType copyrights
1147 	_AddPackageCredit(PackageCredit("FreeType2")
1148 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1996-2002, 2006 "
1149 			"David Turner, Robert Wilhelm and Werner Lemberg."),
1150 			COPYRIGHT_STRING "2014 The FreeType Project. "
1151 			"All rights reserved.",
1152 			NULL)
1153 		.SetLicense("FreeType")
1154 		.SetURL("http://www.freetype.org"));
1155 
1156 	// Mesa3D (http://www.mesa3d.org) copyrights
1157 	_AddPackageCredit(PackageCredit("Mesa")
1158 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2006 Brian Paul. "
1159 			"Mesa3D Project. All rights reserved."))
1160 		.SetLicense("MIT")
1161 		.SetURL("http://www.mesa3d.org"));
1162 
1163 	// SGI's GLU implementation copyrights
1164 	_AddPackageCredit(PackageCredit("GLU")
1165 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1991-2000 "
1166 			"Silicon Graphics, Inc. All rights reserved."))
1167 		.SetLicense("SGI Free B")
1168 		.SetURL("http://www.sgi.com/products/software/opengl"));
1169 
1170 	// GLUT implementation copyrights
1171 	_AddPackageCredit(PackageCredit("GLUT")
1172 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
1173 			"All rights reserved."),
1174 			COPYRIGHT_STRING "1997 Be Inc.",
1175 			COPYRIGHT_STRING "1999 Jake Hamby.",
1176 			NULL)
1177 		.SetLicense("MIT")
1178 		.SetURL("http://www.opengl.org/resources/libraries/glut"));
1179 
1180 	// OpenGroup & DEC (BRegion backend) copyright
1181 	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
1182 		.SetCopyrights(COPYRIGHT_STRING "1987-1988, 1998 The Open Group.",
1183 			B_TRANSLATE(COPYRIGHT_STRING "1987-1988 Digital Equipment "
1184 			"Corporation, Maynard, Massachusetts.\n"
1185 			"All rights reserved."),
1186 			NULL)
1187 		.SetLicenses("OpenGroup", "DEC", NULL)
1188 		.SetURL("https://xfree86.org"));
1189 
1190 	// Bitstream Charter font
1191 	_AddPackageCredit(PackageCredit("Bitstream Charter font")
1192 		.SetCopyrights(COPYRIGHT_STRING "1989-1992 Bitstream Inc.,"
1193 			"Cambridge, MA.",
1194 			B_TRANSLATE("BITSTREAM CHARTER is a registered trademark of "
1195 				"Bitstream Inc."),
1196 			NULL)
1197 		.SetLicense("Bitstream Charter")
1198 		.SetURL("http://www.bitstream.com/"));
1199 
1200 	// Noto fonts copyright
1201 	_AddPackageCredit(PackageCredit("Noto fonts")
1202 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING
1203 			"2012-2016 Google Internationalization team."),
1204 			NULL)
1205 		.SetLicense("SIL Open Font Licence v1.1")
1206 		.SetURL("http://www.google.com/get/noto/"));
1207 
1208 	// expat copyrights
1209 	_AddPackageCredit(PackageCredit("expat")
1210 		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1998-2000 Thai "
1211 			"Open Source Software Center Ltd and Clark Cooper."),
1212 			B_TRANSLATE(COPYRIGHT_STRING "2001-2003 Expat maintainers."),
1213 			NULL)
1214 		.SetLicense("Expat")
1215 		.SetURL("http://expat.sourceforge.net"));
1216 
1217 	// zlib copyrights
1218 	_AddPackageCredit(PackageCredit("zlib")
1219 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2004 Jean-loup "
1220 			"Gailly and Mark Adler."))
1221 		.SetLicense("Zlib")
1222 		.SetURL("http://www.zlib.net"));
1223 
1224 	// zip copyrights
1225 	_AddPackageCredit(PackageCredit("Info-ZIP")
1226 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1990-2002 Info-ZIP. "
1227 			"All rights reserved."))
1228 		.SetLicense("Info-ZIP")
1229 		.SetURL("http://www.info-zip.org"));
1230 
1231 	// bzip2 copyrights
1232 	_AddPackageCredit(PackageCredit("bzip2")
1233 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-2005 Julian R "
1234 			"Seward. All rights reserved."))
1235 		.SetLicense(kBSDFourClause)
1236 		.SetURL("http://bzip.org"));
1237 
1238 	// OpenEXR copyrights
1239 	_AddPackageCredit(PackageCredit("OpenEXR")
1240 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2014 Industrial "
1241 			"Light & Magic, a division of Lucas Digital Ltd. LLC."))
1242 		.SetLicense(kBSDThreeClause)
1243 		.SetURL("http://www.openexr.com"));
1244 
1245 	// acpica copyrights
1246 	_AddPackageCredit(PackageCredit("ACPI Component Architecture (ACPICA)")
1247 		.SetCopyright(COPYRIGHT_STRING "1999-2018 Intel Corp.")
1248 		.SetLicense("Intel (ACPICA)")
1249 		.SetURL("https://www.acpica.org"));
1250 
1251 	// libpng copyrights
1252 	_AddPackageCredit(PackageCredit("libpng")
1253 		.SetCopyright(COPYRIGHT_STRING "1995-2017 libpng authors")
1254 		.SetLicense("LibPNG")
1255 		.SetURL("http://www.libpng.org"));
1256 
1257 	// libjpeg copyrights
1258 	_AddPackageCredit(PackageCredit("libjpeg")
1259 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1994-2009, Thomas G. "
1260 			"Lane, Guido Vollbeding. This software is based in part on the "
1261 			"work of the Independent JPEG Group."))
1262 		.SetLicense("LibJPEG")
1263 		.SetURL("http://www.ijg.org"));
1264 
1265 	// libprint copyrights
1266 	_AddPackageCredit(PackageCredit("libprint")
1267 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2000 Y.Takagi. "
1268 			"All rights reserved.")));
1269 			// TODO: License!
1270 
1271 	// cortex copyrights
1272 	_AddPackageCredit(PackageCredit("Cortex")
1273 		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon.")
1274 		.SetLicense(kBSDThreeClause)
1275 		.SetURL("http://cortex.sourceforge.net/documentation"));
1276 
1277 	// FluidSynth copyrights
1278 	_AddPackageCredit(PackageCredit("FluidSynth")
1279 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003 Peter Hanappe "
1280 			"and others."))
1281 		.SetLicense(kLGPLv2)
1282 		.SetURL("http://www.fluidsynth.org"));
1283 
1284 	// Xiph.org Foundation copyrights
1285 	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1286 		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1287 			B_TRANSLATE(COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1288 			"All rights reserved."), NULL)
1289 		.SetLicense(kBSDThreeClause)
1290 		.SetURL("http://www.xiph.org"));
1291 
1292 	// Matroska
1293 	_AddPackageCredit(PackageCredit("libmatroska")
1294 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1295 			"All rights reserved."))
1296 		.SetLicense(kLGPLv21)
1297 		.SetURL("http://www.matroska.org"));
1298 
1299 	// BColorQuantizer (originally CQuantizer code)
1300 	_AddPackageCredit(PackageCredit("CQuantizer")
1301 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1302 			"All rights reserved."))
1303 		.SetLicense("CQuantizer")
1304 		.SetURL("http://www.xdp.it"));
1305 
1306 	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1307 	_AddPackageCredit(PackageCredit("MAPM")
1308 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2007 Michael C. "
1309 			"Ring. All rights reserved."))
1310 		.SetLicense("MAPM")
1311 		.SetURL("http://tc.umn.edu/~ringx004"));
1312 
1313 	// MkDepend 1.7 copyright (Makefile dependency generator)
1314 	_AddPackageCredit(PackageCredit("MkDepend")
1315 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2001 Lars Düning. "
1316 			"All rights reserved."))
1317 		.SetLicense("MIT")
1318 		.SetURL("http://bearnip.com/lars/be"));
1319 
1320 	// libhttpd copyright (used as Poorman backend)
1321 	_AddPackageCredit(PackageCredit("libhttpd")
1322 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995, 1998-2001 "
1323 			"Jef Poskanzer. All rights reserved."))
1324 		.SetLicense(kBSDTwoClause)
1325 		.SetURL("http://www.acme.com/software/thttpd/"));
1326 
1327 #ifdef __INTEL__
1328 	// Udis86 copyrights
1329 	_AddPackageCredit(PackageCredit("Udis86")
1330 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2004 "
1331 			"Vivek Mohan. All rights reserved."))
1332 		.SetLicense(kBSDTwoClause)
1333 		.SetURL("http://udis86.sourceforge.net"));
1334 
1335 	// Intel PRO/Wireless 2100 & 2200BG firmwares
1336 	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2100 & 2200BG firmwares")
1337 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003-2006 "
1338 			"Intel Corporation. All rights reserved."))
1339 		.SetLicense(kIntel2xxxFirmware)
1340 		.SetURL("http://www.intellinuxwireless.org/"));
1341 
1342 	// Intel wireless firmwares
1343 	_AddPackageCredit(
1344 		PackageCredit("Intel PRO/Wireless network adapter firmwares")
1345 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2015 "
1346 			"Intel Corporation. All rights reserved."))
1347 		.SetLicense(kIntelFirmware)
1348 		.SetURL("http://www.intellinuxwireless.org/"));
1349 
1350 	// Marvell 88w8363
1351 	_AddPackageCredit(PackageCredit("Marvell 88w8363")
1352 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007-2009 "
1353 			"Marvell Semiconductor, Inc. All rights reserved."))
1354 		.SetLicense(kMarvellFirmware)
1355 		.SetURL("http://www.marvell.com/"));
1356 
1357 	// Ralink Firmware RT2501/RT2561/RT2661
1358 	_AddPackageCredit(PackageCredit("Ralink Firmware RT2501/RT2561/RT2661")
1359 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007 "
1360 			"Ralink Technology Corporation. All rights reserved."))
1361 		.SetLicense(kRalinkFirmware)
1362 		.SetURL("http://www.ralinktech.com/"));
1363 #endif
1364 
1365 	// Gutenprint
1366 	_AddPackageCredit(PackageCredit("Gutenprint")
1367 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1368 			"1999-2010 by the authors of Gutenprint. All rights reserved."))
1369 		.SetLicense(kGPLv2)
1370 		.SetURL("http://gutenprint.sourceforge.net/"));
1371 
1372 	// libwebp
1373 	_AddPackageCredit(PackageCredit("libwebp")
1374 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
1375 			"2010-2011 Google Inc. All rights reserved."))
1376 		.SetLicense(kBSDThreeClause)
1377 		.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
1378 
1379 	// GTF
1380 	_AddPackageCredit(PackageCredit("GTF")
1381 		.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
1382 			"Generalized Timing Formula"))
1383 		.SetLicense(kBSDThreeClause)
1384 		.SetURL("http://gtf.sourceforge.net/"));
1385 
1386 	// libqrencode
1387 	_AddPackageCredit(PackageCredit("libqrencode")
1388 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi"))
1389 		.SetLicense(kLGPLv21)
1390 		.SetURL("http://fukuchi.org/works/qrencode/"));
1391 
1392 	// scrypt
1393 	_AddPackageCredit(PackageCredit("scrypt")
1394 		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2009 Colin Percival"))
1395 		.SetLicense(kBSDTwoClause)
1396 		.SetURL("https://tarsnap.com/scrypt.html"));
1397 
1398 	_AddCopyrightsFromAttribute();
1399 	_AddPackageCreditEntries();
1400 
1401 	return new CropView(creditsScroller, 0, 1, 1, 1);
1402 }
1403 
1404 
1405 status_t
1406 AboutView::_GetLicensePath(const char* license, BPath& path)
1407 {
1408 	BPathFinder pathFinder;
1409 	BStringList paths;
1410 	struct stat st;
1411 
1412 	status_t error = pathFinder.FindPaths(B_FIND_PATH_DATA_DIRECTORY,
1413 		"licenses", paths);
1414 
1415 	for (int i = 0; i < paths.CountStrings(); ++i) {
1416 		if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
1417 			&& path.Append(license) == B_OK
1418 			&& lstat(path.Path(), &st) == 0) {
1419 			return B_OK;
1420 		}
1421 	}
1422 
1423 	path.Unset();
1424 	return B_ENTRY_NOT_FOUND;
1425 }
1426 
1427 
1428 void
1429 AboutView::_AddCopyrightsFromAttribute()
1430 {
1431 #ifdef __HAIKU__
1432 	// open the app executable file
1433 	char appPath[B_PATH_NAME_LENGTH];
1434 	int appFD;
1435 	if (BPrivate::get_app_path(appPath) != B_OK
1436 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1437 		return;
1438 	}
1439 
1440 	// open the attribute
1441 	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1442 	close(appFD);
1443 	if (attrFD < 0)
1444 		return;
1445 
1446 	// attach it to a FILE
1447 	FILE* attrFile = fdopen(attrFD, "r");
1448 	if (attrFile == NULL) {
1449 		close(attrFD);
1450 		return;
1451 	}
1452 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1453 
1454 	// read and parse the copyrights
1455 	BMessage package;
1456 	BString fieldName;
1457 	BString fieldValue;
1458 	char lineBuffer[LINE_MAX];
1459 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1460 		// chop off line break
1461 		size_t lineLen = strlen(line);
1462 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1463 			line[--lineLen] = '\0';
1464 
1465 		// flush previous field, if a new field begins, otherwise append
1466 		if (lineLen == 0 || !isspace(line[0])) {
1467 			// new field -- flush the previous one
1468 			if (fieldName.Length() > 0) {
1469 				fieldValue = trim_string(fieldValue.String(),
1470 					fieldValue.Length());
1471 				package.AddString(fieldName.String(), fieldValue);
1472 				fieldName = "";
1473 			}
1474 		} else if (fieldName.Length() > 0) {
1475 			// append to current field
1476 			fieldValue += line;
1477 			continue;
1478 		} else {
1479 			// bogus line -- ignore
1480 			continue;
1481 		}
1482 
1483 		if (lineLen == 0)
1484 			continue;
1485 
1486 		// parse new field
1487 		char* colon = strchr(line, ':');
1488 		if (colon == NULL) {
1489 			// bogus line -- ignore
1490 			continue;
1491 		}
1492 
1493 		fieldName.SetTo(line, colon - line);
1494 		fieldName = trim_string(line, colon - line);
1495 		if (fieldName.Length() == 0) {
1496 			// invalid field name
1497 			continue;
1498 		}
1499 
1500 		fieldValue = colon + 1;
1501 
1502 		if (fieldName == "Package") {
1503 			// flush the current package
1504 			_AddPackageCredit(PackageCredit(package));
1505 			package.MakeEmpty();
1506 		}
1507 	}
1508 
1509 	// flush current package
1510 	_AddPackageCredit(PackageCredit(package));
1511 #endif
1512 }
1513 
1514 
1515 void
1516 AboutView::_AddPackageCreditEntries()
1517 {
1518 	// sort the packages case-insensitively
1519 	PackageCredit* packages[fPackageCredits.size()];
1520 	int32 count = 0;
1521 	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1522 			it != fPackageCredits.end(); ++it) {
1523 		packages[count++] = it->second;
1524 	}
1525 
1526 	if (count > 1) {
1527 		std::sort(packages, packages + count,
1528 			&PackageCredit::NameLessInsensitive);
1529 	}
1530 
1531 	// add the credits
1532 	for (int32 i = 0; i < count; i++) {
1533 		PackageCredit* package = packages[i];
1534 
1535 		BString text(package->CopyrightAt(0));
1536 		int32 count = package->CountCopyrights();
1537 		for (int32 i = 1; i < count; i++)
1538 			text << "\n" << package->CopyrightAt(i);
1539 
1540 		AddCopyrightEntry(package->PackageName(), text.String(),
1541 			package->Licenses(), package->Sources(), package->URL());
1542 	}
1543 }
1544 
1545 
1546 void
1547 AboutView::_AddPackageCredit(const PackageCredit& package)
1548 {
1549 	if (!package.IsValid())
1550 		return;
1551 
1552 	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
1553 	if (it != fPackageCredits.end()) {
1554 		// If the new package credit isn't "better" than the old one, ignore it.
1555 		PackageCredit* oldPackage = it->second;
1556 		if (!package.IsBetterThan(*oldPackage))
1557 			return;
1558 
1559 		// replace the old credit
1560 		fPackageCredits.erase(it);
1561 		delete oldPackage;
1562 	}
1563 
1564 	fPackageCredits[package.PackageName()] = new PackageCredit(package);
1565 }
1566 
1567 
1568 //	#pragma mark -
1569 
1570 
1571 static const char*
1572 MemSizeToString(char string[], size_t size, system_info* info)
1573 {
1574 	int inaccessibleMemory = int(info->ignored_pages
1575 		* (B_PAGE_SIZE / 1048576.0f) + 0.5f);
1576 	if (inaccessibleMemory > 0) {
1577 		BString message(B_TRANSLATE("%total MiB total, %inaccessible MiB "
1578 			"inaccessible"));
1579 
1580 		snprintf(string, size, "%d", int((info->max_pages
1581 			+ info->ignored_pages) * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1582 		message.ReplaceFirst("%total", string);
1583 
1584 		snprintf(string, size, "%d", inaccessibleMemory);
1585 		message.ReplaceFirst("%inaccessible", string);
1586 		strlcpy(string, message.String(), size);
1587 	} else {
1588 		snprintf(string, size, B_TRANSLATE("%d MiB total"),
1589 			int(info->max_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f));
1590 	}
1591 
1592 	return string;
1593 }
1594 
1595 
1596 static const char*
1597 MemUsageToString(char string[], size_t size, system_info* info)
1598 {
1599 	snprintf(string, size, B_TRANSLATE("%d MiB used (%d%%)"),
1600 		int(info->used_pages * (B_PAGE_SIZE / 1048576.0f) + 0.5f),
1601 		int(100 * info->used_pages / info->max_pages));
1602 
1603 	return string;
1604 }
1605 
1606 
1607 static const char*
1608 UptimeToString(char string[], size_t size)
1609 {
1610 	BDurationFormat formatter;
1611 	BString str;
1612 
1613 	bigtime_t uptime = system_time();
1614 	bigtime_t now = (bigtime_t)time(NULL) * 1000000;
1615 	formatter.Format(str, now - uptime, now);
1616 	str.CopyInto(string, 0, size);
1617 	string[std::min((size_t)str.Length(), size)] = '\0';
1618 
1619 	return string;
1620 }
1621 
1622 
1623 int
1624 main()
1625 {
1626 	AboutApp app;
1627 	app.Run();
1628 	return 0;
1629 }
1630 
1631