Author: stippi Date: 2010-01-21 15:41:58 +0100 (Thu, 21 Jan 2010) New Revision: 35221 Changeset: http://dev.haiku-os.org/changeset/35221/haiku Added: haiku/trunk/src/apps/readonlybootprompt/ haiku/trunk/src/apps/readonlybootprompt/BootPrompt.cpp haiku/trunk/src/apps/readonlybootprompt/BootPrompt.h haiku/trunk/src/apps/readonlybootprompt/BootPrompt.rdef haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.h haiku/trunk/src/apps/readonlybootprompt/Jamfile Modified: haiku/trunk/src/apps/Jamfile Log: Added application which is supposed to replace the "Do you wish to run the Installer or continue booting to the Desktop" alert that pops up on CD boots. It allows to set the language and keymap as the very first thing before a Haiku installation. (Aside from replacing the alert.) Everything tested and working, I just need to test integration in the Bootscript. Modified: haiku/trunk/src/apps/Jamfile =================================================================== --- haiku/trunk/src/apps/Jamfile 2010-01-21 14:39:43 UTC (rev 35220) +++ haiku/trunk/src/apps/Jamfile 2010-01-21 14:41:58 UTC (rev 35221) @@ -43,6 +43,7 @@ HaikuSubInclude powerstatus ; HaikuSubInclude processcontroller ; HaikuSubInclude pulse ; +HaikuSubInclude readonlybootprompt ; HaikuSubInclude remotedesktop ; HaikuSubInclude resedit ; HaikuSubInclude screenshot ; Added: haiku/trunk/src/apps/readonlybootprompt/BootPrompt.cpp =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPrompt.cpp (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/BootPrompt.cpp 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,78 @@ +/* + * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx> + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "BootPrompt.h" + +#include <stdlib.h> + +#include <AboutWindow.h> +#include <Locale.h> + +#include "BootPromptWindow.h" + + +int +main(int, char **) +{ + BootPromptApp app; + app.Run(); + return 0; +} + + +// #pragma mark - + + +const char* kAppSignature = "application/x-vnd.Haiku-ReadOnlyBootPrompt"; + + +BootPromptApp::BootPromptApp() + : + BApplication(kAppSignature) +{ +} + + +void +BootPromptApp::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_BOOT_DESKTOP: + // TODO: Exit with some value that the Bootscript can deal with. + exit(1); + break; + case MSG_RUN_INSTALLER: + // TODO: Exit with some value that the Bootscript can deal with. + exit(0); + break; + + default: + BApplication::MessageReceived(message); + } +} + + +void +BootPromptApp::AboutRequested() +{ + const char* kAuthors[] = { + "Stephan Aßmus", + NULL + }; + + BAboutWindow* aboutWindow = new BAboutWindow("ReadOnlyBootPrompt", 2010, + kAuthors); + + aboutWindow->Show(); +} + + +void +BootPromptApp::ReadyToRun() +{ + // Prompt the user to select his preferred language. + new BootPromptWindow(); +} + Added: haiku/trunk/src/apps/readonlybootprompt/BootPrompt.h =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPrompt.h (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/BootPrompt.h 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,28 @@ +/* + * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx>. + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef BOOT_PROMPT_APP_H +#define BOOT_PROMPT_APP_H + +#include <Application.h> + + +enum { + MSG_BOOT_DESKTOP = 'dktp', + MSG_RUN_INSTALLER = 'inst' +}; + +extern const char* kAppSignature; + + +class BootPromptApp : public BApplication { +public: + BootPromptApp(); + + virtual void MessageReceived(BMessage* message); + virtual void AboutRequested(); + virtual void ReadyToRun(); +}; + +#endif // BOOT_PROMPT_APP_H Added: haiku/trunk/src/apps/readonlybootprompt/BootPrompt.rdef =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPrompt.rdef (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/BootPrompt.rdef 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,17 @@ + +resource app_signature "application/x-vnd.Haiku-ReadOnlyBootPrompt"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_BETA, + internal = 0, + + short_info = "ReadOnlyBootPrompt", + long_info = "ReadOnlyBootPrompt ©2010 The Haiku Project" +}; + +resource app_flags B_EXCLUSIVE_LAUNCH; + Added: haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,398 @@ +/* + * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx> + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "BootPromptWindow.h" + +#include <stdio.h> + +#include <Button.h> +#include <ControlLook.h> +#include <Directory.h> +#include <Entry.h> +#include <Font.h> +#include <FindDirectory.h> +#include <File.h> +#include <GroupLayoutBuilder.h> +#include <ListView.h> +#include <Locale.h> +#include <LocaleRoster.h> +#include <Path.h> +#include <ScrollView.h> +#include <SeparatorView.h> +#include <StringItem.h> +#include <StringView.h> +#include <TextView.h> + +#include "BootPrompt.h" +#include "Keymap.h" +#include "KeymapListItem.h" + + +enum { + MSG_LANGUAGE_SELECTED = 'lngs', + MSG_KEYMAP_SELECTED = 'kmps' +}; + +#undef TR_CONTEXT +#define TR_CONTEXT "BootPromptWindow" + + +class LanguageItem : public BStringItem { +public: + LanguageItem(const char* label, const char* language) + : + BStringItem(label), + fLanguage(language) + { + } + + const char* Language() const + { + return fLanguage.String(); + } + +private: + BString fLanguage; +}; + + +BootPromptWindow::BootPromptWindow() + : + BWindow(BRect(0, 0, 450, 380), "", + B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE + | B_AUTO_UPDATE_SIZE_LIMITS) +{ + // TODO: Remove once BLocalRoster is fixed. + be_locale_roster->GetInstalledLanguages(&fInstalledLanguages); + + fInfoTextView = new BTextView("info", be_plain_font, NULL, B_WILL_DRAW); + fInfoTextView->SetInsets(10, 10, 10, 10); + fInfoTextView->MakeEditable(false); + fInfoTextView->MakeSelectable(false); + + BScrollView* infoScrollView = new BScrollView("infoScroll", + fInfoTextView, B_WILL_DRAW, false, true); + + fDesktopButton = new BButton("", new BMessage(MSG_BOOT_DESKTOP)); + fDesktopButton->SetTarget(be_app); + fDesktopButton->MakeDefault(true); + + fInstallerButton = new BButton("", new BMessage(MSG_RUN_INSTALLER)); + fInstallerButton->SetTarget(be_app); + + fLanguagesLabelView = new BStringView("languagesLabel", ""); + fLanguagesLabelView->SetFont(be_bold_font); + fLanguagesLabelView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, + B_SIZE_UNSET)); + + fKeymapsLabelView = new BStringView("keymapsLabel", ""); + fKeymapsLabelView->SetFont(be_bold_font); + fKeymapsLabelView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, + B_SIZE_UNSET)); + + fLanguagesListView = new BListView(); + BScrollView* languagesScrollView = new BScrollView("languagesScroll", + fLanguagesListView, B_WILL_DRAW, false, true); + + fKeymapsListView = new BListView(); + BScrollView* keymapsScrollView = new BScrollView("keymapsScroll", + fKeymapsListView, B_WILL_DRAW, false, true); + + _InitCatalog(false); + _UpdateStrings(); + + float spacing = be_control_look->DefaultItemSpacing(); + + SetLayout(new BGroupLayout(B_HORIZONTAL)); + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(infoScrollView) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(fLanguagesLabelView) + .Add(languagesScrollView) + ) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(fKeymapsLabelView) + .Add(keymapsScrollView) + ) + ) + .SetInsets(spacing, spacing, spacing, spacing) + ) + .Add(new BSeparatorView(B_HORIZONTAL)) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) + .AddGlue() + .Add(fInstallerButton) + .Add(fDesktopButton) + .SetInsets(spacing, spacing, spacing, spacing) + ) + ); + + CenterOnScreen(); + Show(); +} + + +void +BootPromptWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_LANGUAGE_SELECTED: + if (BListItem* item = fLanguagesListView->ItemAt( + fLanguagesListView->CurrentSelection(0))) { + LanguageItem* languageItem = dynamic_cast<LanguageItem*>(item); + BMessage preferredLanguages; + preferredLanguages.AddString("language", + languageItem->Language()); + be_locale_roster->SetPreferredLanguages(&preferredLanguages); + _InitCatalog(true); + } + // Calling it here is a cheap way of preventing the user to have + // no item selected. Always the current item will be selected. + _UpdateStrings(); + break; + + case MSG_KEYMAP_SELECTED: + _StoreKeymap(); + break; + + default: + BWindow::MessageReceived(message); + } +} + + +void +BootPromptWindow::_InitCatalog(bool saveSettings) +{ + // Initilialize the Locale Kit + // TODO: The below code is a work-around for not being able to + // call GetAppCatalog() more than once. + be_catalog = be_app_catalog = NULL; + // NOTE: be_catalog and be_app_catalog will point fo &fCatalog! + + be_locale->GetAppCatalog(&fCatalog); + + // Generate a settings file + // TODO: This should not be necessary. + // be_locale_roster->SetPreferredLanguages() should take care of things + if (!saveSettings) + return; + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append("Locale settings") != B_OK) { + return; + } + + BMessage settings; + + BFile file; + if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) + settings.Unflatten(&file); + + BString language; + if (fCatalog.GetLanguage(&language) == B_OK) { + settings.RemoveName("language"); + settings.AddString("language", language.String()); + } + + settings.RemoveName("country"); + BCountry country(language.String(), language.ToUpper()); + settings.AddString("country", country.Code()); + + if (file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY) + != B_OK + || settings.Flatten(&file) != B_OK) { + fprintf(stderr, "Failed to write Local Kit settings!\n"); + } +} + + +void +BootPromptWindow::_UpdateStrings() +{ + SetTitle(TR("Welcome to Haiku")); + + const char* infoText = TR( + "Welcome to Haiku!\n\n" + + "Do you wish to want to run the Installer or continue booting " + "to the Desktop?\n\n" + + "Please select your preferred language and keyboard layout from " + "the list below." + ); + + fInfoTextView->SetText(infoText); + + fDesktopButton->SetLabel(TR("Desktop")); + fInstallerButton->SetLabel(TR("Installer")); + + fLanguagesLabelView->SetText(TR("Language")); + fKeymapsLabelView->SetText(TR("Keymap")); + + _PopulateLanguages(); + _PopulateKeymaps(); +} + + +void +BootPromptWindow::_PopulateLanguages() +{ + // Disable sending the selection message while we change the selection. + fLanguagesListView->SetSelectionMessage(NULL); + + // Clear the list view first + while (BListItem* item = fLanguagesListView->RemoveItem( + fLanguagesListView->CountItems() - 1)) { + delete item; + } + + // Get current first preferred language of the user + BMessage preferredLanguages; + be_locale_roster->GetPreferredLanguages(&preferredLanguages); + const char* firstPreferredLanguage; + if (preferredLanguages.FindString("language", &firstPreferredLanguage) + != B_OK) { + // Fall back to built-in language of this application. + firstPreferredLanguage = "en"; + } + +// TODO: Use this API instead once it's ready. +// BMessage installedCatalogs; +// be_locale_roster->GetInstalledCatalogs(&installedCatalogs); +// installedCatalogs.PrintToStream(); + +// TODO: BLocaleRoster uses static variables!! Fix this! Or else one can only +// call this once! +// // Get the list of all known languages +// BMessage installedLanguages; +// be_locale_roster->GetInstalledLanguages(&installedLanguages); + + // Try to instantiate a BCatalog for each language, it will only work + // for translations of this application. So the list of languages will be + // limited to catalogs written for this application, which is on purpose! + const char* languageString; + for (int32 i = 0; + fInstalledLanguages.FindString("langs", i, &languageString) == B_OK; + i++) { + BCatalog catalog("x-vnd.Haiku-ReadOnlyBootPrompt", languageString); + if (catalog.InitCheck() == B_OK) { + BLanguage* language; + if (be_locale_roster->GetLanguage(&language, + BString(languageString)) == B_OK) { + BString name; + language->GetName(&name); + LanguageItem* item = new LanguageItem(name.String(), + languageString); + fLanguagesListView->AddItem(item); + // Select this item if it is the first preferred language + if (strcmp(firstPreferredLanguage, languageString) == 0) { + fLanguagesListView->Select( + fLanguagesListView->CountItems() - 1); + } + } else + printf("failed to get BLanguage for %s\n", languageString); + } + } + + // Re-enable sending the selection message. + fLanguagesListView->SetSelectionMessage( + new BMessage(MSG_LANGUAGE_SELECTED)); +} + + +void +BootPromptWindow::_PopulateKeymaps() +{ + // Disable sending the selection message while we change the selection. + fKeymapsListView->SetSelectionMessage(NULL); + + // Clean the list view first + while (BListItem* item = fKeymapsListView->RemoveItem( + fKeymapsListView->CountItems() - 1)) { + delete item; + } + + // Get the name of the current keymap, so we can mark the correct entry + // in the list view. + BString currentKeymapName; + entry_ref ref; + if (_GetCurrentKeymapRef(ref) == B_OK) { + BNode node(&ref); + node.ReadAttrString("keymap:name", ¤tKeymapName); + } + + // TODO: common keymaps! + BPath path; + if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK + || path.Append("Keymaps") != B_OK) { + return; + } + + // Populate the list + BDirectory directory; + if (directory.SetTo(path.Path()) == B_OK) { + while (directory.GetNextRef(&ref) == B_OK) { + fKeymapsListView->AddItem(new KeymapListItem(ref)); + if (currentKeymapName == ref.name) + fKeymapsListView->Select(fKeymapsListView->CountItems() - 1); + } + } + + fKeymapsListView->ScrollToSelection(); + + // Re-enable sending the selection message. + fKeymapsListView->SetSelectionMessage( + new BMessage(MSG_KEYMAP_SELECTED)); +} + + +void +BootPromptWindow::_StoreKeymap() const +{ + KeymapListItem* item = dynamic_cast<KeymapListItem*>( + fKeymapsListView->ItemAt(fKeymapsListView->CurrentSelection(0))); + if (item == NULL) + return; + + // Load and use the new keymap + Keymap keymap; + if (keymap.Load(item->EntryRef()) != B_OK) { + fprintf(stderr, "Failed to load new keymap file (%s).\n", + item->EntryRef().name); + return; + } + + // Get entry_ref to the Key_map file in the user settings. + entry_ref ref; + if (_GetCurrentKeymapRef(ref) != B_OK) { + fprintf(stderr, "Failed to get ref to user keymap file.\n"); + return; + } + + if (keymap.Save(ref) != B_OK) { + fprintf(stderr, "Failed to save new keymap file (%s).\n", + item->EntryRef().name); + return; + } + + keymap.Use(); +} + + +status_t +BootPromptWindow::_GetCurrentKeymapRef(entry_ref& ref) const +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append("Key_map") != B_OK) { + return B_ERROR; + } + + return get_ref_for_path(path.Path(), &ref); +} + Added: haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.h =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.h (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.h 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,46 @@ +/* + * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx>. + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef BOOT_PROMPT_WINDOW_H +#define BOOT_PROMPT_WINDOW_H + +#include <Catalog.h> +#include <Message.h> +#include <Window.h> + +class BButton; +class BListView; +class BStringView; +class BTextView; + + +class BootPromptWindow : public BWindow { +public: + BootPromptWindow(); + + virtual void MessageReceived(BMessage* message); + +private: + void _InitCatalog(bool saveSettings); + void _UpdateStrings(); + void _PopulateLanguages(); + void _PopulateKeymaps(); + void _StoreKeymap() const; + status_t _GetCurrentKeymapRef(entry_ref& ref) const; + +private: + BCatalog fCatalog; + BTextView* fInfoTextView; + BStringView* fLanguagesLabelView; + BListView* fLanguagesListView; + BStringView* fKeymapsLabelView; + BListView* fKeymapsListView; + BButton* fDesktopButton; + BButton* fInstallerButton; + + // TODO: Should not be needed, see TODO in _PopulateLanguages() + BMessage fInstalledLanguages; +}; + +#endif // BOOT_PROMPT_WINDOW_H Added: haiku/trunk/src/apps/readonlybootprompt/Jamfile =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/Jamfile (rev 0) +++ haiku/trunk/src/apps/readonlybootprompt/Jamfile 2010-01-21 14:41:58 UTC (rev 35221) @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src apps readonlybootprompt ; + +UsePrivateHeaders interface shared ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src preferences keymap ] ; + +Application ReadOnlyBootPrompt : + BootPrompt.cpp + BootPromptWindow.cpp + Keymap.cpp + KeymapListItem.cpp + : be libshared.a $(TARGET_LIBSTDC++) liblocale.so + : BootPrompt.rdef +; + +DoCatalogs ReadOnlyBootPrompt : + x-vnd.Haiku-ReadOnlyBootPrompt + : + BootPrompt.cpp + BootPromptWindow.cpp + : en.catalog + : de.catkeys +; +