487 lines
9.8 KiB
C++
487 lines
9.8 KiB
C++
/*
|
|
* 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 <Catalog.h>
|
|
#include <Directory.h>
|
|
#include <Entry.h>
|
|
#include <File.h>
|
|
#include <FindDirectory.h>
|
|
#include <Font.h>
|
|
#include <GraphicsDefs.h>
|
|
#include <Locale.h>
|
|
#include <Message.h>
|
|
#include <NodeInfo.h>
|
|
#include <Path.h>
|
|
|
|
#include "Globals.h"
|
|
#include "TermConst.h"
|
|
|
|
#include <iostream>
|
|
|
|
/*
|
|
* Startup preference settings.
|
|
*/
|
|
static const pref_defaults kTermDefaults[] = {
|
|
{ PREF_COLS, "80" },
|
|
{ PREF_ROWS, "25" },
|
|
|
|
// No need for PREF_HALF_FONT_FAMILY/_STYLE defaults here,
|
|
// these entries will be filled with corresponding params
|
|
// of the current system fixed font if they are not
|
|
// available in the settings file
|
|
|
|
{ PREF_HALF_FONT_SIZE, "12" },
|
|
|
|
{ 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());
|
|
}
|
|
|
|
// TODO: If no fixed font is available, be_fixed_font
|
|
// points to a proportional font.
|
|
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()
|
|
{
|
|
}
|
|
|
|
|
|
/* static */
|
|
PrefHandler *
|
|
PrefHandler::Default()
|
|
{
|
|
if (sPrefHandler == NULL)
|
|
sPrefHandler = new PrefHandler();
|
|
return sPrefHandler;
|
|
}
|
|
|
|
|
|
/* static */
|
|
void
|
|
PrefHandler::DeleteDefault()
|
|
{
|
|
delete sPrefHandler;
|
|
sPrefHandler = NULL;
|
|
}
|
|
|
|
|
|
/* static */
|
|
void
|
|
PrefHandler::SetDefault(PrefHandler *prefHandler)
|
|
{
|
|
DeleteDefault();
|
|
sPrefHandler = prefHandler;
|
|
}
|
|
|
|
|
|
/* static */
|
|
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;
|
|
|
|
// Just create the directory. Harmless if already there
|
|
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)
|
|
{
|
|
// make sure the target path exists
|
|
#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);
|
|
}
|
|
}
|
|
|
|
|
|
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!");
|
|
|
|
//printf("%x GET %s: %s\n", this, key, buf);
|
|
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"
|
|
|
|
/** Returns RGB data from given key. */
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/** Setting Int32 data with key. */
|
|
|
|
void
|
|
PrefHandler::setInt32(const char *key, int32 data)
|
|
{
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%d", (int)data);
|
|
setString(key, buffer);
|
|
}
|
|
|
|
|
|
/** Setting Float data with key */
|
|
|
|
void
|
|
PrefHandler::setFloat(const char *key, float data)
|
|
{
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%g", data);
|
|
setString(key, buffer);
|
|
}
|
|
|
|
|
|
/** Setting Bool data with key */
|
|
|
|
void
|
|
PrefHandler::setBool(const char *key, bool data)
|
|
{
|
|
if (data)
|
|
setString(key, PREF_TRUE);
|
|
else
|
|
setString(key, PREF_FALSE);
|
|
}
|
|
|
|
|
|
/** Setting CString data with key */
|
|
|
|
void
|
|
PrefHandler::setString(const char *key, const char *data)
|
|
{
|
|
//printf("%x SET %s: %s\n", this, key, data);
|
|
fContainer.RemoveName(key);
|
|
fContainer.AddString(key, data);
|
|
}
|
|
|
|
|
|
/** Setting RGB data with key */
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/** Check any peference stored or not. */
|
|
|
|
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++) {
|
|
// check style if we can safely use this font
|
|
if (get_font_style(family, j, &style) == B_OK
|
|
&& strcmp(style, prefStyle) == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
// use fall-back font
|
|
fallbackFont->GetFamilyAndStyle(&family, &style);
|
|
setString(PREF_HALF_FONT_FAMILY, family);
|
|
setString(PREF_HALF_FONT_STYLE, style);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/** Text is "key","Content"
|
|
* 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;
|
|
}
|