* Copyright 2003-2015, Haiku, Inc. All Rights Reserved.
* Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net>
* Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net>
* Copyright (c) 1998,99 Kazuho Okui and Takashi Murai.
*
* Distributed unter the terms of the MIT License.
*
* Authors:
* Kian Duffy, myob@users.sourceforge.net
* Daniel Furrer, assimil8or@users.sourceforge.net
* Simon South, simon@simonsouth.net
* Siarzhuk Zharski, zharik@gmx.li
*/
#include "PrefHandler.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Font.h>
#include <GraphicsDefs.h>
#include <Locale.h>
#include <Message.h>
#include <NodeInfo.h>
#include <Path.h>
#include <PathFinder.h>
#include "Colors.h"
#include "Globals.h"
#include "TermConst.h"
#include <iostream>
* Startup preference settings.
*/
static const pref_defaults kTermDefaults[] = {
{ PREF_COLS, "80" },
{ PREF_ROWS, "25" },
{ PREF_TEXT_FORE_COLOR, " 0, 0, 0" },
{ PREF_TEXT_BACK_COLOR, "255, 255, 255" },
{ PREF_CURSOR_FORE_COLOR, "255, 255, 255" },
{ PREF_CURSOR_BACK_COLOR, " 0, 0, 0" },
{ PREF_SELECT_FORE_COLOR, "255, 255, 255" },
{ PREF_SELECT_BACK_COLOR, " 0, 0, 0" },
{ PREF_IM_FORE_COLOR, " 0, 0, 0" },
{ PREF_IM_BACK_COLOR, "152, 203, 255" },
{ PREF_IM_SELECT_COLOR, "255, 152, 152" },
{ PREF_ANSI_BLACK_COLOR, " 40, 40, 40" },
{ PREF_ANSI_RED_COLOR, "204, 0, 0" },
{ PREF_ANSI_GREEN_COLOR, " 78, 154, 6" },
{ PREF_ANSI_YELLOW_COLOR, "218, 168, 0" },
{ PREF_ANSI_BLUE_COLOR, " 51, 102, 152" },
{ PREF_ANSI_MAGENTA_COLOR, "115, 68, 123" },
{ PREF_ANSI_CYAN_COLOR, " 6, 152, 154" },
{ PREF_ANSI_WHITE_COLOR, "245, 245, 245" },
{ PREF_ANSI_BLACK_HCOLOR, "128, 128, 128" },
{ PREF_ANSI_RED_HCOLOR, "255, 0, 0" },
{ PREF_ANSI_GREEN_HCOLOR, " 0, 255, 0" },
{ PREF_ANSI_YELLOW_HCOLOR, "255, 255, 0" },
{ PREF_ANSI_BLUE_HCOLOR, " 0, 0, 255" },
{ PREF_ANSI_MAGENTA_HCOLOR, "255, 0, 255" },
{ PREF_ANSI_CYAN_HCOLOR, " 0, 255, 255" },
{ PREF_ANSI_WHITE_HCOLOR, "255, 255, 255" },
{ PREF_HISTORY_SIZE, "10000" },
{ PREF_TEXT_ENCODING, "UTF-8" },
{ PREF_IM_AWARE, "0"},
{ PREF_TAB_TITLE, "%1d: %p%e" },
{ PREF_WINDOW_TITLE, "%T% i: %t" },
{ PREF_BLINK_CURSOR, PREF_TRUE },
{ PREF_USE_OPTION_AS_META, PREF_FALSE },
{ PREF_WARN_ON_EXIT, PREF_TRUE },
{ PREF_CURSOR_STYLE, PREF_BLOCK_CURSOR },
{ PREF_EMULATE_BOLD, PREF_FALSE },
{ NULL, NULL},
};
PrefHandler *PrefHandler::sPrefHandler = NULL;
PrefHandler::PrefHandler(bool loadSettings)
:
fContainer('Pref')
{
_LoadFromDefault(kTermDefaults);
if (loadSettings) {
BPath path;
GetDefaultPath(path);
OpenText(path.Path());
if (gColorSchemes == NULL) {
LoadThemes();
}
}
if (IsFontUsable(be_fixed_font))
_ConfirmFont(be_fixed_font);
else {
int32 numFamilies = count_font_families();
for (int32 i = 0; i < numFamilies; i++) {
font_family family;
uint32 flags;
if (get_font_family(i, &family, &flags) == B_OK) {
font_style style;
int32 numStyles = count_font_styles(family);
for (int32 j = 0; j < numStyles; j++) {
if (get_font_style(family, j, &style) == B_OK) {
BFont fallBackFont;
fallBackFont.SetFamilyAndStyle(family, style);
if (IsFontUsable(fallBackFont)) {
_ConfirmFont(&fallBackFont);
return;
}
}
}
}
}
}
}
PrefHandler::PrefHandler(const PrefHandler* p)
{
fContainer = p->fContainer;
}
PrefHandler::~PrefHandler()
{
}
PrefHandler *
PrefHandler::Default()
{
if (sPrefHandler == NULL)
sPrefHandler = new PrefHandler();
return sPrefHandler;
}
void
PrefHandler::DeleteDefault()
{
delete sPrefHandler;
sPrefHandler = NULL;
}
void
PrefHandler::SetDefault(PrefHandler *prefHandler)
{
DeleteDefault();
sPrefHandler = prefHandler;
}
status_t
PrefHandler::GetDefaultPath(BPath& path)
{
status_t status;
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
if (status != B_OK)
return status;
status = path.Append("Terminal");
if (status != B_OK)
return status;
status = create_directory(path.Path(), 0755);
if (status != B_OK)
return status;
return path.Append("Default");
}
status_t
PrefHandler::OpenText(const char *path)
{
return _LoadFromTextFile(path);
}
void
PrefHandler::SaveDefaultAsText()
{
BPath path;
if (GetDefaultPath(path) == B_OK)
SaveAsText(path.Path(), PREFFILE_MIMETYPE);
}
void
PrefHandler::SaveAsText(const char *path, const char *mimetype,
const char *signature)
{
#if 0
BPath directoryPath(path);
if (directoryPath.GetParent(&directoryPath) == B_OK)
create_directory(directoryPath.Path(), 0755);
#endif
BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
char buffer[512];
type_code type;
const char *key;
for (int32 i = 0;
#ifdef B_BEOS_VERSION_DANO
fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK;
#else
fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK;
#endif
i++) {
int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
key, getString(key));
file.Write(buffer, len);
}
if (mimetype != NULL) {
BNodeInfo info(&file);
info.SetType(mimetype);
info.SetPreferredApp(signature);
}
}
static int
SortByName(const color_scheme *lhs, const color_scheme *rhs)
{
return strcmp(lhs->name, rhs->name);
}
void
PrefHandler::LoadThemes()
{
gColorSchemes = new BObjectList<const color_scheme, true>(10);
BStringList paths;
if (BPathFinder::FindPaths(B_FIND_PATH_DATA_DIRECTORY,
"Terminal/Themes/", B_FIND_PATH_EXISTING_ONLY, paths) == B_OK)
paths.DoForEach(PrefHandler::_LoadThemesFromDirectory);
if (BPathFinder::FindPaths(B_FIND_PATH_SETTINGS_DIRECTORY,
"Terminal/Themes/", B_FIND_PATH_EXISTING_ONLY, paths) == B_OK)
paths.DoForEach(PrefHandler::_LoadThemesFromDirectory);
gColorSchemes->SortItems(SortByName);
}
void
PrefHandler::LoadColorScheme(color_scheme* scheme)
{
scheme->text_fore_color = getRGB(PREF_TEXT_FORE_COLOR);
scheme->text_back_color = getRGB(PREF_TEXT_BACK_COLOR);
scheme->select_fore_color = getRGB(PREF_SELECT_FORE_COLOR);
scheme->select_back_color = getRGB(PREF_SELECT_BACK_COLOR);
scheme->cursor_fore_color = getRGB(PREF_CURSOR_FORE_COLOR);
scheme->cursor_back_color = getRGB(PREF_CURSOR_BACK_COLOR);
scheme->ansi_colors.black = getRGB(PREF_ANSI_BLACK_COLOR);
scheme->ansi_colors.red = getRGB(PREF_ANSI_RED_COLOR);
scheme->ansi_colors.green = getRGB(PREF_ANSI_GREEN_COLOR);
scheme->ansi_colors.yellow = getRGB(PREF_ANSI_YELLOW_COLOR);
scheme->ansi_colors.blue = getRGB(PREF_ANSI_BLUE_COLOR);
scheme->ansi_colors.magenta = getRGB(PREF_ANSI_MAGENTA_COLOR);
scheme->ansi_colors.cyan = getRGB(PREF_ANSI_CYAN_COLOR);
scheme->ansi_colors.white = getRGB(PREF_ANSI_WHITE_COLOR);
scheme->ansi_colors_h.black = getRGB(PREF_ANSI_BLACK_HCOLOR);
scheme->ansi_colors_h.red = getRGB(PREF_ANSI_RED_HCOLOR);
scheme->ansi_colors_h.green = getRGB(PREF_ANSI_GREEN_HCOLOR);
scheme->ansi_colors_h.yellow = getRGB(PREF_ANSI_YELLOW_HCOLOR);
scheme->ansi_colors_h.blue = getRGB(PREF_ANSI_BLUE_HCOLOR);
scheme->ansi_colors_h.magenta = getRGB(PREF_ANSI_MAGENTA_HCOLOR);
scheme->ansi_colors_h.cyan = getRGB(PREF_ANSI_CYAN_HCOLOR);
scheme->ansi_colors_h.white = getRGB(PREF_ANSI_WHITE_HCOLOR);
}
int32
PrefHandler::getInt32(const char *key)
{
const char *value = fContainer.FindString(key);
if (value == NULL)
return 0;
return atoi(value);
}
float
PrefHandler::getFloat(const char *key)
{
const char *value = fContainer.FindString(key);
if (value == NULL)
return 0;
return atof(value);
}
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal getString"
const char*
PrefHandler::getString(const char *key)
{
const char *buffer;
if (fContainer.FindString(key, &buffer) != B_OK)
buffer = B_TRANSLATE("Error!");
return buffer;
}
bool
PrefHandler::getBool(const char *key)
{
const char *value = fContainer.FindString(key);
if (value == NULL)
return false;
return strcmp(value, PREF_TRUE) == 0;
}
int
PrefHandler::getCursor(const char *key)
{
const char *value = fContainer.FindString(key);
if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) {
if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0)
return UNDERLINE_CURSOR;
if (strcmp(value, PREF_IBEAM_CURSOR) == 0)
return IBEAM_CURSOR;
}
return BLOCK_CURSOR;
}
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal getRGB"
rgb_color
PrefHandler::getRGB(const char *key)
{
rgb_color col;
int r, g, b;
if (const char *s = fContainer.FindString(key)) {
sscanf(s, "%d, %d, %d", &r, &g, &b);
} else {
fprintf(stderr,
"PrefHandler::getRGB(%s) - key not found\n", key);
r = g = b = 0;
}
col.red = r;
col.green = g;
col.blue = b;
col.alpha = 255;
return col;
}
void
PrefHandler::setInt32(const char *key, int32 data)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d", (int)data);
setString(key, buffer);
}
void
PrefHandler::setFloat(const char *key, float data)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%g", data);
setString(key, buffer);
}
void
PrefHandler::setBool(const char *key, bool data)
{
if (data)
setString(key, PREF_TRUE);
else
setString(key, PREF_FALSE);
}
void
PrefHandler::setString(const char *key, const char *data)
{
fContainer.RemoveName(key);
fContainer.AddString(key, data);
}
void
PrefHandler::setRGB(const char *key, const rgb_color data)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue);
setString(key, buffer);
}
bool
PrefHandler::IsEmpty() const
{
return fContainer.IsEmpty();
}
void
PrefHandler::_ConfirmFont(const BFont *fallbackFont)
{
font_family family;
font_style style;
const char *prefFamily = getString(PREF_HALF_FONT_FAMILY);
int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0;
for (int32 i = 0; i < familiesCount; i++) {
if (get_font_family(i, &family) != B_OK
|| strcmp(family, prefFamily) != 0)
continue;
const char *prefStyle = getString(PREF_HALF_FONT_STYLE);
int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0;
for (int32 j = 0; j < stylesCount; j++) {
if (get_font_style(family, j, &style) == B_OK
&& strcmp(style, prefStyle) == 0)
return;
}
}
fallbackFont->GetFamilyAndStyle(&family, &style);
setString(PREF_HALF_FONT_FAMILY, family);
setString(PREF_HALF_FONT_STYLE, style);
setInt32(PREF_HALF_FONT_SIZE, fallbackFont->Size());
}
status_t
PrefHandler::_LoadFromDefault(const pref_defaults* defaults)
{
if (defaults == NULL)
return B_ERROR;
while (defaults->key) {
setString(defaults->key, defaults->item);
++defaults;
}
return B_OK;
}
* Comment : Start with '#'
*/
status_t
PrefHandler::_LoadFromTextFile(const char * path)
{
char buffer[1024];
char key[B_FIELD_NAME_LENGTH], data[512];
int n;
FILE *file;
file = fopen(path, "r");
if (file == NULL)
return B_ENTRY_NOT_FOUND;
while (fgets(buffer, sizeof(buffer), file) != NULL) {
if (*buffer == '#')
continue;
n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data);
if (n == 2)
setString(key, data);
}
fclose(file);
return B_OK;
}
bool
PrefHandler::_LoadThemesFromDirectory(const BString &directory)
{
BDirectory *themes = new BDirectory(directory.String());
if (themes == NULL)
return false;
BEntry entry;
BPath path;
FindColorSchemeByName comparator;
while (themes->GetNextEntry(&entry) == B_OK)
{
if (entry.GetPath(&path) != B_OK)
continue;
PrefHandler *themeHandler = new PrefHandler(false);
ObjectDeleter<PrefHandler> themeHandlerDeleter(themeHandler);
themeHandler->_LoadFromTextFile(path.Path());
const char *name = themeHandler->fContainer.GetString(PREF_THEME_NAME, NULL);
if (name == NULL || strlen(name) == 0)
continue;
comparator.scheme_name = name;
const color_scheme *scheme = gColorSchemes->FindIf(comparator);
if (scheme != NULL) {
gColorSchemes->RemoveItem(scheme);
}
color_scheme *newScheme = new color_scheme();
newScheme->name = strdup(name);
themeHandler->LoadColorScheme(newScheme);
gColorSchemes->AddItem(newScheme);
}
return false;
}