diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 62d81f57d2..2e03da66cd 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -24,7 +24,7 @@ if $(INCLUDE_GPL_ADDONS) = 1 { GPL_ONLY = "" ; } -BEOS_BIN = "[" addattr alert arp base64 basename bc beep bzip2 cal cat +BEOS_BIN = "[" addattr alert arp base64 basename bc beep bootman bzip2 cal cat catattr chgrp chmod chop chown chroot cksum clear clockconfig cmp comm compress cp copyattr $(X86_ONLY)CortexAddOnHost csplit ctags cut date dc dd desklink df diff diff3 dircolors dirname diff --git a/src/apps/Jamfile b/src/apps/Jamfile index 7631470501..6b815e5864 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src apps ; SubInclude HAIKU_TOP src apps 3dmov ; SubInclude HAIKU_TOP src apps aboutsystem ; SubInclude HAIKU_TOP src apps bsnow ; +SubInclude HAIKU_TOP src apps bootman ; SubInclude HAIKU_TOP src apps cdplayer ; SubInclude HAIKU_TOP src apps clock ; SubInclude HAIKU_TOP src apps codycam ; diff --git a/src/apps/bootman/BootDrive.h b/src/apps/bootman/BootDrive.h new file mode 100644 index 0000000000..47b6182e21 --- /dev/null +++ b/src/apps/bootman/BootDrive.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOT_DRIVE_H +#define BOOT_DRIVE_H + +#include +#include + +/* + Setting BMessage Format: + + "disk" String (path to boot disk) + + "partition" array of BMessage: + "show" bool (flag if entry should be added to boot menu) + "name" String (the name as shown in boot menu) + "type" String (short name of file system: bfs, dos) + "path" String (path to partition in /dev/...) + "size" long (size of partition in bytes) + */ +class BootDrive +{ +public: + BootDrive() {} + virtual ~BootDrive() {} + + virtual bool IsBootMenuInstalled() = 0; + virtual status_t ReadPartitions(BMessage *message) = 0; + virtual status_t WriteBootMenu(BMessage *message) = 0; + virtual status_t SaveMasterBootRecord(BFile *file) = 0; + virtual status_t RestoreMasterBootRecord(BFile *file) = 0; +}; + +#endif // BOOT_DRIVE_H diff --git a/src/apps/bootman/BootManager.cpp b/src/apps/bootman/BootManager.cpp new file mode 100644 index 0000000000..ddc792d73b --- /dev/null +++ b/src/apps/bootman/BootManager.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "BootManagerWindow.h" + +#include +#include +#include + + +static const char* kSignature = "application/x-vnd.Haiku-bootman"; + + +class BootManager : public BApplication { +public: + BootManager(); + + virtual void ReadyToRun(); + + virtual void AboutRequested(); +}; + + +BootManager::BootManager() + : BApplication(kSignature) +{ +} + + +void +BootManager::ReadyToRun() +{ + BootManagerWindow * window = new BootManagerWindow(); + window->Show(); +} + + +void +BootManager::AboutRequested() +{ + BAlert *alert = new BAlert("about", "Haiku Boot Manager\n" + "\twritten by Michael Pfeiffer\n" + "\tCopyright 2008, Haiku Inc.\n", "Ok"); + BTextView *view = alert->TextView(); + BFont font; + + view->SetStylable(true); + + view->GetFont(&font); + font.SetSize(18); + font.SetFace(B_BOLD_FACE); + view->SetFontAndColor(0, 18, &font); + + alert->Go(); +} + + +// #pragma mark - + + +int +main(int /*argc*/, char** /*argv*/) +{ + BootManager application; + application.Run(); + + return 0; +} diff --git a/src/apps/bootman/BootManagerController.cpp b/src/apps/bootman/BootManagerController.cpp new file mode 100644 index 0000000000..da7459ce5f --- /dev/null +++ b/src/apps/bootman/BootManagerController.cpp @@ -0,0 +1,388 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "BootManagerController.h" + +#include "WizardView.h" + +#include "EntryPage.h" +#include "PartitionsPage.h" +#include "DefaultPartitionPage.h" +#include "DescriptionPage.h" +#include "FileSelectionPage.h" + +// TODO remove +#define USE_TEST_BOOT_DRIVE 1 + +#if USE_TEST_BOOT_DRIVE + #include "TestBootDrive.h" +#endif + + +#include +#include +#include +#include +#include +#include + + +BootManagerController::BootManagerController() +{ +#if USE_TEST_BOOT_DRIVE + fBootDrive = new TestBootDrive(); +#else + // TODO implement + fBootDrive = NULL; +#endif + + // set defaults + fSettings.AddBool("install", true); + fSettings.AddInt32("defaultPartition", 0); + fSettings.AddInt32("timeout", -1); + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) == B_OK) { + path.Append("bootman/MBR"); + fSettings.AddString("file", path.Path()); + } else { + fSettings.AddString("file", ""); + } + + fBootDrive->ReadPartitions(&fSettings); +} + + +BootManagerController::~BootManagerController() +{ +} + + +int32 +BootManagerController::InitialState() +{ + return kStateEntry; +} + + +int32 +BootManagerController::NextState(int32 state) +{ + switch (state) { + case kStateEntry: + { + bool install; + fSettings.FindBool("install", &install); + if (install) { + if (fBootDrive->IsBootMenuInstalled()) + return kStatePartitions; + else + return kStateSaveMBR; + } + else + return kStateUninstall; + } + + case kStateSaveMBR: + if (_SaveMBR()) + return kStateMBRSaved; + break; + + case kStateMBRSaved: + return kStatePartitions; + + case kStatePartitions: + if (_HasSelectedPartitions()) + return kStateDefaultPartitions; + break; + + case kStateDefaultPartitions: + return kStateInstallSummary; + + case kStateInstallSummary: + if (_WriteBootMenu()) + return kStateInstalled; + break; + + case kStateInstalled: + be_app->PostMessage(B_QUIT_REQUESTED); + break; + + case kStateUninstall: + if (_RestoreMBR()) + return kStateUninstalled; + break; + + case kStateUninstalled: + be_app->PostMessage(B_QUIT_REQUESTED); + break; + } + // cannot leave the current state/page + return -1; +} + + +bool +BootManagerController::_HasSelectedPartitions() +{ + BMessage message; + for (int32 i = 0; fSettings.FindMessage("partition", i, &message) == B_OK; i ++) { + bool show; + if (message.FindBool("show", &show) == B_OK && show) + return true; + } + + BAlert* alert = new BAlert("info", "At least one partition must be selected!", + "OK"); + alert->Go(); + + return false; +} + + +bool +BootManagerController::_WriteBootMenu() +{ + BAlert* alert = new BAlert("confirm", "About to write the boot menu " + "to disk. Are you sure you want to continue?", "Write Boot Menu", "Back", + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + + if (alert->Go() == 1) + return false; + + status_t status = fBootDrive->WriteBootMenu(&fSettings); + fSettings.RemoveName("installStatus"); + fSettings.AddInt32("installStatus", status); + + return true; +} + + +bool +BootManagerController::_SaveMBR() +{ + BFile file("", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + status_t state = fBootDrive->SaveMasterBootRecord(&file); + fSettings.RemoveName("saveMBRStatus"); + fSettings.AddInt32("saveMBRStatus", state); + + return true; +} + + +bool +BootManagerController::_RestoreMBR() +{ + BString disk; + BString path; + fSettings.FindString("disk", &disk); + fSettings.FindString("file", &path); + + BString message; + message << "About to restore the Master Boot Record (MBR) of " + << disk << " from " << path << ". " + "Do you wish to continue?"; + BAlert* alert = new BAlert("confirm", message.String(), + "Restore MBR", "Back", + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + if (alert->Go() == 1) + return false; + + BFile file(path.String(), B_READ_ONLY); + status_t state = fBootDrive->RestoreMasterBootRecord(&file); + fSettings.RemoveName("restoreMBRStatus"); + fSettings.AddInt32("restoreMBRStatus", state); + + return true; +} + + +WizardPageView* +BootManagerController::CreatePage(int32 state, WizardView* wizard) +{ + WizardPageView* page = NULL; + BRect frame = wizard->PageFrame(); + + switch (state) { + case kStateEntry: + page = new EntryPage(&fSettings, frame, "entry"); + wizard->SetPreviousButtonHidden(true); + break; + case kStateSaveMBR: + page = _CreateSaveMBRPage(frame); + wizard->SetPreviousButtonHidden(false); + break; + case kStateMBRSaved: + page = _CreateMBRSavedPage(frame); + break; + case kStatePartitions: + page = new PartitionsPage(&fSettings, frame, "partitions"); + wizard->SetPreviousButtonHidden(false); + break; + case kStateDefaultPartitions: + page = new DefaultPartitionPage(&fSettings, frame, "default"); + break; + case kStateInstallSummary: + page = _CreateInstallSummaryPage(frame); + wizard->SetNextButtonLabel("Next"); + break; + case kStateInstalled: + page = _CreateInstalledPage(frame); + wizard->SetNextButtonLabel("Done"); + break; + case kStateUninstall: + page = _CreateUninstallPage(frame); + wizard->SetPreviousButtonHidden(false); + wizard->SetNextButtonLabel("Next"); + break; + case kStateUninstalled: + // TODO prevent overwriting MBR after clicking "Previous" + page = _CreateUninstalledPage(frame); + wizard->SetNextButtonLabel("Done"); + break; + } + + return page; +} + + +WizardPageView* +BootManagerController::_CreateSaveMBRPage(BRect frame) +{ + BString description; + BString disk; + fSettings.FindString("disk", &disk); + + description << + "Backup Master Boot Record\n\n" + "The Master Boot Record (MBR) of the boot device:\n" + "\t" << disk << "\n" + "will now be saved to disk. Please select a file to " + "save the MBR into.\n\n" + "If something goes wrong with the installation or if " + "you later wish to remove the boot menu, simply run the " + "bootman program and choose to 'Uninstall' option."; + + FileSelectionPage* page = new FileSelectionPage(&fSettings, frame, "saveMBR", description.String()); + return page; +} + + +WizardPageView* +BootManagerController::_CreateMBRSavedPage(BRect frame) +{ + BString description; + BString file; + fSettings.FindString("file", &file); + + description << + "Old Master Boot Record Saved\n\n" + "The old Master Boot Record was successfully save to " + << file << ".\n"; + + DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); + return page; +} + + +WizardPageView* +BootManagerController::_CreateInstallSummaryPage(BRect frame) +{ + BString description; + BString disk; + fSettings.FindString("disk", &disk); + + description << + "Summary\n\n" + "About to write the following boot menu to the boot disk " + "(" << disk << "). Please verify the information below " + "before continuing.\n\n"; + + BMessage message; + for (int32 i = 0; fSettings.FindMessage("partition", i, &message) == B_OK; i ++) { + + bool show; + if (message.FindBool("show", &show) != B_OK || !show) + continue; + + BString name; + BString path; + message.FindString("name", &name); + message.FindString("path", &path); + description << name << "\t(" << path << ")\n"; + } + + DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); + return page; +} + + +WizardPageView* +BootManagerController::_CreateInstalledPage(BRect frame) +{ + const char* description; + + int32 status; + fSettings.FindInt32("installStatus", &status); + if (status == B_OK) { + description = "Installation Boot Menu Completed\n\n" + "The boot manager has been successfully installed " + "on your system."; + } else { + // TODO + description = "Installation Boot Menu Failed\n\n" + "TODO"; + } + + DescriptionPage* page = new DescriptionPage(frame, "done", description, true); + return page; +} + + +WizardPageView* +BootManagerController::_CreateUninstallPage(BRect frame) +{ + BString description; + + description << + "Uninstall Boot Manager\n\n" + "Please locate the Master Boot Record (MBR) save file to " + "restore from. This is the file that was created when the " + "boot manager was first installed."; + + FileSelectionPage* page = new FileSelectionPage(&fSettings, frame, "restoreMBR", description.String()); + return page; +} + + +WizardPageView* +BootManagerController::_CreateUninstalledPage(BRect frame) +{ + BString description; + BString disk; + BString file; + fSettings.FindString("disk", &disk); + fSettings.FindString("file", &file); + + int32 status; + fSettings.FindInt32("restoreMBRStatus", &status); + if (status == B_OK) { + description << + "Uninstallation Boot Menu Completed\n\n" + "The Master Boot Record of the boot device " + "(" << disk << ") has been successfully restored from " + << file << "."; + } else { + // TODO + description << + "Uninstallation Boot Menu Failed\n\n" + "TODO"; + } + + DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); + return page; + +} diff --git a/src/apps/bootman/BootManagerController.h b/src/apps/bootman/BootManagerController.h new file mode 100644 index 0000000000..ae0939ad39 --- /dev/null +++ b/src/apps/bootman/BootManagerController.h @@ -0,0 +1,76 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOT_MANAGER_CONTROLLER_H +#define BOOT_MANAGER_CONTROLLER_H + +#include "WizardController.h" + +#include + +class BootDrive; + +class WizardView; +class WizardPageView; +class BRect; + +/* + Remainder of Settings Message Format: + (See also BootDrive.h) + "install" bool (whether install or uninstall should be performed) + "file" String (the file where the backup of the MBR is saved) + "defaultPartition" int32 (index of default partition) + "timeout" int32 (timeout in seconds, -1 for no timeout) + "installStatus" int32 (status_t) + "saveMBRStatus" int32 (status_t) + "restoreMBRStatus" int32 (status_t) + */ + +class BootManagerController : public WizardController +{ +public: + BootManagerController(); + virtual ~BootManagerController(); + +protected: + virtual int32 InitialState(); + virtual int32 NextState(int32 state); + virtual WizardPageView* CreatePage(int32 state, WizardView* wizard); + +private: + + enum State { + kStateEntry, + + // Install states + kStateSaveMBR, + kStateMBRSaved, + kStatePartitions, + kStateDefaultPartitions, + kStateInstallSummary, + kStateInstalled, + + // Uninstall states + kStateUninstall, + kStateUninstalled + }; + + bool _HasSelectedPartitions(); + bool _WriteBootMenu(); + bool _SaveMBR(); + bool _RestoreMBR(); + + WizardPageView* _CreateSaveMBRPage(BRect frame); + WizardPageView* _CreateMBRSavedPage(BRect frame); + WizardPageView* _CreateInstallSummaryPage(BRect frame); + WizardPageView* _CreateInstalledPage(BRect frame); + WizardPageView* _CreateUninstallPage(BRect frame); + WizardPageView* _CreateUninstalledPage(BRect frame); + + BMessage fSettings; + BootDrive* fBootDrive; +}; + + +#endif // BOOT_MANAGER_CONTROLLER_H diff --git a/src/apps/bootman/BootManagerWindow.cpp b/src/apps/bootman/BootManagerWindow.cpp new file mode 100644 index 0000000000..75d0a0b03b --- /dev/null +++ b/src/apps/bootman/BootManagerWindow.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "BootManagerWindow.h" + +#include "WizardView.h" + +#include "EntryPage.h" +#include "PartitionsPage.h" +#include "DefaultPartitionPage.h" + +#include +#include + +#include + +BootManagerWindow::BootManagerWindow() + : BWindow(BRect(100, 100, 500, 400), "Boot Manager", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS) + , fWindowCentered(false) +{ + float minWidth, maxWidth, minHeight, maxHeight; + GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); + SetSizeLimits(250, maxWidth, 250, maxHeight); + + fWizardView = new WizardView(Bounds(), "wizard", B_FOLLOW_ALL); + AddChild(fWizardView); + + fController.Initialize(fWizardView); +} + + +BootManagerWindow::~BootManagerWindow() +{ +} + + +void +BootManagerWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kMessageNext: + fController.Next(fWizardView); + break; + + case kMessagePrevious: + fController.Previous(fWizardView); + break; + + default: + BWindow::MessageReceived(msg); + } +} + + +bool +BootManagerWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +void +BootManagerWindow::WindowActivated(bool active) +{ + _CenterWindow(); +} + + +void +BootManagerWindow::_CenterWindow() +{ + if (fWindowCentered) + return; + fWindowCentered = true; + + BScreen screen(this); + if (!screen.IsValid()) + return; + + BRect frame = screen.Frame(); + BRect windowFrame = Frame(); + + float left = floor((frame.Width() - windowFrame.Width()) / 2); + float top = floor((frame.Height() - windowFrame.Height()) / 2); + + if (left < 20) + left = 20; + if (top < 20) + top = 20; + + MoveTo(left, top); +} + diff --git a/src/apps/bootman/BootManagerWindow.h b/src/apps/bootman/BootManagerWindow.h new file mode 100644 index 0000000000..30de92ec3a --- /dev/null +++ b/src/apps/bootman/BootManagerWindow.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOT_MANAGER_WINDOW_H +#define BOOT_MANAGER_WINDOW_H + + +#include + +#include "BootManagerController.h" + +class WizardView; + +class BootManagerWindow : public BWindow +{ +public: + BootManagerWindow(); + virtual ~BootManagerWindow(); + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + virtual void WindowActivated(bool active); + +private: + + void _CenterWindow(); + + bool fWindowCentered; + + BootManagerController fController; + WizardView* fWizardView; +}; + +#endif // BOOT_MANAGER_WINDOW_H diff --git a/src/apps/bootman/DefaultPartitionPage.cpp b/src/apps/bootman/DefaultPartitionPage.cpp new file mode 100644 index 0000000000..5a973c0c7f --- /dev/null +++ b/src/apps/bootman/DefaultPartitionPage.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "DefaultPartitionPage.h" + + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +const uint32 kMsgPartition = 'part'; +const uint32 kMsgTimeout = 'time'; + + +DefaultPartitionPage::DefaultPartitionPage(BMessage* settings, BRect frame, const char* name) + : WizardPageView(settings, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(); +} + + +DefaultPartitionPage::~DefaultPartitionPage() +{ +} + + +void +DefaultPartitionPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +void +DefaultPartitionPage::AttachedToWindow() +{ + fDefaultPartition->Menu()->SetTargetForItems(this); + fWait0->SetTarget(this); + fWait5->SetTarget(this); + fWait10->SetTarget(this); + fWait15->SetTarget(this); +} + + +void +DefaultPartitionPage::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kMsgPartition: + { + int32 index; + msg->FindInt32("index", &index); + fSettings->ReplaceInt32("defaultPartition", index); + } + break; + case kMsgTimeout: + { + int32 timeout; + msg->FindInt32("timeout", &timeout); + fSettings->ReplaceInt32("timeout", timeout); + } + break; + default: + WizardPageView::MessageReceived(msg); + } +} + + +static const float kTextDistance = 10; + +void +DefaultPartitionPage::_BuildUI() +{ + BRect rect(Bounds()); + + fDescription = CreateDescription(rect, "description", + "Default Partition\n\n" + "Please specify a default partition and a timeout.\n" + "The boot menu will load the default partition after " + "the timeout unless you select another partition. You " + "can also have the boot menu wait indefinitely for you " + "to select a partition." + ); + MakeHeading(fDescription); + AddChild(fDescription); + LayoutDescriptionVertically(fDescription); + rect.top = fDescription->Frame().bottom + kTextDistance; + fDescription->SetViewColor(255, 0, 0); + + BPopUpMenu* popUpMenu = _CreatePopUpMenu(); + fDefaultPartition = new BMenuField(rect, "partitions", "Default Partition:", + popUpMenu); + float divider = be_plain_font->StringWidth(fDefaultPartition->Label()) + 3; + fDefaultPartition->SetDivider(divider); + AddChild(fDefaultPartition); + fDefaultPartition->ResizeToPreferred(); + fDefaultPartition->SetViewColor(0, 255, 0); + + rect.top = fDefaultPartition->Frame().bottom + kTextDistance; + int32 timeout; + fSettings->FindInt32("timeout", &timeout); + fWait0 = _CreateWaitRadioButton(rect, "wait0", "Wait Indefinitely", -1, timeout); + fWait0->SetViewColor(0, 0, 255); + fWait5 = _CreateWaitRadioButton(rect, "wait5", "Wait 5 Seconds", 5, timeout); + fWait10 = _CreateWaitRadioButton(rect, "wait10", "Wait 10 Seconds", 10, timeout); + fWait15 = _CreateWaitRadioButton(rect, "wait15", "Wait 15 Seconds", 15, timeout); + + _Layout(); +} + + +BPopUpMenu* +DefaultPartitionPage::_CreatePopUpMenu() +{ + int32 defaultPartitionIndex; + fSettings->FindInt32("defaultPartition", &defaultPartitionIndex); + + BMenuItem* selectedItem = NULL; + int32 selectedItemIndex = 0; + + BPopUpMenu* menu = new BPopUpMenu("Partitions"); + BMessage message; + for (int32 i = 0; fSettings->FindMessage("partition", i, &message) == B_OK; i ++) { + + bool show; + if (message.FindBool("show", &show) != B_OK || !show) + continue; + + BString name; + message.FindString("name", &name); + + BMessage* msg = new BMessage(kMsgPartition); + msg->AddInt32("index", i); + BMenuItem* item = new BMenuItem(name.String(), msg); + menu->AddItem(item); + if (defaultPartitionIndex == i || selectedItem == NULL) { + selectedItem = item; + selectedItemIndex = i; + } + } + fSettings->ReplaceInt32("defaultPartition", selectedItemIndex); + selectedItem->SetMarked(true); + return menu; +} + + +BRadioButton* +DefaultPartitionPage::_CreateWaitRadioButton(BRect rect, const char* name, const char* label, int32 timeout, + int32 defaultTimeout) +{ + BMessage* msg = new BMessage(kMsgTimeout); + msg->AddInt32("timeout", timeout); + BRadioButton* button = new BRadioButton(rect, name, label, msg); + AddChild(button); + button->ResizeToPreferred(); + + if (timeout == defaultTimeout) + button->SetValue(1); + + return button; +} + +#include +void +DefaultPartitionPage::_Layout() +{ + LayoutDescriptionVertically(fDescription); + + float left = fDefaultPartition->Frame().left; + float top = fDescription->Frame().bottom + kTextDistance; + printf("top %f\n", top); + + BView* controls[] = { + fDefaultPartition, + fWait0, + fWait5, + fWait10, + fWait15 + }; + + for (int i = 0; i < 5; i ++) { + printf("*"); + BView* view = controls[i]; + view->MoveTo(left, top); + top = view->Frame().bottom + 3; + } + printf("\n"); +} + diff --git a/src/apps/bootman/DefaultPartitionPage.h b/src/apps/bootman/DefaultPartitionPage.h new file mode 100644 index 0000000000..8337b98005 --- /dev/null +++ b/src/apps/bootman/DefaultPartitionPage.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef DEFAULT_PARTITON_PAGE_H +#define DEFAULT_PARTITON_PAGE_H + + +#include "WizardPageView.h" + +class BMenuField; +class BMessage; +class BRadioButton; +class BPopUpMenu; +class BTextView; + + +class DefaultPartitionPage : public WizardPageView +{ +public: + DefaultPartitionPage(BMessage* settings, BRect frame, const char* name); + virtual ~DefaultPartitionPage(); + + virtual void FrameResized(float width, float height); + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage* msg); + +private: + + void _BuildUI(); + BPopUpMenu* _CreatePopUpMenu(); + BRadioButton* _CreateWaitRadioButton(BRect frame, const char* name, const char* label, + int32 timeout, int32 defaultTimeout); + void _Layout(); + + BTextView* fDescription; + BMenuField* fDefaultPartition; + BRadioButton* fWait0; + BRadioButton* fWait5; + BRadioButton* fWait10; + BRadioButton* fWait15; +}; + +#endif // DEFAULT_PARTITON_PAGE_H diff --git a/src/apps/bootman/DescriptionPage.cpp b/src/apps/bootman/DescriptionPage.cpp new file mode 100644 index 0000000000..1dc5ca45c2 --- /dev/null +++ b/src/apps/bootman/DescriptionPage.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "DescriptionPage.h" + + +#include +#include + +#include + + +DescriptionPage::DescriptionPage(BRect frame, const char* name, + const char* description, bool hasHeading) + : WizardPageView(NULL, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(description, hasHeading); +} + + +DescriptionPage::~DescriptionPage() +{ +} + + +void +DescriptionPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +static const float kTextDistance = 10; + +void +DescriptionPage::_BuildUI(const char* description, bool hasHeading) +{ + BRect rect(Bounds()); + + fDescription = CreateDescription(rect, "description", description); + if (hasHeading) + MakeHeading(fDescription); + fDescription->SetTabWidth(85); + AddChild(fDescription); + + _Layout(); +} + + +void +DescriptionPage::_Layout() +{ + LayoutDescriptionVertically(fDescription); +} + diff --git a/src/apps/bootman/DescriptionPage.h b/src/apps/bootman/DescriptionPage.h new file mode 100644 index 0000000000..d8eb384f15 --- /dev/null +++ b/src/apps/bootman/DescriptionPage.h @@ -0,0 +1,30 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef DESCRIPTION_PAGE_H +#define DESCRIPTION_PAGE_H + + +#include "WizardPageView.h" + + +class BTextView; + +class DescriptionPage : public WizardPageView +{ +public: + DescriptionPage(BRect frame, const char* name, const char* description, bool hasHeading); + virtual ~DescriptionPage(); + + virtual void FrameResized(float width, float height); + +private: + + void _BuildUI(const char* description, bool hasHeading); + void _Layout(); + + BTextView* fDescription; +}; + +#endif // DESCRIPTION_PAGE_H diff --git a/src/apps/bootman/EntryPage.cpp b/src/apps/bootman/EntryPage.cpp new file mode 100644 index 0000000000..136b265c16 --- /dev/null +++ b/src/apps/bootman/EntryPage.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "EntryPage.h" + + +#include +#include + +#include + + +EntryPage::EntryPage(BMessage* settings, BRect frame, const char* name) + : WizardPageView(settings, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(); +} + + +EntryPage::~EntryPage() +{ +} + + +void +EntryPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +void +EntryPage::PageCompleted() +{ + fSettings->ReplaceBool("install", fInstall->Value() != 0); +} + +static const float kTextDistance = 10; + +void +EntryPage::_BuildUI() +{ + BRect rect(Bounds()); + + fInstall = new BRadioButton(rect, "install", + "", + new BMessage('null')); + AddChild(fInstall); + fInstall->ResizeToPreferred(); + + BRect textRect(rect); + textRect.left = fInstall->Frame().right + kTextDistance; + + fInstallText = CreateDescription(textRect, "installText", + "Install Boot Menu\n\n" + "Choose this option to install a boot menu, " + "allowing you to select which operating " + "system to boot when you turn on your " + "computer.\n"); + MakeHeading(fInstallText); + AddChild(fInstallText); + + fUninstall = new BRadioButton(rect, "uninstall", + "", + new BMessage('null')); + AddChild(fUninstall); + fUninstall->ResizeToPreferred(); + + fUninstallText = CreateDescription(textRect, "uninstallText", + "Uninstall Boot Menu\n\n" + "Choose this option to remove the boot menu " + "previously installed by this program.\n" + ); + MakeHeading(fUninstallText); + AddChild(fUninstallText); + + bool install; + fSettings->FindBool("install", &install); + + if (install) + fInstall->SetValue(1); + else + fUninstall->SetValue(1); + + _Layout(); +} + + +void +EntryPage::_Layout() +{ + LayoutDescriptionVertically(fInstallText); + + float left = fUninstall->Frame().left; + float top = fInstallText->Frame().bottom; + fUninstall->MoveTo(left, top); + + left = fUninstallText->Frame().left; + fUninstallText->MoveTo(left, top); + + LayoutDescriptionVertically(fUninstallText); +} + diff --git a/src/apps/bootman/EntryPage.h b/src/apps/bootman/EntryPage.h new file mode 100644 index 0000000000..5739fd5cbf --- /dev/null +++ b/src/apps/bootman/EntryPage.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ENTRY_PAGE_H +#define ENTRY_PAGE_H + + +#include "WizardPageView.h" + + +class BRadioButton; +class BTextView; + +class EntryPage : public WizardPageView +{ +public: + EntryPage(BMessage* settings, BRect frame, const char* name); + virtual ~EntryPage(); + + virtual void FrameResized(float width, float height); + + virtual void PageCompleted(); + +private: + + void _BuildUI(); + void _Layout(); + + BRadioButton* fInstall; + BTextView* fInstallText; + BRadioButton* fUninstall; + BTextView* fUninstallText; +}; + +#endif // ENTRY_PAGE_H diff --git a/src/apps/bootman/FileSelectionPage.cpp b/src/apps/bootman/FileSelectionPage.cpp new file mode 100644 index 0000000000..55ffc1cb18 --- /dev/null +++ b/src/apps/bootman/FileSelectionPage.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "FileSelectionPage.h" + + +#include +#include +#include +#include + +#include +#include + + +FileSelectionPage::FileSelectionPage(BMessage* settings, BRect frame, const char* name, + const char* description) + : WizardPageView(settings, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(description); +} + + +FileSelectionPage::~FileSelectionPage() +{ +} + + +void +FileSelectionPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +void +FileSelectionPage::PageCompleted() +{ + fSettings->ReplaceString("file", fFile->Text()); +} + + +const float kTextDistance = 10; +const float kFileButtonDistance = 10; + +void +FileSelectionPage::_BuildUI(const char* description) +{ + BRect rect(Bounds()); + + fDescription = CreateDescription(rect, "description", description); + + MakeHeading(fDescription); + AddChild(fDescription); + + BString file; + fSettings->FindString("file", &file); + + // TODO align text and button + fFile = new BTextControl(rect, "file", "File:", file.String(), new BMessage()); + fFile->SetDivider(be_plain_font->StringWidth(fFile->Label()) + 5); + AddChild(fFile); + + // TODO open file dialog + fSelect = new BButton(rect, "select", "Select", new BMessage(), + B_FOLLOW_RIGHT); + fSelect->ResizeToPreferred(); + float left = rect.right - fSelect->Frame().Width(); + fSelect->MoveTo(left, 0); + AddChild(fSelect); + + _Layout(); +} + + +void +FileSelectionPage::_Layout() +{ + LayoutDescriptionVertically(fDescription); + + float left = fFile->Frame().left; + float top = fDescription->Frame().bottom + kTextDistance; + fFile->MoveTo(left, top); + + float width = fSelect->Frame().left - kFileButtonDistance - left; + float height = fFile->Frame().Height(); + fFile->ResizeTo(width, height); + + left = fSelect->Frame().left; + fSelect->MoveTo(left, top); +} + diff --git a/src/apps/bootman/FileSelectionPage.h b/src/apps/bootman/FileSelectionPage.h new file mode 100644 index 0000000000..363b56ecd5 --- /dev/null +++ b/src/apps/bootman/FileSelectionPage.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef FILE_SELECTION_PAGE_H +#define FILE_SELECTION_PAGE_H + + +#include "WizardPageView.h" + + +class BButton; +class BTextControl; +class BTextView; + +class FileSelectionPage : public WizardPageView +{ +public: + FileSelectionPage(BMessage* settings, BRect frame, const char* name, const char* description); + virtual ~FileSelectionPage(); + + virtual void FrameResized(float width, float height); + + virtual void PageCompleted(); + +private: + + void _BuildUI(const char* description); + void _Layout(); + + BTextView* fDescription; + BTextControl* fFile; + BButton* fSelect; +}; + +#endif // FILE_SELECTION_PAGE_H diff --git a/src/apps/bootman/Jamfile b/src/apps/bootman/Jamfile new file mode 100644 index 0000000000..448e783a02 --- /dev/null +++ b/src/apps/bootman/Jamfile @@ -0,0 +1,21 @@ +SubDir HAIKU_TOP src apps bootman ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +Application bootman : + BootManager.cpp + BootManagerController.cpp + BootManagerWindow.cpp + DefaultPartitionPage.cpp + DescriptionPage.cpp + EntryPage.cpp + FileSelectionPage.cpp + PartitionsPage.cpp + TestBootDrive.cpp + UninstallPage.cpp + WizardController.cpp + WizardPageView.cpp + WizardView.cpp + : be + : bootman.rdef +; diff --git a/src/apps/bootman/PartitionsPage.cpp b/src/apps/bootman/PartitionsPage.cpp new file mode 100644 index 0000000000..8112384730 --- /dev/null +++ b/src/apps/bootman/PartitionsPage.cpp @@ -0,0 +1,337 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "PartitionsPage.h" + + +#include +#include +#include +#include +#include +#include + +#include +#include + + +const uint32 kMessageShow = 'show'; +const uint32 kMessageName = 'name'; + + +PartitionsPage::PartitionsPage(BMessage* settings, BRect frame, const char* name) + : WizardPageView(settings, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(); +} + + +PartitionsPage::~PartitionsPage() +{ +} + + +void +PartitionsPage::PageCompleted() +{ + int32 i; + const int32 n = fPartitions->CountChildren(); + for (i = 0; i < n; i ++) { + BView* row = fPartitions->ChildAt(i); + int32 j; + const int32 m = row->CountChildren(); + for (j = 0; j < m; j ++) { + BView* child = row->ChildAt(j); + BControl* control = dynamic_cast(child); + if (control == NULL) + continue; + + int32 index; + BMessage* message = control->Message(); + if (message == NULL || message->FindInt32("index", &index) != B_OK) + continue; + + BMessage partition; + if (fSettings->FindMessage("partition", index, &partition) != B_OK) + continue; + + if (kMessageShow == message->what) { + partition.ReplaceBool("show", control->Value() == 1); + } else if (kMessageName == message->what && + dynamic_cast(control) != NULL) { + partition.ReplaceString("name", ((BTextControl*)control)->Text()); + } + + fSettings->ReplaceMessage("partition", index, &partition); + } + } +} + + +void +PartitionsPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +static const float kTextDistance = 10; + +void +PartitionsPage::_BuildUI() +{ + BRect rect(Bounds()); + + fDescription = CreateDescription(rect, "description", + "Partitions\n\n" + "The following partitions were detected. Please " + "check the box next to the partitions to be included " + "in the boot menu. You can also set the names of the " + "partitions as you would like them to appear in the " + "boot menu." + ); + MakeHeading(fDescription); + AddChild(fDescription); + LayoutDescriptionVertically(fDescription); + + rect.left = fDescription->Frame().left + 1; + rect.top = fDescription->Frame().bottom + kTextDistance; + rect.right -= B_V_SCROLL_BAR_WIDTH; + rect.bottom -= B_H_SCROLL_BAR_HEIGHT + 3; + + fPartitions = new BView(rect, "partitions", B_FOLLOW_ALL, + B_WILL_DRAW); + + fPartitionsScrollView = new BScrollView("scrollView", fPartitions, + B_FOLLOW_ALL, + 0, + true, true); + fPartitionsScrollView->SetViewColor(ViewColor()); + AddChild(fPartitionsScrollView); + + _FillPartitionsView(fPartitions); + + _Layout(); +} + + +void +PartitionsPage::_Layout() +{ + LayoutDescriptionVertically(fDescription); + + float left = fPartitionsScrollView->Frame().left; + float top = fDescription->Frame().bottom + kTextDistance; + fPartitionsScrollView->MoveTo(left, top); + + float width = fPartitionsScrollView->Frame().Width(); + float height = Bounds().bottom - top; + fPartitionsScrollView->ResizeTo(width, height); + + BScrollBar* scrollbar = fPartitionsScrollView->ScrollBar(B_HORIZONTAL); + float max = fPartitionsWidth - fPartitions->Bounds().IntegerWidth(); + if (max < 0) + max = 0; + scrollbar->SetRange(0, max); + + scrollbar = fPartitionsScrollView->ScrollBar(B_VERTICAL); + max = fPartitionsHeight - fPartitions->Bounds().IntegerHeight(); + if (max < 0) + max = 0; + scrollbar->SetRange(0, max); +} + + +const rgb_color kOddRowColor = {224, 255, 224}; +const rgb_color kEvenRowColor = {224, 224, 255}; + + +void +PartitionsPage::_FillPartitionsView(BView* view) +{ + const int32 inset = 1; + + + font_height fontHeight; + be_plain_font->GetHeight(&fontHeight); + + const int32 height = (int32)(6 + 2*inset + fontHeight.ascent + fontHeight.descent); + const int32 kDistance = (int32)(ceil(be_plain_font->StringWidth("x"))); + + // show | name | type | size | path + int32 showWidth = 0; + int32 nameWidth = 0; + int32 typeWidth = 0; + int32 sizeWidth = 0; + int32 pathWidth = 0; + _ComputeColumnWidths(showWidth, nameWidth, typeWidth, sizeWidth, pathWidth); + + int32 totalWidth = showWidth + nameWidth + typeWidth + sizeWidth + pathWidth + + 2*inset + 4 * kDistance; + + int32 rowNumber = 0; + + BRect frame(view->Bounds()); + frame.bottom = frame.top + height; + frame.right = frame.left + 65000; + + BMessage message; + for (int32 i = 0; fSettings->FindMessage("partition", i, &message) == B_OK; i ++, rowNumber ++) { + // get partition data + bool show; + BString name; + BString type; + BString path; + int64 size; + message.FindBool("show", &show); + message.FindString("name", &name); + message.FindString("type", &type); + message.FindString("path", &path); + message.FindInt64("size", &size); + + // create row for partition data + BView* row = new BView(frame, "row", B_FOLLOW_TOP | B_FOLLOW_LEFT, 0); + row->SetViewColor(((rowNumber % 2) == 0) ? kEvenRowColor : kOddRowColor); + view->AddChild(row); + frame.OffsetBy(0, height); + + // box + BRect rect(row->Bounds()); + rect.InsetBy(inset, inset); + rect.right = rect.left + showWidth; + BCheckBox* checkBox = new BCheckBox(rect, "show", "", + _CreateControlMessage(kMessageShow, i)); + if (show) + checkBox->SetValue(1); + row->AddChild(checkBox); + rect.OffsetBy(showWidth + kDistance, 0); + + // name + rect.right = rect.left + nameWidth; + BTextControl* nameControl = new BTextControl(rect, "name", "", name.String(), + _CreateControlMessage(kMessageName, i)); + nameControl->SetDivider(0); + row->AddChild(nameControl); + rect.OffsetBy(nameWidth + kDistance, 0); + + // type + rect.right = rect.left + typeWidth; + BStringView* typeView = new BStringView(rect, "type", type.String()); + row->AddChild(typeView); + rect.OffsetBy(typeWidth + kDistance, 0); + + + // size + BString sizeText; + _CreateSizeText(size, &sizeText); + rect.right = rect.left + sizeWidth; + BStringView* sizeView = new BStringView(rect, "type", sizeText.String()); + sizeView->SetAlignment(B_ALIGN_RIGHT); + row->AddChild(sizeView); + rect.OffsetBy(sizeWidth + kDistance, 0); + + // path + rect.right = rect.left + pathWidth; + BStringView* pathView = new BStringView(rect, "path", path.String()); + row->AddChild(pathView); + } + + + fPartitionsWidth = totalWidth; + fPartitionsHeight = frame.Height(); +} + + +void +PartitionsPage::_ComputeColumnWidths(int32& showWidth, int32& nameWidth, + int32& typeWidth, int32& sizeWidth, int32& pathWidth) +{ + BCheckBox checkBox(BRect(0, 0, 100, 100), "show", "", new BMessage()); + checkBox.ResizeToPreferred(); + showWidth = checkBox.Bounds().IntegerWidth(); + // reserve space for about 16 characters + nameWidth = (int32)ceil(be_plain_font->StringWidth("oooooooooooooooo")); + + const int32 kTextControlInsets = 6; + const int32 kStringViewInsets = 2; + + BMessage message; + for (int32 i = 0; fSettings->FindMessage("partition", i, &message) == B_OK; i ++) { + // get partition data + BString name; + BString type; + BString path; + int64 size; + message.FindString("name", &name); + message.FindString("type", &type); + message.FindString("path", &path); + message.FindInt64("size", &size); + BString sizeText; + _CreateSizeText(size, &sizeText); + + int32 width = (int32)ceil(be_plain_font->StringWidth(name.String())) + + kTextControlInsets; + if (nameWidth < width) + nameWidth = width; + + width = (int32)ceil(be_plain_font->StringWidth(type.String())) + + kStringViewInsets; + if (typeWidth < width) + typeWidth = width; + + width = (int32)ceil(be_plain_font->StringWidth(path.String())) + + kStringViewInsets; + if (pathWidth < width) + pathWidth = width; + + width = (int32)ceil(be_plain_font->StringWidth(sizeText.String())) + + kStringViewInsets; + if (sizeWidth < width) + sizeWidth = width; + } +} + + +static const char kPrefix[] = " KMGTPE"; + + +void +PartitionsPage::_CreateSizeText(int64 size, BString* text) +{ + if (size < 0) { + (*text) << "Error"; + return; + } + + int index = 0; + int n = 7; + int64 remainder = 0; + for (; size >= 1000 && index <= n; index ++) { + remainder = size % 1000; + size /= 1000; + } + + // round + size = size + ((remainder + 500) / 1000); + + if (index == 0) + (*text) << size << " B"; + else if (index < n) + (*text) << size << " " << kPrefix[index] << "B"; + else + (*text) << "-"; +} + + +BMessage* +PartitionsPage::_CreateControlMessage(uint32 what, int32 index) +{ + BMessage* message = new BMessage(what); + message->AddInt32("index", index); + return message; +} diff --git a/src/apps/bootman/PartitionsPage.h b/src/apps/bootman/PartitionsPage.h new file mode 100644 index 0000000000..53ce0a4529 --- /dev/null +++ b/src/apps/bootman/PartitionsPage.h @@ -0,0 +1,42 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef PARTITONS_PAGE_H +#define PARTITONS_PAGE_H + + +#include "WizardPageView.h" + + +class BTextView; +class BScrollView; + +class PartitionsPage : public WizardPageView +{ +public: + PartitionsPage(BMessage* settings, BRect frame, const char* name); + virtual ~PartitionsPage(); + + virtual void PageCompleted(); + + virtual void FrameResized(float width, float height); + +private: + + void _BuildUI(); + void _Layout(); + void _FillPartitionsView(BView* view); + void _CreateSizeText(int64 size, BString* text); + BMessage* _CreateControlMessage(uint32 what, int32 partitionIndex); + void _ComputeColumnWidths(int32& showWidth, int32& nameWidth, int32& typeWidth, + int32& sizeWidth, int32& pathWidth); + + BTextView* fDescription; + BView* fPartitions; + BScrollView* fPartitionsScrollView; + float fPartitionsWidth; + float fPartitionsHeight; +}; + +#endif // PARTITONS_PAGE_H diff --git a/src/apps/bootman/TestBootDrive.cpp b/src/apps/bootman/TestBootDrive.cpp new file mode 100644 index 0000000000..1e3cc2ed04 --- /dev/null +++ b/src/apps/bootman/TestBootDrive.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "TestBootDrive.h" + + +#include + + +TestBootDrive::TestBootDrive() +{ +} + + +TestBootDrive::~TestBootDrive() +{ +} + + +bool +TestBootDrive::IsBootMenuInstalled() +{ + return true; +} + + +status_t +TestBootDrive::ReadPartitions(BMessage *message) +{ + message->AddString("disk", "/dev/disk/ide/ata/0/master/0/raw"); + + BMessage partition; + + partition.AddBool("show", true); + partition.AddString("name", "Haiku"); + partition.AddString("type", "bfs"); + partition.AddString("path", "/dev/disk/ide/ata/0/master/0/0_0"); + partition.AddInt64("size", 3 * (int64)1024 * 1024 * 1024); + message->AddMessage("partition", &partition); + + + partition.MakeEmpty(); + partition.AddBool("show", true); + partition.AddString("name", "no name"); + partition.AddString("type", "dos"); + partition.AddString("path", "/dev/disk/ide/ata/0/slave/0/0_0"); + partition.AddInt64("size", 10 * (int64)1024 * 1024 * 1024); + message->AddMessage("partition", &partition); + + partition.MakeEmpty(); + partition.AddBool("show", true); + partition.AddString("name", "Data"); + partition.AddString("type", "unknown"); + partition.AddString("path", "/dev/disk/ide/ata/0/slave/0/0_1"); + partition.AddInt64("size", 250 * (int64)1024 * 1024 * 1024); + message->AddMessage("partition", &partition); + + return B_OK; +} + + +status_t +TestBootDrive::WriteBootMenu(BMessage *message) +{ + printf("WriteBootMenu:\n"); + message->PrintToStream(); + + BMessage partition; + int32 index = 0; + for (; message->FindMessage("partition", index, &partition) == B_OK; index ++) { + printf("Partition %d:\n", (int)index); + partition.PrintToStream(); + } + + return B_OK; +} + + +status_t +TestBootDrive::SaveMasterBootRecord(BFile *file) +{ + return B_OK; +} + + +status_t +TestBootDrive::RestoreMasterBootRecord(BFile *file) +{ + return B_OK; +} diff --git a/src/apps/bootman/TestBootDrive.h b/src/apps/bootman/TestBootDrive.h new file mode 100644 index 0000000000..81201839bb --- /dev/null +++ b/src/apps/bootman/TestBootDrive.h @@ -0,0 +1,23 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef TEST_BOOT_DRIVE_H +#define TEST_BOOT_DRIVER_H + +#include "BootDrive.h" + +class TestBootDrive : public BootDrive +{ +public: + TestBootDrive(); + virtual ~TestBootDrive(); + + virtual bool IsBootMenuInstalled(); + virtual status_t ReadPartitions(BMessage *message); + virtual status_t WriteBootMenu(BMessage *message); + virtual status_t SaveMasterBootRecord(BFile *file); + virtual status_t RestoreMasterBootRecord(BFile *file); +}; + +#endif // TEST_BOOT_DRIVER_H diff --git a/src/apps/bootman/UninstallPage.cpp b/src/apps/bootman/UninstallPage.cpp new file mode 100644 index 0000000000..1285d8512c --- /dev/null +++ b/src/apps/bootman/UninstallPage.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "UninstallPage.h" + + +#include +#include + +#include + + +UninstallPage::UninstallPage(BMessage* settings, BRect frame, const char* name) + : WizardPageView(settings, frame, name, B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) +{ + _BuildUI(); +} + + +UninstallPage::~UninstallPage() +{ +} + + +void +UninstallPage::FrameResized(float width, float height) +{ + WizardPageView::FrameResized(width, height); + _Layout(); +} + + +static const float kTextDistance = 10; + +void +UninstallPage::_BuildUI() +{ + BRect rect(Bounds()); + + fDescription = CreateDescription(rect, "description", + "Uninstall Boot Manager\n\n" + "Please locate the Master Boot Record (MBR) save file to " + "restore from. This is the file that was created when the " + "boot manager was first installed."); + + MakeHeading(fDescription); + AddChild(fDescription); + + _Layout(); +} + + +void +UninstallPage::_Layout() +{ + LayoutDescriptionVertically(fDescription); +} + diff --git a/src/apps/bootman/UninstallPage.h b/src/apps/bootman/UninstallPage.h new file mode 100644 index 0000000000..d8a47f3442 --- /dev/null +++ b/src/apps/bootman/UninstallPage.h @@ -0,0 +1,30 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef UNINSTALL_PAGE_H +#define UNINSTALL_PAGE_H + + +#include "WizardPageView.h" + + +class BTextView; + +class UninstallPage : public WizardPageView +{ +public: + UninstallPage(BMessage* settings, BRect frame, const char* name); + virtual ~UninstallPage(); + + virtual void FrameResized(float width, float height); + +private: + + void _BuildUI(); + void _Layout(); + + BTextView* fDescription; +}; + +#endif // UNINSTALL_PAGE_H diff --git a/src/apps/bootman/WizardController.cpp b/src/apps/bootman/WizardController.cpp new file mode 100644 index 0000000000..ffb265823b --- /dev/null +++ b/src/apps/bootman/WizardController.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "WizardController.h" + +#include "WizardView.h" +#include "WizardPageView.h" + +void +WizardController::StateStack::MakeEmpty() +{ + StateStack* stack = this; + StateStack* next; + do { + next = stack->Next(); + delete stack; + stack = next; + } while (next != NULL); +} + + +WizardController::WizardController() + : fStack(NULL) +{ +} + + +WizardController::~WizardController() +{ + if (fStack != NULL) { + fStack->MakeEmpty(); + fStack = NULL; + } +} + + +void +WizardController::Initialize(WizardView* view) +{ + if (fStack == NULL) + _PushState(InitialState()); + _ShowPage(view); +} + + +void +WizardController::Next(WizardView* wizard) +{ + wizard->PageCompleted(); + + if (fStack == NULL) + return; + + int state = NextState(fStack->State()); + if (state < 0) + return; + + _PushState(state); + _ShowPage(wizard); +} + + +void +WizardController::Previous(WizardView* wizard) +{ + wizard->PageCompleted(); + + if (fStack != NULL) { + StateStack* stack = fStack; + fStack = fStack->Next(); + delete stack; + } + _ShowPage(wizard); +} + + +void +WizardController::_PushState(int32 state) +{ + fStack = new StateStack(state, fStack); +} + + +void +WizardController::_ShowPage(WizardView* wizard) +{ + if (fStack == NULL) + return; + + WizardPageView* page = CreatePage(fStack->State(), wizard); + wizard->SetPage(page); +} diff --git a/src/apps/bootman/WizardController.h b/src/apps/bootman/WizardController.h new file mode 100644 index 0000000000..aa05375f39 --- /dev/null +++ b/src/apps/bootman/WizardController.h @@ -0,0 +1,64 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef WIZARD_CONTROLLER_H +#define WIZARD_CONTROLLER_H + + +#include + +class WizardView; +class WizardPageView; + + +class WizardController +{ +public: + WizardController(); + virtual ~WizardController(); + + virtual void Initialize(WizardView* wizard); + virtual void Next(WizardView* wizard); + virtual void Previous(WizardView* wizard); + + +protected: + virtual int32 InitialState() = 0; + virtual int32 NextState(int32 state) = 0; + virtual WizardPageView* CreatePage(int32 state, WizardView* wizard) = 0; + + +private: + + class StateStack { + public: + StateStack(int32 state, StateStack* next) + : fState(state) + , fNext(next) + { + } + + int32 State() { + return fState; + } + + StateStack* Next() { + return fNext; + } + + void MakeEmpty(); + + private: + int32 fState; + StateStack* fNext; + }; + + void _PushState(int32 state); + void _ShowPage(WizardView* wizard); + + StateStack* fStack; +}; + + +#endif // WIZARD_CONTROLLER_H diff --git a/src/apps/bootman/WizardPageView.cpp b/src/apps/bootman/WizardPageView.cpp new file mode 100644 index 0000000000..28dd7ecaa5 --- /dev/null +++ b/src/apps/bootman/WizardPageView.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "WizardPageView.h" + + +#include + +#include +#include + + +WizardPageView::WizardPageView(BMessage* settings, BRect frame, const char* name, + uint32 resizingMode, uint32 flags) + : BView(frame, name, resizingMode, flags) + , fSettings(settings) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + + +WizardPageView::~WizardPageView() +{ +} + + +void +WizardPageView::PageCompleted() +{ +} + + +BTextView* +WizardPageView::CreateDescription(BRect frame, const char* name, + const char* description) +{ + BTextView* view = new BTextView(frame, "text", + frame.OffsetToCopy(0, 0), + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, + B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS); + view->MakeEditable(false); + view->SetViewColor(ViewColor()); + view->SetStylable(true); + view->SetText(description); + return view; +} + + +void +WizardPageView::MakeHeading(BTextView* view) +{ + const char* text = view->Text(); + const char* firstLineEnd = strchr(text, '\n'); + if (firstLineEnd != NULL) { + int indexFirstLineEnd = firstLineEnd - text; + BFont font; + view->GetFont(&font); + font.SetSize(ceil(font.Size() * 1.2)); + font.SetFace(B_BOLD_FACE); + view->SetFontAndColor(0, indexFirstLineEnd, &font); + } +} + + +void +WizardPageView::LayoutDescriptionVertically(BTextView* view) +{ + view->SetTextRect(view->Bounds()); + + float height = view->TextHeight(0, 32000); + float width = view->Bounds().Width(); + + view->ResizeTo(width, height); + view->SetTextRect(view->Bounds()); +} + diff --git a/src/apps/bootman/WizardPageView.h b/src/apps/bootman/WizardPageView.h new file mode 100644 index 0000000000..a3f95c02c9 --- /dev/null +++ b/src/apps/bootman/WizardPageView.h @@ -0,0 +1,37 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef WIZARD_PAGE_VIEW_H +#define WIZARD_PAGE_VIEW_H + + +#include +#include +#include +#include + + +class WizardPageView : public BView +{ +public: + WizardPageView(BMessage* settings, BRect frame, const char* name, + uint32 resizingMode = B_FOLLOW_ALL, uint32 flags = B_WILL_DRAW); + virtual ~WizardPageView(); + + virtual void PageCompleted(); + + virtual BTextView* CreateDescription(BRect frame, const char* name, + const char* description); + + virtual void MakeHeading(BTextView* view); + virtual void LayoutDescriptionVertically(BTextView* view); + +protected: + BMessage* fSettings; + +private: + void _BuildUI(); +}; + +#endif // WIZARD_PAGE_VIEW_H diff --git a/src/apps/bootman/WizardView.cpp b/src/apps/bootman/WizardView.cpp new file mode 100644 index 0000000000..a0caeca5a1 --- /dev/null +++ b/src/apps/bootman/WizardView.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "WizardView.h" + +#include "WizardPageView.h" + +#include + +static const float kSeparatorHeight = 2; +static const float kSeparatorDistance = 5; +static const float kBorderWidth = 10; +static const float kBorderHeight = 5; + + +WizardView::WizardView(BRect frame, const char* name, uint32 resizingMode) + : BView(frame, name, resizingMode, 0) + , fSeparator(NULL) + , fPrevious(NULL) + , fNext(NULL) + , fPage(NULL) +{ + _BuildUI(); + SetPreviousButtonHidden(true); +} + + +WizardView::~WizardView() +{ +} + + +BRect +WizardView::PageFrame() +{ + float left = kBorderWidth; + float right = Bounds().right - kBorderWidth; + float top = kBorderHeight; + float bottom = fSeparator->Frame().top - kSeparatorDistance - 1; + return BRect(left, top, right, bottom); +} + + +void +WizardView::SetPage(WizardPageView* page) +{ + if (fPage == page) + return; + + if (fPage != NULL) { + RemoveChild(fPage); + delete fPage; + } + + fPage = page; + if (page == NULL) + return; + + BRect frame = PageFrame(); + page->MoveTo(frame.left, frame.top); + page->ResizeTo(frame.Width()+1, frame.Height()+1); + AddChild(page); +} + + +void +WizardView::PageCompleted() +{ + if (fPage != NULL) + fPage->PageCompleted(); +} + + +void +WizardView::SetPreviousButtonEnabled(bool enabled) +{ + fPrevious->SetEnabled(enabled); +} + + +void +WizardView::SetNextButtonEnabled(bool enabled) +{ + fNext->SetEnabled(enabled); +} + + +void +WizardView::SetPreviousButtonLabel(const char* text) +{ + fPrevious->SetLabel(text); + fPrevious->ResizeToPreferred(); +} + + +void +WizardView::SetNextButtonLabel(const char* text) +{ + BRect frame = fNext->Frame(); + fNext->SetLabel(text); + fNext->ResizeToPreferred(); + BRect newFrame = fNext->Frame(); + fNext->MoveBy(frame.Width() - newFrame.Width(), + frame.Height() - newFrame.Height()); +} + + +void +WizardView::SetPreviousButtonHidden(bool hide) +{ + if (hide) { + if (!fPrevious->IsHidden()) + fPrevious->Hide(); + } else { + if (fPrevious->IsHidden()) + fPrevious->Show(); + } +} + + +void +WizardView::_BuildUI() +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + float width = Bounds().Width(); + float height = Bounds().Height(); + + fSeparator = new BBox(BRect(kBorderWidth, 0, + width - 1 - kBorderWidth, kSeparatorHeight - 1), + "separator", + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); + AddChild(fSeparator); + + fPrevious = new BButton(BRect(0, 0, 100, 20), "previous", "Previous", + new BMessage(kMessagePrevious), + B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + AddChild(fPrevious); + fPrevious->ResizeToPreferred(); + + fNext = new BButton(BRect(0, 0, 100, 20), "next", "Next", + new BMessage(kMessageNext), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + AddChild(fNext); + fNext->ResizeToPreferred(); + + // layout views + float buttonHeight = fPrevious->Bounds().Height(); + float buttonTop = height - 1 - buttonHeight - kBorderHeight; + fPrevious->MoveTo(kBorderWidth, buttonTop); + + fSeparator->MoveTo(kBorderWidth, buttonTop - kSeparatorDistance - kSeparatorHeight); + + fNext->MoveTo(width - fNext->Bounds().Width() - kBorderWidth - 1, buttonTop); +} diff --git a/src/apps/bootman/WizardView.h b/src/apps/bootman/WizardView.h new file mode 100644 index 0000000000..92815a7195 --- /dev/null +++ b/src/apps/bootman/WizardView.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef WIZARD_VIEW_H +#define WIZARD_VIEW_H + + +#include +#include +#include + + +class BTextView; +class WizardPageView; + + +const uint32 kMessageNext = 'next'; +const uint32 kMessagePrevious = 'prev'; + + +class WizardView : public BView +{ +public: + WizardView(BRect frame, const char* name, uint32 resizingMode); + virtual ~WizardView(); + + virtual BRect PageFrame(); + + virtual void SetPage(WizardPageView* page); + + virtual void PageCompleted(); + + virtual void SetPreviousButtonEnabled(bool enabled); + virtual void SetNextButtonEnabled(bool enabled); + virtual void SetPreviousButtonLabel(const char* text); + virtual void SetNextButtonLabel(const char* text); + virtual void SetPreviousButtonHidden(bool hide); + +private: + void _BuildUI(); + + BBox* fSeparator; + BButton* fPrevious; + BButton* fNext; + + WizardPageView* fPage; +}; + +#endif // WIZARD_VIEW_H diff --git a/src/apps/bootman/bootman.rdef b/src/apps/bootman/bootman.rdef new file mode 100644 index 0000000000..e0be39bdfc --- /dev/null +++ b/src/apps/bootman/bootman.rdef @@ -0,0 +1,94 @@ +/* + * Copyright 2008, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Pfeiffer + * + */ + +resource(1, "BEOS:APP_FLAGS") (#'APPF') $"00000000"; + +resource(1, "BEOS:APP_VERSION") #'APPV' array { + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"000000000000000000000000000000000000000080031200FC105760EC111000" + $"EC088BC800000000FC1057808003220080052980800294408000600380032200" + $"8005298000000002FC1057C0FC105A7C000000018003E7800000000280032200" + $"800529808002944080006003EC02ECB88005298000000000FC1057D0EC111000" + $"EC01BE200000000200000000FC105A7C000000018003E7800000000280006003" + $"000000028001DEE88001DEF8EC02ECB88004B38000000000FC1058108003E780" + $"EC01BE20EC02ECB8FC105810EC111000EC01BE7C00000001FC10582000000000" + $"EC02ECBCFFFFFFFFEC05B434FC1058B88005298080029440FC10585080019244" + $"FC1059B8EC02ECB8FC105850EC111000EC01BE7C8002A680FC105870EC111000" + $"80052980FFFFFFFFEC05B434FC10593800000004000201DC800060038003E780" + $"8005298000000000FC105890420C0000EC019C080000010043300000EC111000" + $"8004B38000000000" +}; + +resource(101, "BEOS:L:STD_ICON") #'ICON' array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource(101, "BEOS:M:STD_ICON") #'MICN' array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource(1, "BEOS:APP_SIG") (#'MIMS') "application/x-vnd.Haiku-bootman"; + +resource(1, "BEOS:FILE_TYPES") message { }; +