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