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