1 /* 2 * Copyright 2003-2015, Haiku, Inc. All Rights Reserved. 3 * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net> 4 * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> 5 * Copyright (c) 1998,99 Kazuho Okui and Takashi Murai. 6 * 7 * Distributed unter the terms of the MIT License. 8 * 9 * Authors: 10 * Kian Duffy, myob@users.sourceforge.net 11 * Daniel Furrer, assimil8or@users.sourceforge.net 12 * Siarzhuk Zharski, zharik@gmx.li 13 */ 14 15 16 #include "PrefHandler.h" 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include <Catalog.h> 24 #include <Directory.h> 25 #include <Entry.h> 26 #include <File.h> 27 #include <FindDirectory.h> 28 #include <Font.h> 29 #include <GraphicsDefs.h> 30 #include <Locale.h> 31 #include <Message.h> 32 #include <NodeInfo.h> 33 #include <Path.h> 34 35 #include "Globals.h" 36 #include "TermConst.h" 37 38 #include <iostream> 39 40 /* 41 * Startup preference settings. 42 */ 43 static const pref_defaults kTermDefaults[] = { 44 { PREF_COLS, "80" }, 45 { PREF_ROWS, "25" }, 46 47 // No need for PREF_HALF_FONT_FAMILY/_STYLE defaults here, 48 // these entries will be filled with corresponding params 49 // of the current system fixed font if they are not 50 // available in the settings file 51 52 { PREF_HALF_FONT_SIZE, "12" }, 53 54 { PREF_TEXT_FORE_COLOR, " 0, 0, 0" }, 55 { PREF_TEXT_BACK_COLOR, "255, 255, 255" }, 56 { PREF_CURSOR_FORE_COLOR, "255, 255, 255" }, 57 { PREF_CURSOR_BACK_COLOR, " 0, 0, 0" }, 58 { PREF_SELECT_FORE_COLOR, "255, 255, 255" }, 59 { PREF_SELECT_BACK_COLOR, " 0, 0, 0" }, 60 61 { PREF_IM_FORE_COLOR, " 0, 0, 0" }, 62 { PREF_IM_BACK_COLOR, "152, 203, 255" }, 63 { PREF_IM_SELECT_COLOR, "255, 152, 152" }, 64 65 { PREF_ANSI_BLACK_COLOR, " 40, 40, 40" }, 66 { PREF_ANSI_RED_COLOR, "204, 0, 0" }, 67 { PREF_ANSI_GREEN_COLOR, " 78, 154, 6" }, 68 { PREF_ANSI_YELLOW_COLOR, "218, 168, 0" }, 69 { PREF_ANSI_BLUE_COLOR, " 51, 102, 152" }, 70 { PREF_ANSI_MAGENTA_COLOR, "115, 68, 123" }, 71 { PREF_ANSI_CYAN_COLOR, " 6, 152, 154" }, 72 { PREF_ANSI_WHITE_COLOR, "245, 245, 245" }, 73 74 { PREF_ANSI_BLACK_HCOLOR, "128, 128, 128" }, 75 { PREF_ANSI_RED_HCOLOR, "255, 0, 0" }, 76 { PREF_ANSI_GREEN_HCOLOR, " 0, 255, 0" }, 77 { PREF_ANSI_YELLOW_HCOLOR, "255, 255, 0" }, 78 { PREF_ANSI_BLUE_HCOLOR, " 0, 0, 255" }, 79 { PREF_ANSI_MAGENTA_HCOLOR, "255, 0, 255" }, 80 { PREF_ANSI_CYAN_HCOLOR, " 0, 255, 255" }, 81 { PREF_ANSI_WHITE_HCOLOR, "255, 255, 255" }, 82 83 { PREF_HISTORY_SIZE, "10000" }, 84 85 { PREF_TEXT_ENCODING, "UTF-8" }, 86 87 { PREF_IM_AWARE, "0"}, 88 89 { PREF_TAB_TITLE, "%1d: %p%e" }, 90 { PREF_WINDOW_TITLE, "%T% i: %t" }, 91 { PREF_BLINK_CURSOR, PREF_TRUE }, 92 { PREF_WARN_ON_EXIT, PREF_TRUE }, 93 { PREF_CURSOR_STYLE, PREF_BLOCK_CURSOR }, 94 { PREF_EMULATE_BOLD, PREF_FALSE }, 95 96 { NULL, NULL}, 97 }; 98 99 100 PrefHandler *PrefHandler::sPrefHandler = NULL; 101 102 103 PrefHandler::PrefHandler(bool loadSettings) 104 : 105 fContainer('Pref') 106 { 107 _LoadFromDefault(kTermDefaults); 108 109 if (loadSettings) { 110 BPath path; 111 GetDefaultPath(path); 112 OpenText(path.Path()); 113 } 114 115 // TODO: If no fixed font is available, be_fixed_font 116 // points to a proportional font. 117 if (IsFontUsable(be_fixed_font)) 118 _ConfirmFont(be_fixed_font); 119 else { 120 int32 numFamilies = count_font_families(); 121 for (int32 i = 0; i < numFamilies; i++) { 122 font_family family; 123 uint32 flags; 124 if (get_font_family(i, &family, &flags) == B_OK) { 125 font_style style; 126 int32 numStyles = count_font_styles(family); 127 for (int32 j = 0; j < numStyles; j++) { 128 if (get_font_style(family, j, &style) == B_OK) { 129 BFont fallBackFont; 130 fallBackFont.SetFamilyAndStyle(family, style); 131 if (IsFontUsable(fallBackFont)) { 132 _ConfirmFont(&fallBackFont); 133 return; 134 } 135 } 136 } 137 } 138 } 139 } 140 } 141 142 143 PrefHandler::PrefHandler(const PrefHandler* p) 144 { 145 fContainer = p->fContainer; 146 } 147 148 149 PrefHandler::~PrefHandler() 150 { 151 } 152 153 154 /* static */ 155 PrefHandler * 156 PrefHandler::Default() 157 { 158 if (sPrefHandler == NULL) 159 sPrefHandler = new PrefHandler(); 160 return sPrefHandler; 161 } 162 163 164 /* static */ 165 void 166 PrefHandler::DeleteDefault() 167 { 168 delete sPrefHandler; 169 sPrefHandler = NULL; 170 } 171 172 173 /* static */ 174 void 175 PrefHandler::SetDefault(PrefHandler *prefHandler) 176 { 177 DeleteDefault(); 178 sPrefHandler = prefHandler; 179 } 180 181 182 /* static */ 183 status_t 184 PrefHandler::GetDefaultPath(BPath& path) 185 { 186 status_t status; 187 status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 188 if (status != B_OK) 189 return status; 190 191 status = path.Append("Terminal"); 192 if (status != B_OK) 193 return status; 194 195 // Just create the directory. Harmless if already there 196 status = create_directory(path.Path(), 0755); 197 if (status != B_OK) 198 return status; 199 200 return path.Append("Default"); 201 } 202 203 204 status_t 205 PrefHandler::OpenText(const char *path) 206 { 207 return _LoadFromTextFile(path); 208 } 209 210 211 void 212 PrefHandler::SaveDefaultAsText() 213 { 214 BPath path; 215 if (GetDefaultPath(path) == B_OK) 216 SaveAsText(path.Path(), PREFFILE_MIMETYPE); 217 } 218 219 220 void 221 PrefHandler::SaveAsText(const char *path, const char *mimetype, 222 const char *signature) 223 { 224 // make sure the target path exists 225 #if 0 226 BPath directoryPath(path); 227 if (directoryPath.GetParent(&directoryPath) == B_OK) 228 create_directory(directoryPath.Path(), 0755); 229 #endif 230 231 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 232 char buffer[512]; 233 type_code type; 234 const char *key; 235 236 for (int32 i = 0; 237 #ifdef B_BEOS_VERSION_DANO 238 fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK; 239 #else 240 fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK; 241 #endif 242 i++) { 243 int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", 244 key, getString(key)); 245 file.Write(buffer, len); 246 } 247 248 if (mimetype != NULL) { 249 BNodeInfo info(&file); 250 info.SetType(mimetype); 251 info.SetPreferredApp(signature); 252 } 253 } 254 255 256 int32 257 PrefHandler::getInt32(const char *key) 258 { 259 const char *value = fContainer.FindString(key); 260 if (value == NULL) 261 return 0; 262 263 return atoi(value); 264 } 265 266 267 float 268 PrefHandler::getFloat(const char *key) 269 { 270 const char *value = fContainer.FindString(key); 271 if (value == NULL) 272 return 0; 273 274 return atof(value); 275 } 276 277 278 #undef B_TRANSLATION_CONTEXT 279 #define B_TRANSLATION_CONTEXT "Terminal getString" 280 281 const char* 282 PrefHandler::getString(const char *key) 283 { 284 const char *buffer; 285 if (fContainer.FindString(key, &buffer) != B_OK) 286 buffer = B_TRANSLATE("Error!"); 287 288 //printf("%x GET %s: %s\n", this, key, buf); 289 return buffer; 290 } 291 292 293 bool 294 PrefHandler::getBool(const char *key) 295 { 296 const char *value = fContainer.FindString(key); 297 if (value == NULL) 298 return false; 299 300 return strcmp(value, PREF_TRUE) == 0; 301 } 302 303 304 int 305 PrefHandler::getCursor(const char *key) 306 { 307 const char *value = fContainer.FindString(key); 308 if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) { 309 if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0) 310 return UNDERLINE_CURSOR; 311 if (strcmp(value, PREF_IBEAM_CURSOR) == 0) 312 return IBEAM_CURSOR; 313 } 314 return BLOCK_CURSOR; 315 } 316 317 318 #undef B_TRANSLATION_CONTEXT 319 #define B_TRANSLATION_CONTEXT "Terminal getRGB" 320 321 /** Returns RGB data from given key. */ 322 323 rgb_color 324 PrefHandler::getRGB(const char *key) 325 { 326 rgb_color col; 327 int r, g, b; 328 329 if (const char *s = fContainer.FindString(key)) { 330 sscanf(s, "%d, %d, %d", &r, &g, &b); 331 } else { 332 fprintf(stderr, 333 "PrefHandler::getRGB(%s) - key not found\n", key); 334 r = g = b = 0; 335 } 336 337 col.red = r; 338 col.green = g; 339 col.blue = b; 340 col.alpha = 255; 341 return col; 342 } 343 344 345 /** Setting Int32 data with key. */ 346 347 void 348 PrefHandler::setInt32(const char *key, int32 data) 349 { 350 char buffer[32]; 351 snprintf(buffer, sizeof(buffer), "%d", (int)data); 352 setString(key, buffer); 353 } 354 355 356 /** Setting Float data with key */ 357 358 void 359 PrefHandler::setFloat(const char *key, float data) 360 { 361 char buffer[32]; 362 snprintf(buffer, sizeof(buffer), "%g", data); 363 setString(key, buffer); 364 } 365 366 367 /** Setting Bool data with key */ 368 369 void 370 PrefHandler::setBool(const char *key, bool data) 371 { 372 if (data) 373 setString(key, PREF_TRUE); 374 else 375 setString(key, PREF_FALSE); 376 } 377 378 379 /** Setting CString data with key */ 380 381 void 382 PrefHandler::setString(const char *key, const char *data) 383 { 384 //printf("%x SET %s: %s\n", this, key, data); 385 fContainer.RemoveName(key); 386 fContainer.AddString(key, data); 387 } 388 389 390 /** Setting RGB data with key */ 391 392 void 393 PrefHandler::setRGB(const char *key, const rgb_color data) 394 { 395 char buffer[32]; 396 snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue); 397 setString(key, buffer); 398 } 399 400 401 /** Check any peference stored or not. */ 402 403 bool 404 PrefHandler::IsEmpty() const 405 { 406 return fContainer.IsEmpty(); 407 } 408 409 410 void 411 PrefHandler::_ConfirmFont(const BFont *fallbackFont) 412 { 413 font_family family; 414 font_style style; 415 416 const char *prefFamily = getString(PREF_HALF_FONT_FAMILY); 417 int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0; 418 419 for (int32 i = 0; i < familiesCount; i++) { 420 if (get_font_family(i, &family) != B_OK 421 || strcmp(family, prefFamily) != 0) 422 continue; 423 424 const char *prefStyle = getString(PREF_HALF_FONT_STYLE); 425 int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0; 426 427 for (int32 j = 0; j < stylesCount; j++) { 428 // check style if we can safely use this font 429 if (get_font_style(family, j, &style) == B_OK 430 && strcmp(style, prefStyle) == 0) 431 return; 432 } 433 } 434 435 // use fall-back font 436 fallbackFont->GetFamilyAndStyle(&family, &style); 437 setString(PREF_HALF_FONT_FAMILY, family); 438 setString(PREF_HALF_FONT_STYLE, style); 439 } 440 441 442 status_t 443 PrefHandler::_LoadFromDefault(const pref_defaults* defaults) 444 { 445 if (defaults == NULL) 446 return B_ERROR; 447 448 while (defaults->key) { 449 setString(defaults->key, defaults->item); 450 ++defaults; 451 } 452 453 return B_OK; 454 } 455 456 457 /** Text is "key","Content" 458 * Comment : Start with '#' 459 */ 460 461 status_t 462 PrefHandler::_LoadFromTextFile(const char * path) 463 { 464 char buffer[1024]; 465 char key[B_FIELD_NAME_LENGTH], data[512]; 466 int n; 467 FILE *file; 468 469 file = fopen(path, "r"); 470 if (file == NULL) 471 return B_ENTRY_NOT_FOUND; 472 473 while (fgets(buffer, sizeof(buffer), file) != NULL) { 474 if (*buffer == '#') 475 continue; 476 477 n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data); 478 if (n == 2) 479 setString(key, data); 480 } 481 482 fclose(file); 483 return B_OK; 484 } 485