1 /* 2 * Copyright 2005-2008, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk> 9 */ 10 11 12 #include "DesktopSettings.h" 13 #include "DesktopSettingsPrivate.h" 14 #include "Desktop.h" 15 #include "FontCache.h" 16 #include "FontCacheEntry.h" 17 #include "FontManager.h" 18 #include "GlobalSubpixelSettings.h" 19 #include "ServerConfig.h" 20 21 #include <DefaultColors.h> 22 #include <ServerReadOnlyMemory.h> 23 24 #include <Directory.h> 25 #include <File.h> 26 #include <FindDirectory.h> 27 #include <Path.h> 28 29 30 DesktopSettingsPrivate::DesktopSettingsPrivate(server_read_only_memory* shared) 31 : 32 fShared(*shared) 33 { 34 // if the on-disk settings are not complete, the defaults will be kept 35 _SetDefaults(); 36 _Load(); 37 } 38 39 40 DesktopSettingsPrivate::~DesktopSettingsPrivate() 41 { 42 } 43 44 45 void 46 DesktopSettingsPrivate::_SetDefaults() 47 { 48 fPlainFont = *gFontManager->DefaultPlainFont(); 49 fBoldFont = *gFontManager->DefaultBoldFont(); 50 fFixedFont = *gFontManager->DefaultFixedFont(); 51 52 fMouseMode = B_NORMAL_MOUSE; 53 fShowAllDraggers = true; 54 55 // init scrollbar info 56 fScrollBarInfo.proportional = true; 57 fScrollBarInfo.double_arrows = false; 58 fScrollBarInfo.knob = 1; 59 // look of the knob (R5: (0, 1, 2), 1 = default) 60 fScrollBarInfo.min_knob_size = 15; 61 62 // init menu info 63 strlcpy(fMenuInfo.f_family, fPlainFont.Family(), B_FONT_FAMILY_LENGTH); 64 strlcpy(fMenuInfo.f_style, fPlainFont.Style(), B_FONT_STYLE_LENGTH); 65 fMenuInfo.font_size = fPlainFont.Size(); 66 fMenuInfo.background_color.set_to(216, 216, 216); 67 68 fMenuInfo.separator = 0; 69 // look of the separator (R5: (0, 1, 2), default 0) 70 fMenuInfo.click_to_open = true; // always true 71 fMenuInfo.triggers_always_shown = false; 72 73 fWorkspacesCount = 4; 74 75 memcpy(fShared.colors, BPrivate::kDefaultColors, sizeof(rgb_color) * kNumColors); 76 77 gSubpixelAntialiasing = false; 78 gDefaultHinting = true; 79 gSubpixelAverageWeight = 120; 80 gSubpixelOrderingRGB = true; 81 } 82 83 84 status_t 85 DesktopSettingsPrivate::_GetPath(BPath& path) 86 { 87 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 88 if (status < B_OK) 89 return status; 90 91 status = path.Append("system/app_server"); 92 if (status < B_OK) 93 return status; 94 95 return create_directory(path.Path(), 0755); 96 } 97 98 99 status_t 100 DesktopSettingsPrivate::_Load() 101 { 102 // TODO: add support for old app_server_settings file as well 103 104 BPath basePath; 105 status_t status = _GetPath(basePath); 106 if (status < B_OK) 107 return status; 108 109 // read workspaces settings 110 111 BPath path(basePath); 112 path.Append("workspaces"); 113 114 BFile file; 115 status = file.SetTo(path.Path(), B_READ_ONLY); 116 if (status == B_OK) { 117 BMessage settings; 118 status = settings.Unflatten(&file); 119 if (status == B_OK) { 120 int32 count; 121 if (settings.FindInt32("count", &count) == B_OK) { 122 fWorkspacesCount = count; 123 if (fWorkspacesCount < 1 || fWorkspacesCount > 32) 124 fWorkspacesCount = 4; 125 } 126 127 int32 i = 0; 128 while (i < kMaxWorkspaces 129 && settings.FindMessage("workspace", i, &fWorkspaceMessages[i]) == B_OK) { 130 i++; 131 } 132 } 133 } 134 135 // read font settings 136 137 path = basePath; 138 path.Append("fonts"); 139 140 status = file.SetTo(path.Path(), B_READ_ONLY); 141 if (status == B_OK) { 142 BMessage settings; 143 status = settings.Unflatten(&file); 144 if (status == B_OK && gFontManager->Lock()) { 145 const char* family; 146 const char* style; 147 float size; 148 bool hinting; 149 if (settings.FindString("plain family", &family) == B_OK 150 && settings.FindString("plain style", &style) == B_OK 151 && settings.FindFloat("plain size", &size) == B_OK) { 152 FontStyle* fontStyle = gFontManager->GetStyle(family, style); 153 fPlainFont.SetStyle(fontStyle); 154 fPlainFont.SetSize(size); 155 } 156 if (settings.FindString("bold family", &family) == B_OK 157 && settings.FindString("bold style", &style) == B_OK 158 && settings.FindFloat("bold size", &size) == B_OK) { 159 FontStyle* fontStyle = gFontManager->GetStyle(family, style); 160 fBoldFont.SetStyle(fontStyle); 161 fBoldFont.SetSize(size); 162 } 163 if (settings.FindString("fixed family", &family) == B_OK 164 && settings.FindString("fixed style", &style) == B_OK 165 && settings.FindFloat("fixed size", &size) == B_OK) { 166 FontStyle* fontStyle = gFontManager->GetStyle(family, style); 167 if (fontStyle->IsFixedWidth()) 168 fFixedFont.SetStyle(fontStyle); 169 fFixedFont.SetSize(size); 170 } 171 if (settings.FindBool("hinting", &hinting) == B_OK) { 172 gDefaultHinting = hinting; 173 } 174 gFontManager->Unlock(); 175 } 176 } 177 178 // read mouse settings 179 180 path = basePath; 181 path.Append("mouse"); 182 183 status = file.SetTo(path.Path(), B_READ_ONLY); 184 if (status == B_OK) { 185 BMessage settings; 186 status = settings.Unflatten(&file); 187 if (status == B_OK) { 188 int32 mode; 189 if (settings.FindInt32("mode", &mode) == B_OK) { 190 fMouseMode = (mode_mouse)mode; 191 } 192 } 193 } 194 195 // read appearance settings 196 197 path = basePath; 198 path.Append("appearance"); 199 200 status = file.SetTo(path.Path(), B_READ_ONLY); 201 if (status == B_OK) { 202 BMessage settings; 203 status = settings.Unflatten(&file); 204 if (status == B_OK) { 205 float fontSize; 206 if (settings.FindFloat("font size", &fontSize) == B_OK) 207 fMenuInfo.font_size = fontSize; 208 209 const char* fontFamily; 210 if (settings.FindString("font family", &fontFamily) == B_OK) 211 strlcpy(fMenuInfo.f_family, fontFamily, B_FONT_FAMILY_LENGTH); 212 213 const char* fontStyle; 214 if (settings.FindString("font style", &fontStyle) == B_OK) 215 strlcpy(fMenuInfo.f_style, fontStyle, B_FONT_STYLE_LENGTH); 216 217 rgb_color bgColor; 218 if (settings.FindInt32("bg color", (int32*)&bgColor) == B_OK) 219 fMenuInfo.background_color = bgColor; 220 221 int32 separator; 222 if (settings.FindInt32("separator", &separator) == B_OK) 223 fMenuInfo.separator = separator; 224 225 bool clickToOpen; 226 if (settings.FindBool("click to open", &clickToOpen) == B_OK) 227 fMenuInfo.click_to_open = clickToOpen; 228 229 bool triggersAlwaysShown; 230 if (settings.FindBool("triggers always shown", &triggersAlwaysShown) 231 == B_OK) { 232 fMenuInfo.triggers_always_shown = triggersAlwaysShown; 233 } 234 235 bool subpix; 236 if (settings.FindBool("subpixel antialiasing", &subpix) == B_OK) 237 gSubpixelAntialiasing = subpix; 238 239 int8 averageWeight; 240 if (settings.FindInt8("subpixel average weight", &averageWeight) 241 == B_OK) { 242 gSubpixelAverageWeight = averageWeight; 243 } 244 245 bool subpixelOrdering; 246 if (settings.FindBool("subpixel ordering", &subpixelOrdering) 247 == B_OK) { 248 gSubpixelOrderingRGB = subpixelOrdering; 249 } 250 251 for (int32 i = 0; i < kNumColors; i++) { 252 char colorName[12]; 253 snprintf(colorName, sizeof(colorName), "color%ld", 254 (int32)index_to_color_which(i)); 255 256 settings.FindInt32(colorName, (int32*)&fShared.colors[i]); 257 } 258 } 259 } 260 261 return B_OK; 262 } 263 264 265 status_t 266 DesktopSettingsPrivate::Save(uint32 mask) 267 { 268 BPath basePath; 269 status_t status = _GetPath(basePath); 270 if (status < B_OK) 271 return status; 272 273 if (mask & kWorkspacesSettings) { 274 BPath path(basePath); 275 if (path.Append("workspaces") == B_OK) { 276 BMessage settings('asws'); 277 settings.AddInt32("count", fWorkspacesCount); 278 279 for (int32 i = 0; i < kMaxWorkspaces; i++) { 280 settings.AddMessage("workspace", &fWorkspaceMessages[i]); 281 } 282 283 BFile file; 284 status = file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE 285 | B_READ_WRITE); 286 if (status == B_OK) { 287 status = settings.Flatten(&file, NULL); 288 } 289 } 290 } 291 292 if (mask & kFontSettings) { 293 BPath path(basePath); 294 if (path.Append("fonts") == B_OK) { 295 BMessage settings('asfn'); 296 297 settings.AddString("plain family", fPlainFont.Family()); 298 settings.AddString("plain style", fPlainFont.Style()); 299 settings.AddFloat("plain size", fPlainFont.Size()); 300 301 settings.AddString("bold family", fBoldFont.Family()); 302 settings.AddString("bold style", fBoldFont.Style()); 303 settings.AddFloat("bold size", fBoldFont.Size()); 304 305 settings.AddString("fixed family", fFixedFont.Family()); 306 settings.AddString("fixed style", fFixedFont.Style()); 307 settings.AddFloat("fixed size", fFixedFont.Size()); 308 309 settings.AddBool("hinting", gDefaultHinting); 310 311 BFile file; 312 status = file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE 313 | B_READ_WRITE); 314 if (status == B_OK) { 315 status = settings.Flatten(&file, NULL); 316 } 317 } 318 } 319 320 if (mask & kMouseSettings) { 321 BPath path(basePath); 322 if (path.Append("mouse") == B_OK) { 323 BMessage settings('asms'); 324 settings.AddInt32("mode", (int32)fMouseMode); 325 326 BFile file; 327 status = file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE 328 | B_READ_WRITE); 329 if (status == B_OK) { 330 status = settings.Flatten(&file, NULL); 331 } 332 } 333 } 334 335 if (mask & kDraggerSettings) { 336 BPath path(basePath); 337 if (path.Append("dragger") == B_OK) { 338 BMessage settings('asdg'); 339 settings.AddBool("show", fShowAllDraggers); 340 341 BFile file; 342 status = file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE 343 | B_READ_WRITE); 344 if (status == B_OK) { 345 status = settings.Flatten(&file, NULL); 346 } 347 } 348 } 349 350 if (mask & kAppearanceSettings) { 351 BPath path(basePath); 352 if (path.Append("appearance") == B_OK) { 353 BMessage settings('aslk'); 354 settings.AddFloat("font size", fMenuInfo.font_size); 355 settings.AddString("font family", fMenuInfo.f_family); 356 settings.AddString("font style", fMenuInfo.f_style); 357 settings.AddInt32("bg color", 358 (const int32&)fMenuInfo.background_color); 359 settings.AddInt32("separator", fMenuInfo.separator); 360 settings.AddBool("click to open", fMenuInfo.click_to_open); 361 settings.AddBool("triggers always shown", 362 fMenuInfo.triggers_always_shown); 363 364 settings.AddBool("subpixel antialiasing", gSubpixelAntialiasing); 365 settings.AddInt8("subpixel average weight", gSubpixelAverageWeight); 366 settings.AddBool("subpixel ordering", gSubpixelOrderingRGB); 367 368 for (int32 i = 0; i < kNumColors; i++) { 369 char colorName[12]; 370 snprintf(colorName, sizeof(colorName), "color%ld", 371 (int32)index_to_color_which(i)); 372 settings.AddInt32(colorName, (const int32&)fShared.colors[i]); 373 } 374 375 BFile file; 376 status = file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE 377 | B_READ_WRITE); 378 if (status == B_OK) { 379 status = settings.Flatten(&file, NULL); 380 } 381 } 382 } 383 384 return status; 385 } 386 387 388 void 389 DesktopSettingsPrivate::SetDefaultPlainFont(const ServerFont &font) 390 { 391 fPlainFont = font; 392 Save(kFontSettings); 393 } 394 395 396 const ServerFont & 397 DesktopSettingsPrivate::DefaultPlainFont() const 398 { 399 return fPlainFont; 400 } 401 402 403 void 404 DesktopSettingsPrivate::SetDefaultBoldFont(const ServerFont &font) 405 { 406 fBoldFont = font; 407 Save(kFontSettings); 408 } 409 410 411 const ServerFont & 412 DesktopSettingsPrivate::DefaultBoldFont() const 413 { 414 return fBoldFont; 415 } 416 417 418 void 419 DesktopSettingsPrivate::SetDefaultFixedFont(const ServerFont &font) 420 { 421 fFixedFont = font; 422 Save(kFontSettings); 423 } 424 425 426 const ServerFont & 427 DesktopSettingsPrivate::DefaultFixedFont() const 428 { 429 return fFixedFont; 430 } 431 432 433 void 434 DesktopSettingsPrivate::SetScrollBarInfo(const scroll_bar_info& info) 435 { 436 fScrollBarInfo = info; 437 Save(kAppearanceSettings); 438 } 439 440 441 const scroll_bar_info& 442 DesktopSettingsPrivate::ScrollBarInfo() const 443 { 444 return fScrollBarInfo; 445 } 446 447 448 void 449 DesktopSettingsPrivate::SetMenuInfo(const menu_info& info) 450 { 451 fMenuInfo = info; 452 // Also update the ui_color 453 SetUIColor(B_MENU_BACKGROUND_COLOR, info.background_color); 454 // SetUIColor already saves the settings 455 } 456 457 458 const menu_info& 459 DesktopSettingsPrivate::MenuInfo() const 460 { 461 return fMenuInfo; 462 } 463 464 465 void 466 DesktopSettingsPrivate::SetMouseMode(const mode_mouse mode) 467 { 468 fMouseMode = mode; 469 Save(kMouseSettings); 470 } 471 472 473 mode_mouse 474 DesktopSettingsPrivate::MouseMode() const 475 { 476 return fMouseMode; 477 } 478 479 480 bool 481 DesktopSettingsPrivate::FocusFollowsMouse() const 482 { 483 return MouseMode() != B_NORMAL_MOUSE; 484 } 485 486 487 void 488 DesktopSettingsPrivate::SetShowAllDraggers(bool show) 489 { 490 fShowAllDraggers = show; 491 Save(kDraggerSettings); 492 } 493 494 495 bool 496 DesktopSettingsPrivate::ShowAllDraggers() const 497 { 498 return fShowAllDraggers; 499 } 500 501 502 void 503 DesktopSettingsPrivate::SetWorkspacesCount(int32 number) 504 { 505 if (number < 1) 506 number = 1; 507 else if (number > kMaxWorkspaces) 508 number = kMaxWorkspaces; 509 510 fWorkspacesCount = number; 511 } 512 513 514 int32 515 DesktopSettingsPrivate::WorkspacesCount() const 516 { 517 return fWorkspacesCount; 518 } 519 520 521 void 522 DesktopSettingsPrivate::SetWorkspacesMessage(int32 index, BMessage& message) 523 { 524 if (index < 0 || index > kMaxWorkspaces) 525 return; 526 527 fWorkspaceMessages[index] = message; 528 } 529 530 531 const BMessage* 532 DesktopSettingsPrivate::WorkspacesMessage(int32 index) const 533 { 534 if (index < 0 || index > kMaxWorkspaces) 535 return NULL; 536 537 return &fWorkspaceMessages[index]; 538 } 539 540 541 void 542 DesktopSettingsPrivate::SetUIColor(color_which which, const rgb_color color) 543 { 544 // 545 int32 index = color_which_to_index(which); 546 if (index < 0 || index >= kNumColors) 547 return; 548 fShared.colors[index] = color; 549 // TODO: deprecate the background_color member of the menu_info struct, 550 // otherwise we have to keep this duplication... 551 if (which == B_MENU_BACKGROUND_COLOR) 552 fMenuInfo.background_color = color; 553 Save(kAppearanceSettings); 554 } 555 556 557 rgb_color 558 DesktopSettingsPrivate::UIColor(color_which which) const 559 { 560 static const rgb_color invalidColor = {0, 0, 0, 0}; 561 int32 index = color_which_to_index(which); 562 if (index < 0 || index >= kNumColors) 563 return invalidColor; 564 return fShared.colors[index]; 565 } 566 567 568 void 569 DesktopSettingsPrivate::SetSubpixelAntialiasing(bool subpix) 570 { 571 gSubpixelAntialiasing = subpix; 572 Save(kAppearanceSettings); 573 } 574 575 576 bool 577 DesktopSettingsPrivate::SubpixelAntialiasing() const 578 { 579 return gSubpixelAntialiasing; 580 } 581 582 583 void 584 DesktopSettingsPrivate::SetHinting(bool hinting) 585 { 586 gDefaultHinting = hinting; 587 Save(kFontSettings); 588 } 589 590 591 bool 592 DesktopSettingsPrivate::Hinting() const 593 { 594 return gDefaultHinting; 595 } 596 597 598 void 599 DesktopSettingsPrivate::SetSubpixelAverageWeight(uint8 averageWeight) 600 { 601 gSubpixelAverageWeight = averageWeight; 602 Save(kAppearanceSettings); 603 } 604 605 606 uint8 607 DesktopSettingsPrivate::SubpixelAverageWeight() const 608 { 609 return gSubpixelAverageWeight; 610 } 611 612 613 void 614 DesktopSettingsPrivate::SetSubpixelOrderingRegular(bool subpixelOrdering) 615 { 616 gSubpixelOrderingRGB = subpixelOrdering; 617 Save(kAppearanceSettings); 618 } 619 620 621 bool 622 DesktopSettingsPrivate::IsSubpixelOrderingRegular() const 623 { 624 return gSubpixelOrderingRGB; 625 } 626 627 // #pragma mark - read access 628 629 630 DesktopSettings::DesktopSettings(Desktop* desktop) 631 : 632 fSettings(desktop->fSettings) 633 { 634 #if DEBUG 635 if (!desktop->fWindowLock.IsWriteLocked() 636 && !desktop->fWindowLock.IsReadLocked()) 637 debugger("desktop not locked when trying to access settings"); 638 #endif 639 } 640 641 642 void 643 DesktopSettings::GetDefaultPlainFont(ServerFont &font) const 644 { 645 font = fSettings->DefaultPlainFont(); 646 } 647 648 649 void 650 DesktopSettings::GetDefaultBoldFont(ServerFont &font) const 651 { 652 font = fSettings->DefaultBoldFont(); 653 } 654 655 656 void 657 DesktopSettings::GetDefaultFixedFont(ServerFont &font) const 658 { 659 font = fSettings->DefaultFixedFont(); 660 } 661 662 663 void 664 DesktopSettings::GetScrollBarInfo(scroll_bar_info& info) const 665 { 666 info = fSettings->ScrollBarInfo(); 667 } 668 669 670 void 671 DesktopSettings::GetMenuInfo(menu_info& info) const 672 { 673 info = fSettings->MenuInfo(); 674 } 675 676 677 mode_mouse 678 DesktopSettings::MouseMode() const 679 { 680 return fSettings->MouseMode(); 681 } 682 683 684 bool 685 DesktopSettings::FocusFollowsMouse() const 686 { 687 return fSettings->FocusFollowsMouse(); 688 } 689 690 691 bool 692 DesktopSettings::ShowAllDraggers() const 693 { 694 return fSettings->ShowAllDraggers(); 695 } 696 697 698 int32 699 DesktopSettings::WorkspacesCount() const 700 { 701 return fSettings->WorkspacesCount(); 702 } 703 704 705 const BMessage* 706 DesktopSettings::WorkspacesMessage(int32 index) const 707 { 708 return fSettings->WorkspacesMessage(index); 709 } 710 711 712 rgb_color 713 DesktopSettings::UIColor(color_which which) const 714 { 715 return fSettings->UIColor(which); 716 } 717 718 719 bool 720 DesktopSettings::SubpixelAntialiasing() const 721 { 722 return fSettings->SubpixelAntialiasing(); 723 } 724 725 726 bool 727 DesktopSettings::Hinting() const 728 { 729 return fSettings->Hinting(); 730 } 731 732 733 uint8 734 DesktopSettings::SubpixelAverageWeight() const 735 { 736 return fSettings->SubpixelAverageWeight(); 737 } 738 739 740 bool 741 DesktopSettings::IsSubpixelOrderingRegular() const 742 { 743 // True corresponds to RGB, false means BGR 744 return fSettings->IsSubpixelOrderingRegular(); 745 } 746 747 // #pragma mark - write access 748 749 750 LockedDesktopSettings::LockedDesktopSettings(Desktop* desktop) 751 : DesktopSettings(desktop), 752 fDesktop(desktop) 753 { 754 #if DEBUG 755 if (desktop->fWindowLock.IsReadLocked()) 756 debugger("desktop read locked when trying to change settings"); 757 #endif 758 759 fDesktop->LockAllWindows(); 760 } 761 762 763 LockedDesktopSettings::~LockedDesktopSettings() 764 { 765 fDesktop->UnlockAllWindows(); 766 } 767 768 769 void 770 LockedDesktopSettings::SetDefaultPlainFont(const ServerFont &font) 771 { 772 fSettings->SetDefaultPlainFont(font); 773 } 774 775 776 void 777 LockedDesktopSettings::SetDefaultBoldFont(const ServerFont &font) 778 { 779 fSettings->SetDefaultBoldFont(font); 780 } 781 782 783 void 784 LockedDesktopSettings::SetDefaultFixedFont(const ServerFont &font) 785 { 786 fSettings->SetDefaultFixedFont(font); 787 } 788 789 790 void 791 LockedDesktopSettings::SetScrollBarInfo(const scroll_bar_info& info) 792 { 793 fSettings->SetScrollBarInfo(info); 794 } 795 796 797 void 798 LockedDesktopSettings::SetMenuInfo(const menu_info& info) 799 { 800 fSettings->SetMenuInfo(info); 801 } 802 803 804 void 805 LockedDesktopSettings::SetMouseMode(const mode_mouse mode) 806 { 807 fSettings->SetMouseMode(mode); 808 } 809 810 811 void 812 LockedDesktopSettings::SetShowAllDraggers(bool show) 813 { 814 fSettings->SetShowAllDraggers(show); 815 } 816 817 818 void 819 LockedDesktopSettings::SetUIColor(color_which which, const rgb_color color) 820 { 821 fSettings->SetUIColor(which, color); 822 } 823 824 825 void 826 LockedDesktopSettings::SetSubpixelAntialiasing(bool subpix) 827 { 828 fSettings->SetSubpixelAntialiasing(subpix); 829 } 830 831 832 void 833 LockedDesktopSettings::SetHinting(bool hinting) 834 { 835 fSettings->SetHinting(hinting); 836 } 837 838 839 void 840 LockedDesktopSettings::SetSubpixelAverageWeight(uint8 averageWeight) 841 { 842 fSettings->SetSubpixelAverageWeight(averageWeight); 843 } 844 845 void 846 LockedDesktopSettings::SetSubpixelOrderingRegular(bool subpixelOrdering) 847 { 848 fSettings->SetSubpixelOrderingRegular(subpixelOrdering); 849 } 850 851