Add menus (not all wired yet) and about window
diff --git a/src/LoggerApp.cpp b/src/LoggerApp.cpp
index 1c62c75..fc29708 100644
--- a/src/LoggerApp.cpp
+++ b/src/LoggerApp.cpp
@@ -4,6 +4,7 @@
  * Distributed under terms of the MIT license.
  */
 
+#include <private/interface/AboutWindow.h>
 #include <Application.h>
 #include <private/interface/ColumnListView.h>
 #include <private/interface/ColumnTypes.h>
@@ -73,11 +74,55 @@
 		fEventList->AddColumn(new BColorStringColumn("Name", 100, 50, 200), 0);
 		fEventList->AddColumn(new BColorStringColumn("Text", INT16_MAX, 50, INT16_MAX), 1);
 
+		BMenuBar* mainMenu = new BMenuBar("main menu");
+
+		BMessage* separatorMessage = new BMessage(BEDC_MESSAGE);
+		separatorMessage->AddInt8("bedc_type", DC_SEPARATOR);
+
+		BMessage* clearMessage = new BMessage(BEDC_MESSAGE);
+		clearMessage->AddInt8("bedc_type", DC_CLEAR);
+
+		BLayoutBuilder::Menu<>(mainMenu)
+			.AddMenu("File")
+				.AddItem("New window", new BMessage(), 'N')
+				.AddItem("Activate window", new BMessage(), 'S')
+					.SetEnabled(false)
+				.AddSeparator()
+				.AddItem("About…", new BMessage(B_ABOUT_REQUESTED))
+				.AddSeparator()
+				.AddItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')
+			.End()
+			.AddMenu("Edit")
+				.AddItem("Cut", new BMessage(), 'X')
+				.AddItem("Copy", new BMessage(), 'C')
+				.AddItem("Delete", new BMessage(), 'D')
+				.AddSeparator()
+				.AddItem("Clear", clearMessage, 'E')
+				.AddItem("Select all", new BMessage(), 'A')
+				.AddSeparator()
+				.AddItem("Preferences", new BMessage())
+			.End()
+			.AddMenu("Tools")
+				.AddItem("Add separator", separatorMessage, 'S')
+				.AddSeparator()
+				.AddItem("Save to file…", new BMessage())
+				.AddItem("Save selection to file…", new BMessage())
+			.End()
+		.End();
+
 		BLayoutBuilder::Group<>(layout)
 			.SetInsets(0, -1, -1, -1)
-			.Add(new BMenuBar("main menu"))
+			.Add(mainMenu)
 			.Add(fEventList)
 		.End();
+
+		// TODO make all menu items work
+		// TODO add status bar with online/offline status and line counter
+		//      Newest created window becomes active, deactivates all other
+		//      Actve window can be switched from menu
+		//      Active window has its 'activate window' menu disabled, using the shortcut adds a
+		//      separator instead
+		// TODO add line numbers in list view
 	}
 
 	void MessageReceived(BMessage* message) override
@@ -85,9 +130,7 @@
 		switch(message->what) {
 			case BEDC_MESSAGE:
 			{
-				// TODO parse all info: bedc_ver, bedc_main_type
-				// bedc_ver: "1.0" (can be changed in later versions if the message format changes)
-				// bedc_main_type: BEDC_BMESSAGE or BEDC_PLAIN_MESSAGE
+				// TODO parse bedc_ver to handle mulitple protocol versions
 				BString name = message->FindString("bedc_name");
 				BString text = message->FindString("bedc_text");
 				int8 colorEnum = message->FindInt8("bedc_color");
@@ -101,16 +144,16 @@
 
 				if (main_type == BEDC_BMESSAGE && text.IsEmpty()) {
 					int32 what = message->FindInt32("bedc_what");
+					BString description = message->FindString("bedc_desc");
+					if (description.IsEmpty())
+						description = "BMessage";
 
-					text.SetToFormat("BMessage(what=%#010x, %d, '%c%c%c%c')", what, what,
+					text.SetToFormat("%s(what=%#010x, %d, '%c%c%c%c')", description.String(),
+						what, what,
 						sanechar(what >> 24), sanechar(what >> 16),
 						sanechar(what >>  8), sanechar(what >>  0));
 				}
 
-				// TODO: generic BMessage handling (results in one line per item in the message)
-				// TODO: separators
-				//
-				//
 				BRow* row = new BRow();
 				if (colorEnum == 0) {
 					row->SetField(new BStringField(name), 0);
@@ -152,6 +195,8 @@
 				}
 				fEventList->AddRow(row, -1);
 
+				// For BEDC_MESSAGE, there is no bedc_text, but instead all non-bedc fields of the
+				// message should be added to the view. We add them in subrows that can be folded.
 				if (main_type == BEDC_BMESSAGE) {
 					int index = 0;
 					char* nameFound;
@@ -249,6 +294,11 @@
 
 				break;
 			}
+			case B_ABOUT_REQUESTED:
+			{
+				be_app_messenger.SendMessage(B_ABOUT_REQUESTED);
+				break;
+			}
 			default:
 				BWindow::MessageReceived(message);
 				break;
@@ -266,21 +316,38 @@
 	LoggerApp()
 		: BApplication("application/x-vnd.ml-BeDCApp")
 	{
-		LoggerWindow* window = new LoggerWindow();
-		window->Show();
+	}
+
+	void ReadyToRun() override
+	{
+		BApplication::ReadyToRun();
+		fActiveLogWindow = new LoggerWindow();
+		fActiveLogWindow->Show();
+	}
+
+	void AboutRequested() override
+	{
+		BAboutWindow* about = new BAboutWindow("Dev Console", "application/x-vnd.ml-BeDCApp");
+		about->AddDescription("Display log messages from other applications");
+		about->AddCopyright(2023, "Adrien Destugues");
+		about->Show();
 	}
 
 	void MessageReceived(BMessage* message) override
 	{
 		switch(message->what) {
 			case BEDC_MESSAGE:
-				WindowAt(0)->PostMessage(message);
+				DetachCurrentMessage();
+				fActiveLogWindow->PostMessage(message);
 				break;
 			default:
 				BApplication::MessageReceived(message);
 				break;
 		}
 	}
+
+private:
+	BWindow* fActiveLogWindow;
 };
 
 
diff --git a/src/build.sh b/src/build.sh
old mode 100644
new mode 100755