xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
1 /*
2  * Copyright (c) 2005-2008, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		René Gollent
8  */
9 
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <sys/utsname.h>
13 #include <time.h>
14 
15 #include <AppFileInfo.h>
16 #include <Application.h>
17 #include <Bitmap.h>
18 #include <File.h>
19 #include <FindDirectory.h>
20 #include <Font.h>
21 #include <fs_attr.h>
22 #include <MessageRunner.h>
23 #include <Messenger.h>
24 #include <OS.h>
25 #include <Path.h>
26 #include <Query.h>
27 #include <Resources.h>
28 #include <Screen.h>
29 #include <ScrollView.h>
30 #include <String.h>
31 #include <StringView.h>
32 #include <TranslationUtils.h>
33 #include <TranslatorFormats.h>
34 #include <View.h>
35 #include <Volume.h>
36 #include <VolumeRoster.h>
37 #include <Window.h>
38 
39 #include <AppMisc.h>
40 #include <AutoDeleter.h>
41 #include <cpu_type.h>
42 
43 #include "HyperTextActions.h"
44 #include "HyperTextView.h"
45 #include "Utilities.h"
46 
47 
48 #define SCROLL_CREDITS_VIEW 'mviv'
49 #define READ_APP_QUERY_ENT 'raqe'
50 
51 
52 static const char *UptimeToString(char string[], size_t size);
53 static const char *MemUsageToString(char string[], size_t size,
54 	system_info *info);
55 
56 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
57 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
58 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
59 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
60 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
61 
62 
63 class AboutApp : public BApplication {
64 	public:
65 		AboutApp(void);
66 };
67 
68 class AboutWindow : public BWindow {
69 	public:
70 				AboutWindow(void);
71 		bool	QuitRequested(void);
72 };
73 
74 class AboutView : public BView {
75 	public:
76 				AboutView(const BRect &r);
77 				~AboutView(void);
78 
79 		virtual void AttachedToWindow();
80 		virtual void Pulse();
81 
82 		virtual void FrameResized(float width, float height);
83 		virtual void Draw(BRect update);
84 		virtual void MessageReceived(BMessage *msg);
85 		virtual void MouseDown(BPoint pt);
86 
87 		void	AddCopyrightEntry(const char *name, const char *text,
88 					const Licenses& licenses, const char *url);
89 		void	AddCopyrightEntry(const char *name, const char *text,
90 					const char *url = NULL);
91 		void	AddCopyrightEntry(const BMessage& packageDescription);
92 		void	PickRandomHaiku();
93 
94 	private:
95 		void	_AddCopyrightsFromAttribute();
96 
97 		BStringView		*fMemView;
98 		BStringView		*fUptimeView;
99 		BView			*fInfoView;
100 		HyperTextView	*fCreditsView;
101 
102 		BBitmap			*fLogo;
103 
104 		BPoint			fDrawPoint;
105 
106 		bigtime_t		fLastActionTime;
107 		BMessageRunner	*fScrollRunner;
108 		BQuery			fAppsQuery;
109 };
110 
111 
112 //	#pragma mark -
113 
114 
115 AboutApp::AboutApp(void)
116 	: BApplication("application/x-vnd.Haiku-About")
117 {
118 	AboutWindow *window = new AboutWindow();
119 	window->Show();
120 }
121 
122 
123 //	#pragma mark -
124 
125 
126 AboutWindow::AboutWindow()
127 	: BWindow(BRect(0, 0, 500, 300), "About This System", B_TITLED_WINDOW,
128 			B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
129 {
130 	AboutView *view = new AboutView(Bounds());
131 	AddChild(view);
132 
133 	// start reading from the app query
134 	BMessage msg(READ_APP_QUERY_ENT);
135 	BMessenger msgr(view);
136 	msgr.SendMessage(&msg);
137 
138 	MoveTo((BScreen().Frame().Width() - Bounds().Width()) / 2,
139 		(BScreen().Frame().Height() - Bounds().Height()) / 2 );
140 }
141 
142 
143 bool
144 AboutWindow::QuitRequested()
145 {
146 	be_app->PostMessage(B_QUIT_REQUESTED);
147 	return true;
148 }
149 
150 
151 AboutView::AboutView(const BRect &rect)
152 	: BView(rect, "aboutview", B_FOLLOW_ALL, B_WILL_DRAW | B_PULSE_NEEDED),
153 	fLastActionTime(system_time()),
154 	fScrollRunner(NULL)
155 {
156 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "haikulogo.png");
157 	if (fLogo) {
158 		fDrawPoint.x = (225-fLogo->Bounds().Width()) / 2;
159 		fDrawPoint.y = 0;
160 	}
161 
162 	// Begin Construction of System Information controls
163 
164 	font_height height;
165 	float labelHeight, textHeight;
166 
167 	system_info systemInfo;
168 	get_system_info(&systemInfo);
169 
170 	be_plain_font->GetHeight(&height);
171 	textHeight = height.ascent + height.descent + height.leading;
172 
173 	be_bold_font->GetHeight(&height);
174 	labelHeight = height.ascent + height.descent + height.leading;
175 
176 	BRect r(0, 0, 225, Bounds().bottom);
177 	if (fLogo)
178 		r.OffsetBy(0, fLogo->Bounds().Height());
179 
180 	fInfoView = new BView(r, "infoview", B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
181 		B_WILL_DRAW);
182 	fInfoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
183 	fInfoView->SetLowColor(fInfoView->ViewColor());
184 	fInfoView->SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
185 	AddChild(fInfoView);
186 
187 	// Add all the various labels for system infomation
188 
189 	BStringView *stringView;
190 
191 	// OS Version
192 	r.Set(5, 5, 224, labelHeight + 5);
193 	stringView = new BStringView(r, "oslabel", "Version:");
194 	stringView->SetFont(be_bold_font);
195 	fInfoView->AddChild(stringView);
196 	stringView->ResizeToPreferred();
197 
198 	// we update "labelHeight" to the actual height of the string view
199 	labelHeight = stringView->Bounds().Height();
200 
201 	r.OffsetBy(0, labelHeight);
202 	r.bottom = r.top + textHeight;
203 
204 	char string[1024];
205 	strcpy(string, "Unknown");
206 
207 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
208 	BPath path;
209 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
210 		path.Append("libbe.so");
211 
212 		BAppFileInfo appFileInfo;
213 		version_info versionInfo;
214 		BFile file;
215 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
216 			&& appFileInfo.SetTo(&file) == B_OK
217 			&& appFileInfo.GetVersionInfo(&versionInfo,
218 				B_APP_VERSION_KIND) == B_OK
219 			&& versionInfo.short_info[0] != '\0')
220 			strcpy(string, versionInfo.short_info);
221 	}
222 
223 	// Add revision from uname() info
224 	utsname unameInfo;
225 	if (uname(&unameInfo) == 0) {
226 		long revision;
227 		if (sscanf(unameInfo.version, "r%ld", &revision) == 1) {
228 			char version[16];
229 			snprintf(version, sizeof(version), "%ld", revision);
230 			strlcat(string, " (Revision ", sizeof(string));
231 			strlcat(string, version, sizeof(string));
232 			strlcat(string, ")", sizeof(string));
233 		}
234 	}
235 
236 	stringView = new BStringView(r, "ostext", string);
237 	fInfoView->AddChild(stringView);
238 	stringView->ResizeToPreferred();
239 
240 	// GCC version
241 #if __GNUC__ != 2
242 	r.OffsetBy(0, textHeight);
243 	r.bottom = r.top + textHeight;
244 
245 	snprintf(string, sizeof(string), "GCC %d", __GNUC__);
246 
247 	stringView = new BStringView(r, "gcctext", string);
248 	fInfoView->AddChild(stringView);
249 	stringView->ResizeToPreferred();
250 #endif
251 
252 	// CPU count, type and clock speed
253 	r.OffsetBy(0, textHeight * 1.5);
254 	r.bottom = r.top + labelHeight;
255 
256 	if (systemInfo.cpu_count > 1)
257 		sprintf(string, "%ld Processors:", systemInfo.cpu_count);
258 	else
259 		strcpy(string, "Processor:");
260 
261 	stringView = new BStringView(r, "cpulabel", string);
262 	stringView->SetFont(be_bold_font);
263 	fInfoView->AddChild(stringView);
264 	stringView->ResizeToPreferred();
265 
266 	BString cpuType;
267 	cpuType << get_cpu_vendor_string(systemInfo.cpu_type)
268 		<< " " << get_cpu_model_string(&systemInfo);
269 
270 	r.OffsetBy(0, labelHeight);
271 	r.bottom = r.top + textHeight;
272 	stringView = new BStringView(r, "cputext", cpuType.String());
273 	fInfoView->AddChild(stringView);
274 	stringView->ResizeToPreferred();
275 
276 	r.OffsetBy(0, textHeight);
277 	r.bottom = r.top + textHeight;
278 
279 	int32 clockSpeed = get_rounded_cpu_speed();
280 	if (clockSpeed < 1000)
281 		sprintf(string,"%ld MHz", clockSpeed);
282 	else
283 		sprintf(string,"%.2f GHz", clockSpeed / 1000.0f);
284 
285 	stringView = new BStringView(r, "mhztext", string);
286 	fInfoView->AddChild(stringView);
287 	stringView->ResizeToPreferred();
288 
289 	// RAM
290 	r.OffsetBy(0, textHeight * 1.5);
291 	r.bottom = r.top + labelHeight;
292 	stringView = new BStringView(r, "ramlabel", "Memory:");
293 	stringView->SetFont(be_bold_font);
294 	fInfoView->AddChild(stringView);
295 	stringView->ResizeToPreferred();
296 
297 	r.OffsetBy(0, labelHeight);
298 	r.bottom = r.top + textHeight;
299 
300 	fMemView = new BStringView(r, "ramtext", "");
301 	fInfoView->AddChild(fMemView);
302 	fMemView->SetText(MemUsageToString(string, sizeof(string), &systemInfo));
303 
304 	// Kernel build time/date
305 	r.OffsetBy(0, textHeight * 1.5);
306 	r.bottom = r.top + labelHeight;
307 	stringView = new BStringView(r, "kernellabel", "Kernel:");
308 	stringView->SetFont(be_bold_font);
309 	fInfoView->AddChild(stringView);
310 	stringView->ResizeToPreferred();
311 
312 	r.OffsetBy(0, labelHeight);
313 	r.bottom = r.top + textHeight;
314 
315 	snprintf(string, sizeof(string), "%s %s",
316 		systemInfo.kernel_build_date, systemInfo.kernel_build_time);
317 
318 	stringView = new BStringView(r, "kerneltext", string);
319 	fInfoView->AddChild(stringView);
320 	stringView->ResizeToPreferred();
321 
322 	// Uptime
323 	r.OffsetBy(0, textHeight * 1.5);
324 	r.bottom = r.top + labelHeight;
325 	stringView = new BStringView(r, "uptimelabel", "Time Running:");
326 	stringView->SetFont(be_bold_font);
327 	fInfoView->AddChild(stringView);
328 	stringView->ResizeToPreferred();
329 
330 	r.OffsetBy(0, labelHeight);
331 	r.bottom = r.top + textHeight;
332 
333 	fUptimeView = new BStringView(r, "uptimetext", "");
334 	fInfoView->AddChild(fUptimeView);
335 	// string width changes, so we don't do ResizeToPreferred()
336 
337 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
338 
339 	// Begin construction of the credits view
340 	r = Bounds();
341 	r.left += fInfoView->Bounds().right + 1;
342 	r.right -= B_V_SCROLL_BAR_WIDTH;
343 
344 	fCreditsView = new HyperTextView(r, "credits",
345 		r.OffsetToCopy(0, 0).InsetByCopy(5, 5), B_FOLLOW_ALL);
346 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS );
347 	fCreditsView->SetStylable(true);
348 	fCreditsView->MakeEditable(false);
349 	fCreditsView->MakeSelectable(false);
350 	fCreditsView->SetWordWrap(true);
351 
352 	BScrollView *creditsScroller = new BScrollView("creditsScroller",
353 		fCreditsView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
354 		B_PLAIN_BORDER);
355 	AddChild(creditsScroller);
356 
357 	// Haiku copyright
358 	BFont font(be_bold_font);
359 	font.SetSize(font.Size() + 4);
360 
361 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
362 	fCreditsView->Insert("Haiku\n");
363 
364 	time_t time = ::time(NULL);
365 	struct tm* tm = localtime(&time);
366 	int32 year = tm->tm_year + 1900;
367 	if (year < 2008)
368 		year = 2008;
369 	snprintf(string, sizeof(string),
370 		"Copyright " B_UTF8_COPYRIGHT " 2001-%ld The Haiku project.", year);
371 
372 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
373 	fCreditsView->Insert(string);
374 
375 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
376 	fCreditsView->Insert("The copyright to the Haiku code is property of "
377 		"Haiku, Inc. or of the respective authors where expressly noted "
378 		"in the source."
379 		"\n\n");
380 
381 
382 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
383 	fCreditsView->InsertHyperText("http://www.haiku-os.org",
384 		new URLAction("http://www.haiku-os.org"));
385 	fCreditsView->Insert("\n\n");
386 
387 	font.SetSize(be_bold_font->Size());
388 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
389 
390 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
391 	fCreditsView->Insert("Current Maintainers:\n");
392 
393 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
394 	fCreditsView->Insert(
395 		"Ithamar R. Adema\n"
396 		"Bruno G. Albuquerque\n"
397 		"Stephan Aßmus\n"
398 		"Salvatore Benedetto\n"
399 		"Stefano Ceccherini\n"
400 		"Rudolf Cornelissen\n"
401 		"Alexandre Deckner\n"
402 		"Oliver Ruiz Dorantes\n"
403 		"Axel Dörfler\n"
404 		"Jérôme Duval\n"
405 		"René Gollent\n"
406 		"Karsten Heimrich\n"
407 		"Philippe Houdoin\n"
408 		"Maurice Kalinowski\n"
409 		"Euan Kirkhope\n"
410 		"Ryan Leavengood\n"
411 		"Michael Lotz\n"
412 		"David McPaul\n"
413 		"Fredrik Modéen\n"
414 		"Marcus Overhagen\n"
415 		"Michael Pfeiffer\n"
416 		"François Revol\n"
417 		"Andrej Spielmann\n"
418 		"Oliver Tappe\n"
419 		"Gerasim Troeglazov\n"
420 		"Ingo Weinhold\n"
421 		"Siarzhuk Zharski\n"
422 		"\n");
423 
424 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
425 	fCreditsView->Insert("Past Maintainers:\n");
426 
427 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
428 	fCreditsView->Insert(
429 		"Andrew Bachmann\n"
430 		"Tyler Dauwalder\n"
431 		"Daniel Furrer\n"
432 		"Andre Alves Garzia\n"
433 		"Erik Jaesler\n"
434 		"Marcin Konicki\n"
435 		"Waldemar Kornewald\n"
436 		"Thomas Kurschel\n"
437 		"Frans Van Nispen\n"
438 		"Adi Oanca\n"
439 		"Michael Phipps\n"
440 		"Niels Sascha Reedijk\n"
441 		"David Reid\n"
442 		"Hugo Santos\n"
443 		"Alexander G. M. Smith\n"
444 		"Jonas Sundström\n"
445 		"Bryan Varner\n"
446 		"Nathan Whitehorn\n"
447 		"Michael Wilber\n"
448 		"Jonathan Yoder\n"
449 		"Gabe Yoder\n"
450 		"\n");
451 
452 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
453 	fCreditsView->Insert("Website, Marketing & Documentation:\n");
454 
455 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
456 	fCreditsView->Insert(
457 		"Phil Greenway\n"
458 		"Gavin James\n"
459 		"Urias McCullough\n"
460 		"Niels Sascha Reedijk\n"
461 		"Jonathan Yoder\n"
462 		"\n");
463 
464 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
465 	fCreditsView->Insert("Contributors:\n");
466 
467 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
468 	fCreditsView->Insert(
469 		"Andrea Anzani\n"
470 		"Andre Braga\n"
471 		"Bruce Cameron\n"
472 		"Greg Crain\n"
473 		"David Dengg\n"
474 		"John Drinkwater\n"
475 		"Cian Duffy\n"
476 		"Christian Fasshauer\n"
477 		"Andreas Färber\n"
478 		"Marc Flerackers\n"
479 		"Matthijs Hollemans\n"
480 		"Mathew Hounsell\n"
481 		"Morgan Howe\n"
482 		"Carwyn Jones\n"
483 		"Vasilis Kaoutsis\n"
484 		"James Kim\n"
485 		"Shintaro Kinugawa\n"
486 		"Jan Klötzke\n"
487 		"Kurtis Kopf\n"
488 		"Tomáš Kučera\n"
489 		"Luboš Kulič\n"
490 		"Elad Lahav\n"
491 		"Anthony Lee\n"
492 		"Santiago Lema\n"
493 		"Raynald Lesieur\n"
494 		"Oscar Lesta\n"
495 		"Jerome Leveque\n"
496 		"Christof Lutteroth\n"
497 		"Graham MacDonald\n"
498 		"Jan Matějek\n"
499 		"Brian Matzon\n"
500 		"Christopher ML Zumwalt May\n"
501 		"Andrew McCall\n"
502 		"Scott McCreary\n"
503 		"Michele (zuMi)\n"
504 		"Marius Middelthon\n"
505 		"Marco Minutoli\n"
506 		"Misza\n"
507 		"MrSiggler\n"
508 		"Alan Murta\n"
509 		"Pahtz\n"
510 		"Michael Paine\n"
511 		"David Powell\n"
512 		"Jeremy Rand\n"
513 		"Hartmut Reh\n"
514 		"Daniel Reinhold\n"
515 		"Samuel Rodriguez Perez\n"
516 		"Thomas Roell\n"
517 		"Rafael Romo\n"
518 		"Philippe Saint-Pierre\n"
519 		"Ralf Schülke\n"
520 		"Reznikov Sergei\n"
521 		"Zousar Shaker\n"
522 		"Daniel Switkin\n"
523 		"Atsushi Takamatsu\n"
524 		"James Urquhart\n"
525 		"Jason Vandermark\n"
526 		"Sandor Vroemisse\n"
527 		"Denis Washington\n"
528 		"Ulrich Wimboeck\n"
529 		"James Woodcock\n"
530 		"Artur Wyszynski\n"
531 		"Gerald Zajac\n"
532 		"Łukasz Zemczak\n"
533 		"JiSheng Zhang\n"
534 		"Zhao Shuai\n"
535 		"\n" B_UTF8_ELLIPSIS " and probably some more we forgot to mention "
536 		"(sorry!)"
537 		"\n\n");
538 
539 
540 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
541 	fCreditsView->Insert("Special Thanks To:\n");
542 
543 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
544 	fCreditsView->Insert("Travis Geiselbrecht (and his NewOS kernel)\n");
545 	fCreditsView->Insert("Michael Phipps (project founder)\n\n");
546 
547 	// copyrights for various projects we use
548 
549 	font.SetSize(be_bold_font->Size() + 4);
550 	font.SetFace(B_BOLD_FACE);
551 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
552 	fCreditsView->Insert("\nCopyrights\n\n");
553 
554 	// GNU copyrights
555 	AddCopyrightEntry("The GNU Project",
556 		"Contains software from the GNU Project, "
557 		"released under the GPL and LGPL licences:\n"
558 		"GNU C Library, "
559 		"GNU coretools, diffutils, findutils, "
560 		"sharutils, gawk, bison, m4, make, "
561 		"gdb, wget, ncurses, termcap, "
562 		"Bourne Again Shell.\n"
563 		"Copyright " B_UTF8_COPYRIGHT " The Free Software Foundation.",
564 		Licenses("GNU LGPL v2.1", "GNU GPL v2", "GNU GPL v3", NULL),
565 		"http://www.gnu.org");
566 
567 	// FreeBSD copyrights
568 	AddCopyrightEntry("The FreeBSD Project",
569 		"Contains software from the FreeBSD Project, "
570 		"released under the BSD licence:\n"
571 		"cal, ftpd, ping, telnet, "
572 		"telnetd, traceroute\n"
573 		"Copyright " B_UTF8_COPYRIGHT " 1994-2008 The FreeBSD Project.  "
574 		"All rights reserved.",
575 		"http://www.freebsd.org");
576 
577 	// NetBSD copyrights
578 	AddCopyrightEntry("The NetBSD Project",
579 		"Contains software developed by the NetBSD, "
580 		"Foundation, Inc. and its contributors:\n"
581 		"ftp, tput\n"
582 		"Copyright " B_UTF8_COPYRIGHT " 1996-2008 The NetBSD Foundation, Inc.  "
583 		"All rights reserved.",
584 		"http://www.netbsd.org");
585 
586 	// FFMpeg copyrights
587 	AddCopyrightEntry("FFMpeg libavcodec",
588 		"Copyright " B_UTF8_COPYRIGHT " 2000-2007 Fabrice Bellard, et al.",
589 		"http://www.ffmpeg.org");
590 
591 	// AGG copyrights
592 	AddCopyrightEntry("AntiGrain Geometry",
593 		"Copyright " B_UTF8_COPYRIGHT " 2002-2006 Maxim Shemanarev (McSeem).",
594 		"http://www.antigrain.com");
595 
596 	// PDFLib copyrights
597 	AddCopyrightEntry("PDFLib",
598 		"Copyright " B_UTF8_COPYRIGHT " 1997-2006 PDFlib GmbH and Thomas Merz. "
599 		"All rights reserved.\n"
600 		"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH.",
601 		"http://www.pdflib.com");
602 
603 	// FreeType copyrights
604 	AddCopyrightEntry("FreeType2",
605 		"Portions of this software are copyright " B_UTF8_COPYRIGHT " 1996-2006 "
606 		"The FreeType Project.  All rights reserved.",
607 		"http://www.freetype.org");
608 
609 	// Mesa3D (http://www.mesa3d.org) copyrights
610 	AddCopyrightEntry("Mesa",
611 		"Copyright " B_UTF8_COPYRIGHT " 1999-2006 Brian Paul. "
612 		"Mesa3D project.  All rights reserved.",
613 		"http://www.mesa3d.org");
614 
615 	// SGI's GLU implementation copyrights
616 	AddCopyrightEntry("GLU",
617 		"Copyright " B_UTF8_COPYRIGHT " 1991-2000 Silicon Graphics, Inc. "
618 		"SGI's Software FreeB license.  All rights reserved.");
619 
620 	// GLUT implementation copyrights
621 	AddCopyrightEntry("GLUT",
622 		"Copyright " B_UTF8_COPYRIGHT " 1994-1997 Mark Kilgard. "
623 		"All rights reserved.\n"
624 		"Copyright " B_UTF8_COPYRIGHT " 1997 Be Inc.\n"
625 		"Copyright " B_UTF8_COPYRIGHT " 1999 Jake Hamby.");
626 
627 	// OpenGroup & DEC (BRegion backend) copyright
628 	AddCopyrightEntry("BRegion backend (XFree86)",
629 		"Copyright " B_UTF8_COPYRIGHT " 1987, 1988, 1998  The Open Group.\n"
630 		"Copyright " B_UTF8_COPYRIGHT " 1987, 1988 Digital Equipment "
631 		"Corporation, Maynard, Massachusetts.\n"
632 		"All rights reserved.");
633 
634 	// Konatu font
635 	AddCopyrightEntry("Konatu font",
636 		"Copyright " B_UTF8_COPYRIGHT " 2002- MASUDA mitiya.\n"
637 		"MIT license. All rights reserved.");
638 
639 	// expat copyrights
640 	AddCopyrightEntry("expat",
641 		"Copyright " B_UTF8_COPYRIGHT " 1998, 1999, 2000 Thai Open Source "
642 		"Software Center Ltd and Clark Cooper.\n"
643 		"Copyright " B_UTF8_COPYRIGHT " 2001, 2002, 2003 Expat maintainers.");
644 
645 	// zlib copyrights
646 	AddCopyrightEntry("zlib",
647 		"Copyright " B_UTF8_COPYRIGHT " 1995-2004 Jean-loup Gailly and Mark "
648 		"Adler.");
649 
650 	// zip copyrights
651 	AddCopyrightEntry("Info-ZIP",
652 		"Copyright " B_UTF8_COPYRIGHT " 1990-2002 Info-ZIP. All rights reserved.");
653 
654 	// bzip2 copyrights
655 	AddCopyrightEntry("bzip2",
656 		"Copyright " B_UTF8_COPYRIGHT " 1996-2005 Julian R Seward. All rights "
657 		"reserved.");
658 
659 	// VIM copyrights
660 	AddCopyrightEntry("Vi IMproved",
661 		"Copyright " B_UTF8_COPYRIGHT " Bram Moolenaar et al.");
662 
663 	// lp_solve copyrights
664 	AddCopyrightEntry("lp_solve",
665 		"Copyright " B_UTF8_COPYRIGHT
666 			" Michel Berkelaar, Kjell Eikland, Peter Notebaert",
667 		"http://lpsolve.sourceforge.net/");
668 			// license: LGPL
669 
670 	// OpenEXR copyrights
671 	AddCopyrightEntry("OpenEXR",
672 		"Copyright " B_UTF8_COPYRIGHT " 2002-2005 Industrial Light & Magic, "
673 		"a division of Lucas Digital Ltd. LLC.");
674 
675 	// Bullet copyrights
676 	AddCopyrightEntry("Bullet",
677 		"Copyright " B_UTF8_COPYRIGHT " 2003-2008 Erwin Coumans",
678 		"http://www.bulletphysics.com");
679 
680 	// atftp copyrights
681 	AddCopyrightEntry("atftp",
682 		"Copyright " B_UTF8_COPYRIGHT " 2000 Jean-Pierre Lefebvre and Remi "
683 		"Lefebvre");
684 
685 	// Netcat copyrights
686 	AddCopyrightEntry("Netcat",
687 		"Copyright " B_UTF8_COPYRIGHT " 1996 Hobbit");
688 
689 	// acpica copyrights
690 	AddCopyrightEntry("acpica",
691 		"Copyright " B_UTF8_COPYRIGHT " 1999-2006 Intel Corp.");
692 
693 	// unrar copyrights
694 	AddCopyrightEntry("unrar",
695 		"Copyright " B_UTF8_COPYRIGHT " 2002-2008 Alexander L. Roshal. "
696 		"All rights reserved.",
697 		"http://www.rarlab.com");
698 
699 // p7zip copyrights
700 //	AddCopyrightEntry("p7zip",
701 //		"Copyright " B_UTF8_COPYRIGHT " 2008 Igor Pavlov. "
702 //		"All rights reserved.");
703 
704 	// libpng copyrights
705 	AddCopyrightEntry("libpng",
706 		"Copyright " B_UTF8_COPYRIGHT " 2004, 2006-2008 Glenn "
707 		"Randers-Pehrson.");
708 
709 	// libprint copyrights
710 	AddCopyrightEntry("libprint",
711 		"Copyright " B_UTF8_COPYRIGHT " 1999-2000 Y.Takagi. All rights "
712 		"reserved.");
713 
714 	// cortex copyrights
715 	AddCopyrightEntry("Cortex",
716 		"Copyright " B_UTF8_COPYRIGHT " 1999-2000 Eric Moon.");
717 
718 	// FluidSynth copyrights
719 	AddCopyrightEntry("FluidSynth",
720 		"Copyright " B_UTF8_COPYRIGHT " 2003 Peter Hanappe and others.");
721 
722 	// CannaIM copyrights
723 	AddCopyrightEntry("CannaIM",
724 		"Copyright " B_UTF8_COPYRIGHT " 1999 Masao Kawamura.");
725 
726 	// libxml2, libxslt, libexslt copyrights
727 	AddCopyrightEntry("libxml2, libxslt",
728 		"Copyright " B_UTF8_COPYRIGHT " 1998-2003 Daniel Veillard. "
729 		"All rights reserved.");
730 
731 	AddCopyrightEntry("libexslt",
732 		"Copyright " B_UTF8_COPYRIGHT " 2001-2002 Thomas Broyer, Charlie "
733 		"Bozeman and Daniel Veillard.  All rights reserved.");
734 
735 	// Xiph.org Foundation copyrights
736 	AddCopyrightEntry("Xiph.org Foundation",
737 		"libvorbis, libogg, libtheora, libspeex"
738 		"Copyright " B_UTF8_COPYRIGHT " 1994-2008 Xiph.Org. "
739 		"All rights reserved.",
740 		"http://www.xiph.org");
741 
742 	// The Tcpdump Group
743 	AddCopyrightEntry("The Tcpdump Group",
744 		"tcpdump, libpcap",
745 		"http://www.tcpdump.org");
746 
747 	// Matroska
748 	AddCopyrightEntry("libmatroska",
749 		"Copyright " B_UTF8_COPYRIGHT " 2002-2003 Steve Lhomme. "
750 		"All rights reserved.",
751 		"http://www.matroska.org");
752 
753 	// BColorQuantizer (originally CQuantizer code)
754 	AddCopyrightEntry("CQuantizer",
755 		"Copyright " B_UTF8_COPYRIGHT " 1996-1997 Jeff Prosise. "
756 		"All rights reserved.");
757 
758 // OpenSound
759 //	AddCopyrightEntry("OpenSound",
760 //		"Copyright " B_UTF8_COPYRIGHT " 1996-2008 4Front Technologies ",
761 //		"http://www.opensound.com");
762 // BSD license
763 
764 #ifdef __INTEL__
765 	// Udis86 copyrights
766 	AddCopyrightEntry("Udis86",
767 		"Copyright " B_UTF8_COPYRIGHT " 2002, 2003, 2004 Vivek Mohan. "
768 		"All rights reserved.",
769 		"http://udis86.sourceforge.net");
770 #endif
771 
772 	_AddCopyrightsFromAttribute();
773 
774 	// Build a list of installed applications and show their
775 	// long version info. Well-behaved apps usually give
776 	// copyright info there.
777 
778 	font.SetSize(be_bold_font->Size() + 4);
779 	font.SetFace(B_BOLD_FACE);
780 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
781 	fCreditsView->Insert("\nInstalled applications\n\n");
782 
783 	BVolume bootVolume;
784 	BVolumeRoster().GetBootVolume(&bootVolume);
785 	fAppsQuery.SetVolume(&bootVolume);
786 	if (fAppsQuery.SetPredicate(
787 			"((BEOS:APP_SIG==\"**\")&&(name!=\"*.so\")&&(name!=\"*.rsrc\")&&"
788 			"(BEOS:TYPE==\"application/x-vnd.Be-elfexecutable\"))") >= B_OK) {
789 		fAppsQuery.Fetch();
790 	}
791 }
792 
793 
794 AboutView::~AboutView(void)
795 {
796 	delete fScrollRunner;
797 }
798 
799 
800 void
801 AboutView::AttachedToWindow(void)
802 {
803 	BView::AttachedToWindow();
804 	Window()->SetPulseRate(500000);
805 	SetEventMask(B_POINTER_EVENTS);
806 }
807 
808 
809 void
810 AboutView::MouseDown(BPoint pt)
811 {
812 	BRect r(92, 26, 105, 31);
813 	if (r.Contains(pt)) {
814 		printf("Easter Egg\n");
815 		PickRandomHaiku();
816 	}
817 
818 	if (Bounds().Contains(pt)) {
819 		fLastActionTime = system_time();
820 		delete fScrollRunner;
821 		fScrollRunner = NULL;
822 	}
823 }
824 
825 
826 void
827 AboutView::FrameResized(float width, float height)
828 {
829 	BRect r = fCreditsView->Bounds();
830 	r.OffsetTo(B_ORIGIN);
831 	r.InsetBy(3, 3);
832 	fCreditsView->SetTextRect(r);
833 }
834 
835 
836 void
837 AboutView::Draw(BRect update)
838 {
839 	if (fLogo)
840 		DrawBitmap(fLogo, fDrawPoint);
841 }
842 
843 
844 void
845 AboutView::Pulse(void)
846 {
847 	char string[255];
848 	system_info info;
849 	get_system_info(&info);
850 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
851 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
852 
853 	if (fScrollRunner == NULL && (system_time() > fLastActionTime + 10000000)) {
854 		BMessage message(SCROLL_CREDITS_VIEW);
855 		//fScrollRunner = new BMessageRunner(this, &message, 300000, -1);
856 	}
857 }
858 
859 
860 void
861 AboutView::MessageReceived(BMessage *msg)
862 {
863 	switch (msg->what) {
864 		case SCROLL_CREDITS_VIEW:
865 		{
866 			BScrollBar *scrollBar = fCreditsView->ScrollBar(B_VERTICAL);
867 			if (scrollBar == NULL)
868 				break;
869 			float max, min;
870 			scrollBar->GetRange(&min, &max);
871 			if (scrollBar->Value() < max)
872 				fCreditsView->ScrollBy(0, 5);
873 
874 			break;
875 		}
876 
877 		case READ_APP_QUERY_ENT:
878 		{
879 			BEntry ent;
880 			if (fAppsQuery.GetNextEntry(&ent) < B_OK) {
881 				fAppsQuery.Clear();
882 				fCreditsView->MakeSelectable(true);
883 				break;
884 			}
885 			BFile file;
886 			BPath path;
887 			if (ent.Exists() &&
888 				ent.GetPath(&path) >= B_OK &&
889 				file.SetTo(&ent, B_READ_ONLY) >= B_OK) {
890 				/* filter only apps */
891 				if (strncmp(path.Path(), "/boot/apps", 10) == 0) {
892 					BAppFileInfo appFileInfo(&file);
893 					uint32 flags;
894 					version_info version;
895 					if (appFileInfo.InitCheck() >= B_OK &&
896 						appFileInfo.GetAppFlags(&flags) >= B_OK &&
897 						appFileInfo.GetVersionInfo(&version,
898 							B_APP_VERSION_KIND) >= B_OK) {
899 						//printf("AppFileInfo for %s :\n", path.Path());
900 						//printf("flags: %08x\n", flags);
901 						BString name;
902 						BString info;
903 						name << path.Leaf();
904 						if (strlen(version.short_info) &&
905 							strcmp(version.short_info, path.Leaf()))
906 							name << " (" << version.short_info << ")";
907 						/*
908 						info << "\tVersion: ";
909 						info << version.major << ".";
910 						info << version.middle << ".";
911 						info << version.minor;
912 						char varieties[] = "dabgmf";
913 						if (version.variety > B_FINAL_VERSION)
914 							info << "?";
915 						else
916 							info << varieties[version.variety];
917 						info << version.internal;
918 						info << "\n";
919 						*/
920 						info << version.long_info;
921 						AddCopyrightEntry(name.String(), info.String());
922 
923 					}
924 				}
925 			}
926 			// note for self: read next entry :)
927 			BMessage m(READ_APP_QUERY_ENT);
928 			BMessenger(this).SendMessage(&m);
929 			break;
930 		}
931 
932 		default:
933 			BView::MessageReceived(msg);
934 			break;
935 	}
936 }
937 
938 
939 void
940 AboutView::AddCopyrightEntry(const char *name, const char *text,
941 	const char *url)
942 {
943 	AddCopyrightEntry(name, text, NULL, url);
944 }
945 
946 
947 void
948 AboutView::AddCopyrightEntry(const char *name, const char *text,
949 	const Licenses& licenses, const char *url)
950 {
951 	BFont font(be_bold_font);
952 	//font.SetSize(be_bold_font->Size());
953 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
954 
955 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
956 	fCreditsView->Insert(name);
957 	fCreditsView->Insert("\n");
958 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
959 	fCreditsView->Insert(text);
960 	fCreditsView->Insert("\n");
961 
962 	if (licenses.CountLicenses() > 0) {
963 		if (licenses.CountLicenses() > 1)
964 			fCreditsView->Insert("Licenses: ");
965 		else
966 			fCreditsView->Insert("License: ");
967 
968 		for (int32 i = 0; i < licenses.CountLicenses(); i++) {
969 			const char* license = licenses.LicenseAt(i);
970 			BString licensePath("/etc/licenses/");
971 			licensePath += license;
972 
973 			if (i > 0)
974 				fCreditsView->Insert(", ");
975 
976 			fCreditsView->InsertHyperText(license,
977 				new OpenFileAction(licensePath));
978 		}
979 
980 		fCreditsView->Insert("\n");
981 	}
982 
983 	if (url) {
984 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
985 		fCreditsView->InsertHyperText(url, new URLAction(url));
986 		fCreditsView->Insert("\n");
987 	}
988 	fCreditsView->Insert("\n");
989 }
990 
991 
992 void
993 AboutView::AddCopyrightEntry(const BMessage& packageDescription)
994 {
995 	const char* package;
996 	const char* copyright;
997 	const char* url;
998 
999 	// package and copyright are mandatory
1000 	if (packageDescription.FindString("Package", &package) != B_OK
1001 		|| packageDescription.FindString("Copyright", &copyright) != B_OK) {
1002 		return;
1003 	}
1004 
1005 	// URL is optional
1006 	if (packageDescription.FindString("URL", &url) != B_OK)
1007 		url = NULL;
1008 
1009 	BString copyrightLine("Copyright " B_UTF8_COPYRIGHT " ");
1010 	copyrightLine += copyright;
1011 
1012 	AddCopyrightEntry(package, copyrightLine.String(), packageDescription, url);
1013 }
1014 
1015 
1016 void
1017 AboutView::PickRandomHaiku()
1018 {
1019 	BFile fortunes(
1020 #ifdef __HAIKU__
1021 		"/etc/fortunes/Haiku",
1022 #else
1023 		"data/etc/fortunes/Haiku",
1024 #endif
1025 		B_READ_ONLY);
1026 	struct stat st;
1027 	if (fortunes.InitCheck() < B_OK)
1028 		return;
1029 	if (fortunes.GetStat(&st) < B_OK)
1030 		return;
1031 	char *buff = (char *)malloc((size_t)st.st_size + 1);
1032 	if (!buff)
1033 		return;
1034 	buff[(size_t)st.st_size] = '\0';
1035 	BList haikuList;
1036 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
1037 		char *p = buff;
1038 		while (p && *p) {
1039 			char *e = strchr(p, '%');
1040 			BString *s = new BString(p, e ? (e - p) : -1);
1041 			haikuList.AddItem(s);
1042 			p = e;
1043 			if (p && (*p == '%'))
1044 				p++;
1045 			if (p && (*p == '\n'))
1046 				p++;
1047 		}
1048 	}
1049 	free(buff);
1050 	if (haikuList.CountItems() < 1)
1051 		return;
1052 	BString *s = (BString *)haikuList.ItemAt(rand() % haikuList.CountItems());
1053 	BFont font(be_bold_font);
1054 	font.SetSize(be_bold_font->Size());
1055 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1056 	fCreditsView->SelectAll();
1057 	fCreditsView->Delete();
1058 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
1059 	fCreditsView->Insert(s->String());
1060 	fCreditsView->Insert("\n");
1061 	while ((s = (BString *)haikuList.RemoveItem((int32)0))) {
1062 		delete s;
1063 	}
1064 }
1065 
1066 
1067 void
1068 AboutView::_AddCopyrightsFromAttribute()
1069 {
1070 	// open the app executable file
1071 	char appPath[B_PATH_NAME_LENGTH];
1072 	int appFD;
1073 	if (BPrivate::get_app_path(appPath) != B_OK
1074 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1075 		return;
1076 	}
1077 
1078 	// open the attribute
1079 	int attrFD = fs_open_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1080 	close(appFD);
1081 	if (attrFD < 0)
1082 		return;
1083 
1084 	// attach it to a FILE
1085 	FILE* attrFile = fdopen(attrFD, "r");
1086 	if (attrFile == NULL) {
1087 		close(attrFD);
1088 		return;
1089 	}
1090 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1091 
1092 	// read and parse the copyrights
1093 	BMessage package;
1094 	BString fieldName;
1095 	BString fieldValue;
1096 	char lineBuffer[LINE_MAX];
1097 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1098 		// chop off line break
1099 		size_t lineLen = strlen(line);
1100 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1101 			line[--lineLen] = '\0';
1102 
1103 		// flush previous field, if a new field begins, otherwise append
1104 		if (lineLen == 0 || !isspace(line[0])) {
1105 			// new field -- flush the previous one
1106 			if (fieldName.Length() > 0) {
1107 				fieldValue = trim_string(fieldValue.String(),
1108 					fieldValue.Length());
1109 				package.AddString(fieldName.String(), fieldValue);
1110 				fieldName = "";
1111 			}
1112 		} else if (fieldName.Length() > 0) {
1113 			// append to current field
1114 			fieldValue += line;
1115 			continue;
1116 		} else {
1117 			// bogus line -- ignore
1118 			continue;
1119 		}
1120 
1121 		if (lineLen == 0)
1122 			continue;
1123 
1124 		// parse new field
1125 		char* colon = strchr(line, ':');
1126 		if (colon == NULL) {
1127 			// bogus line -- ignore
1128 			continue;
1129 		}
1130 
1131 		fieldName.SetTo(line, colon - line);
1132 		fieldName = trim_string(line, colon - line);
1133 		if (fieldName.Length() == 0) {
1134 			// invalid field name
1135 			continue;
1136 		}
1137 
1138 		fieldValue = colon + 1;
1139 
1140 		if (fieldName == "Package") {
1141 			// flush the current package
1142 			AddCopyrightEntry(package);
1143 			package.MakeEmpty();
1144 		}
1145 	}
1146 
1147 	// flush current package
1148 	AddCopyrightEntry(package);
1149 }
1150 
1151 
1152 //	#pragma mark -
1153 
1154 
1155 static const char *
1156 MemUsageToString(char string[], size_t size, system_info *info)
1157 {
1158 	snprintf(string, size, "%d MB total, %d MB used (%d%%)",
1159 			int(info->max_pages / 256.0f + 0.5f),
1160 			int(info->used_pages / 256.0f + 0.5f),
1161 			int(100 * info->used_pages / info->max_pages));
1162 
1163 	return string;
1164 }
1165 
1166 
1167 static const char *
1168 UptimeToString(char string[], size_t size)
1169 {
1170 	int64 days, hours, minutes, seconds, remainder;
1171 	int64 systime = system_time();
1172 
1173 	days = systime / 86400000000LL;
1174 	remainder = systime % 86400000000LL;
1175 
1176 	hours = remainder / 3600000000LL;
1177 	remainder = remainder % 3600000000LL;
1178 
1179 	minutes = remainder / 60000000;
1180 	remainder = remainder % 60000000;
1181 
1182 	seconds = remainder / 1000000;
1183 
1184 	char *str = string;
1185 	if (days) {
1186 		str += snprintf(str, size, "%lld day%s",days, days > 1 ? "s" : "");
1187 	}
1188 	if (hours) {
1189 		str += snprintf(str, size - strlen(string), "%s%lld hour%s",
1190 				str != string ? ", " : "",
1191 				hours, hours > 1 ? "s" : "");
1192 	}
1193 	if (minutes) {
1194 		str += snprintf(str, size - strlen(string), "%s%lld minute%s",
1195 				str != string ? ", " : "",
1196 				minutes, minutes > 1 ? "s" : "");
1197 	}
1198 
1199 	if (seconds || str == string) {
1200 		// Haiku would be well-known to boot very fast.
1201 		// Let's be ready to handle below minute uptime, zero second included ;-)
1202 		str += snprintf(str, size - strlen(string), "%s%lld second%s",
1203 				str != string ? ", " : "",
1204 				seconds, seconds > 1 ? "s" : "");
1205 	}
1206 
1207 	return string;
1208 }
1209 
1210 
1211 int
1212 main()
1213 {
1214 	AboutApp app;
1215 	app.Run();
1216 	return 0;
1217 }
1218 
1219