1 /* 2 * Copyright 2001-2008, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Caz <turok2@currantbun.com> 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 /*! Global functions and variables for the Interface Kit */ 12 13 #include <InterfacePrivate.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <Font.h> 20 #include <InterfaceDefs.h> 21 #include <Menu.h> 22 #include <Roster.h> 23 #include <ScrollBar.h> 24 #include <Screen.h> 25 #include <String.h> 26 #include <TextView.h> 27 28 #include <ApplicationPrivate.h> 29 #include <AppServerLink.h> 30 #include <ColorConversion.h> 31 #include <DefaultColors.h> 32 #include <InputServerTypes.h> 33 #include <input_globals.h> 34 #include <pr_server.h> 35 #include <ServerProtocol.h> 36 #include <ServerReadOnlyMemory.h> 37 #include <truncate_string.h> 38 #include <utf8_functions.h> 39 #include <WidthBuffer.h> 40 #include <WindowInfo.h> 41 42 43 // Private definitions not placed in public headers 44 void _init_global_fonts_(); 45 extern "C" status_t _fini_interface_kit_(); 46 47 using namespace BPrivate; 48 49 // some other weird struct exported by BeOS, it's not initialized, though 50 struct general_ui_info { 51 rgb_color background_color; 52 rgb_color mark_color; 53 rgb_color highlight_color; 54 bool color_frame; 55 rgb_color window_frame_color; 56 }; 57 58 struct general_ui_info general_info; 59 60 menu_info *_menu_info_ptr_; 61 62 extern "C" const char B_NOTIFICATION_SENDER[] = "be:sender"; 63 64 static const rgb_color _kDefaultColors[kNumColors] = { 65 {216, 216, 216, 255}, // B_PANEL_BACKGROUND_COLOR 66 {216, 216, 216, 255}, // B_MENU_BACKGROUND_COLOR 67 {255, 203, 0, 255}, // B_WINDOW_TAB_COLOR 68 {0, 0, 229, 255}, // B_KEYBOARD_NAVIGATION_COLOR 69 {51, 102, 152, 255}, // B_DESKTOP_COLOR 70 {153, 153, 153, 255}, // B_MENU_SELECTED_BACKGROUND_COLOR 71 {0, 0, 0, 255}, // B_MENU_ITEM_TEXT_COLOR 72 {0, 0, 0, 255}, // B_MENU_SELECTED_ITEM_TEXT_COLOR 73 {0, 0, 0, 255}, // B_MENU_SELECTED_BORDER_COLOR 74 {0, 0, 0, 255}, // B_PANEL_TEXT_COLOR 75 {255, 255, 255, 255}, // B_DOCUMENT_BACKGROUND_COLOR 76 {0, 0, 0, 255}, // B_DOCUMENT_TEXT_COLOR 77 {245, 245, 245, 255}, // B_CONTROL_BACKGROUND_COLOR 78 {0, 0, 0, 255}, // B_CONTROL_TEXT_COLOR 79 {0, 0, 0, 255}, // B_CONTROL_BORDER_COLOR 80 {102, 152, 203, 255}, // B_CONTROL_HIGHLIGHT_COLOR 81 {0, 0, 0, 255}, // B_NAVIGATION_PULSE_COLOR 82 {255, 255, 255, 255}, // B_SHINE_COLOR 83 {0, 0, 0, 255}, // B_SHADOW_COLOR 84 {255, 255, 0, 255}, // B_TOOLTIP_BACKGROUND_COLOR 85 {0, 0, 0, 255}, // B_TOOLTIP_TEXT_COLOR 86 {0, 0, 0, 255}, // B_WINDOW_TEXT_COLOR 87 {232, 232, 232, 255}, // B_WINDOW_INACTIVE_TAB_COLOR 88 {80, 80, 80, 255}, // B_WINDOW_INACTIVE_TEXT_COLOR 89 // 100... 90 {0, 255, 0, 255}, // B_SUCCESS_COLOR 91 {255, 0, 0, 255}, // B_FAILURE_COLOR 92 {} 93 }; 94 const rgb_color* BPrivate::kDefaultColors = &_kDefaultColors[0]; 95 96 97 namespace BPrivate { 98 99 /*! 100 Fills the \a width, \a height, and \a colorSpace parameters according 101 to the window screen's mode. 102 Returns \c true if the mode is known. 103 */ 104 bool 105 get_mode_parameter(uint32 mode, int32& width, int32& height, uint32& colorSpace) 106 { 107 switch (mode) { 108 case B_8_BIT_640x480: 109 case B_8_BIT_800x600: 110 case B_8_BIT_1024x768: 111 case B_8_BIT_1152x900: 112 case B_8_BIT_1280x1024: 113 case B_8_BIT_1600x1200: 114 colorSpace = B_CMAP8; 115 break; 116 117 case B_15_BIT_640x480: 118 case B_15_BIT_800x600: 119 case B_15_BIT_1024x768: 120 case B_15_BIT_1152x900: 121 case B_15_BIT_1280x1024: 122 case B_15_BIT_1600x1200: 123 colorSpace = B_RGB15; 124 break; 125 126 case B_16_BIT_640x480: 127 case B_16_BIT_800x600: 128 case B_16_BIT_1024x768: 129 case B_16_BIT_1152x900: 130 case B_16_BIT_1280x1024: 131 case B_16_BIT_1600x1200: 132 colorSpace = B_RGB16; 133 break; 134 135 case B_32_BIT_640x480: 136 case B_32_BIT_800x600: 137 case B_32_BIT_1024x768: 138 case B_32_BIT_1152x900: 139 case B_32_BIT_1280x1024: 140 case B_32_BIT_1600x1200: 141 colorSpace = B_RGB32; 142 break; 143 144 default: 145 return false; 146 } 147 148 switch (mode) { 149 case B_8_BIT_640x480: 150 case B_15_BIT_640x480: 151 case B_16_BIT_640x480: 152 case B_32_BIT_640x480: 153 width = 640; height = 480; 154 break; 155 156 case B_8_BIT_800x600: 157 case B_15_BIT_800x600: 158 case B_16_BIT_800x600: 159 case B_32_BIT_800x600: 160 width = 800; height = 600; 161 break; 162 163 case B_8_BIT_1024x768: 164 case B_15_BIT_1024x768: 165 case B_16_BIT_1024x768: 166 case B_32_BIT_1024x768: 167 width = 1024; height = 768; 168 break; 169 170 case B_8_BIT_1152x900: 171 case B_15_BIT_1152x900: 172 case B_16_BIT_1152x900: 173 case B_32_BIT_1152x900: 174 width = 1152; height = 900; 175 break; 176 177 case B_8_BIT_1280x1024: 178 case B_15_BIT_1280x1024: 179 case B_16_BIT_1280x1024: 180 case B_32_BIT_1280x1024: 181 width = 1280; height = 1024; 182 break; 183 184 case B_8_BIT_1600x1200: 185 case B_15_BIT_1600x1200: 186 case B_16_BIT_1600x1200: 187 case B_32_BIT_1600x1200: 188 width = 1600; height = 1200; 189 break; 190 } 191 192 return true; 193 } 194 195 } // namespace BPrivate 196 197 198 void 199 set_subpixel_antialiasing(bool subpix) 200 { 201 BPrivate::AppServerLink link; 202 203 link.StartMessage(AS_SET_SUBPIXEL_ANTIALIASING); 204 link.Attach<bool>(subpix); 205 link.Flush(); 206 } 207 208 209 status_t 210 get_subpixel_antialiasing(bool* subpix) 211 { 212 BPrivate::AppServerLink link; 213 214 link.StartMessage(AS_GET_SUBPIXEL_ANTIALIASING); 215 int32 status = B_ERROR; 216 if (link.FlushWithReply(status) != B_OK || status < B_OK) 217 return status; 218 link.Read<bool>(subpix); 219 return B_OK; 220 } 221 222 223 void 224 set_hinting(bool hinting) 225 { 226 BPrivate::AppServerLink link; 227 228 link.StartMessage(AS_SET_HINTING); 229 link.Attach<bool>(hinting); 230 link.Flush(); 231 } 232 233 234 status_t 235 get_hinting(bool* hinting) 236 { 237 BPrivate::AppServerLink link; 238 239 link.StartMessage(AS_GET_HINTING); 240 int32 status = B_ERROR; 241 if (link.FlushWithReply(status) != B_OK || status < B_OK) 242 return status; 243 link.Read<bool>(hinting); 244 return B_OK; 245 } 246 247 248 void 249 set_average_weight(uint8 averageWeight) 250 { 251 BPrivate::AppServerLink link; 252 253 link.StartMessage(AS_SET_SUBPIXEL_AVERAGE_WEIGHT); 254 link.Attach<uint8>(averageWeight); 255 link.Flush(); 256 } 257 258 259 status_t 260 get_average_weight(uint8* averageWeight) 261 { 262 BPrivate::AppServerLink link; 263 264 link.StartMessage(AS_GET_SUBPIXEL_AVERAGE_WEIGHT); 265 int32 status = B_ERROR; 266 if (link.FlushWithReply(status) != B_OK || status < B_OK) 267 return status; 268 link.Read<uint8>(averageWeight); 269 return B_OK; 270 } 271 272 273 void 274 set_is_subpixel_ordering_regular(bool subpixelOrdering) 275 { 276 BPrivate::AppServerLink link; 277 278 link.StartMessage(AS_SET_SUBPIXEL_ORDERING); 279 link.Attach<bool>(subpixelOrdering); 280 link.Flush(); 281 } 282 283 284 status_t 285 get_is_subpixel_ordering_regular(bool* subpixelOrdering) 286 { 287 288 BPrivate::AppServerLink link; 289 290 link.StartMessage(AS_GET_SUBPIXEL_ORDERING); 291 int32 status = B_ERROR; 292 if (link.FlushWithReply(status) != B_OK || status < B_OK) 293 return status; 294 link.Read<bool>(subpixelOrdering); 295 return B_OK; 296 } 297 298 299 const color_map * 300 system_colors() 301 { 302 return BScreen(B_MAIN_SCREEN_ID).ColorMap(); 303 } 304 305 306 status_t 307 set_screen_space(int32 index, uint32 space, bool stick) 308 { 309 int32 width; 310 int32 height; 311 uint32 depth; 312 if (!BPrivate::get_mode_parameter(space, width, height, depth)) 313 return B_BAD_VALUE; 314 315 BScreen screen(B_MAIN_SCREEN_ID); 316 display_mode mode; 317 318 // TODO: What about refresh rate ? 319 // currently we get it from the current video mode, but 320 // this might be not so wise. 321 status_t status = screen.GetMode(index, &mode); 322 if (status < B_OK) 323 return status; 324 325 mode.virtual_width = width; 326 mode.virtual_height = height; 327 mode.space = depth; 328 329 return screen.SetMode(index, &mode, stick); 330 } 331 332 333 status_t 334 get_scroll_bar_info(scroll_bar_info *info) 335 { 336 if (info == NULL) 337 return B_BAD_VALUE; 338 339 BPrivate::AppServerLink link; 340 link.StartMessage(AS_GET_SCROLLBAR_INFO); 341 342 int32 code; 343 if (link.FlushWithReply(code) == B_OK 344 && code == B_OK) { 345 link.Read<scroll_bar_info>(info); 346 return B_OK; 347 } 348 349 return B_ERROR; 350 } 351 352 353 status_t 354 set_scroll_bar_info(scroll_bar_info *info) 355 { 356 if (info == NULL) 357 return B_BAD_VALUE; 358 359 BPrivate::AppServerLink link; 360 int32 code; 361 362 link.StartMessage(AS_SET_SCROLLBAR_INFO); 363 link.Attach<scroll_bar_info>(*info); 364 365 if (link.FlushWithReply(code) == B_OK 366 && code == B_OK) 367 return B_OK; 368 369 return B_ERROR; 370 } 371 372 373 status_t 374 get_mouse_type(int32 *type) 375 { 376 BMessage command(IS_GET_MOUSE_TYPE); 377 BMessage reply; 378 379 _control_input_server_(&command, &reply); 380 381 if (reply.FindInt32("mouse_type", type) != B_OK) 382 return B_ERROR; 383 384 return B_OK; 385 } 386 387 388 status_t 389 set_mouse_type(int32 type) 390 { 391 BMessage command(IS_SET_MOUSE_TYPE); 392 BMessage reply; 393 394 command.AddInt32("mouse_type", type); 395 return _control_input_server_(&command, &reply); 396 } 397 398 399 status_t 400 get_mouse_map(mouse_map *map) 401 { 402 BMessage command(IS_GET_MOUSE_MAP); 403 BMessage reply; 404 const void *data = 0; 405 ssize_t count; 406 407 _control_input_server_(&command, &reply); 408 409 if (reply.FindData("mousemap", B_RAW_TYPE, &data, &count) != B_OK) 410 return B_ERROR; 411 412 memcpy(map, data, count); 413 414 return B_OK; 415 } 416 417 418 status_t 419 set_mouse_map(mouse_map *map) 420 { 421 BMessage command(IS_SET_MOUSE_MAP); 422 BMessage reply; 423 424 command.AddData("mousemap", B_RAW_TYPE, map, sizeof(mouse_map)); 425 return _control_input_server_(&command, &reply); 426 } 427 428 429 status_t 430 get_click_speed(bigtime_t *speed) 431 { 432 BMessage command(IS_GET_CLICK_SPEED); 433 BMessage reply; 434 435 _control_input_server_(&command, &reply); 436 437 if (reply.FindInt64("speed", speed) != B_OK) 438 *speed = 500000; 439 440 return B_OK; 441 } 442 443 444 status_t 445 set_click_speed(bigtime_t speed) 446 { 447 BMessage command(IS_SET_CLICK_SPEED); 448 BMessage reply; 449 command.AddInt64("speed", speed); 450 return _control_input_server_(&command, &reply); 451 } 452 453 454 status_t 455 get_mouse_speed(int32 *speed) 456 { 457 BMessage command(IS_GET_MOUSE_SPEED); 458 BMessage reply; 459 460 _control_input_server_(&command, &reply); 461 462 if (reply.FindInt32("speed", speed) != B_OK) 463 *speed = 65536; 464 465 return B_OK; 466 } 467 468 469 status_t 470 set_mouse_speed(int32 speed) 471 { 472 BMessage command(IS_SET_MOUSE_SPEED); 473 BMessage reply; 474 command.AddInt32("speed", speed); 475 return _control_input_server_(&command, &reply); 476 } 477 478 479 status_t 480 get_mouse_acceleration(int32 *speed) 481 { 482 BMessage command(IS_GET_MOUSE_ACCELERATION); 483 BMessage reply; 484 485 _control_input_server_(&command, &reply); 486 487 if (reply.FindInt32("speed", speed) != B_OK) 488 *speed = 65536; 489 490 return B_OK; 491 } 492 493 494 status_t 495 set_mouse_acceleration(int32 speed) 496 { 497 BMessage command(IS_SET_MOUSE_ACCELERATION); 498 BMessage reply; 499 command.AddInt32("speed", speed); 500 return _control_input_server_(&command, &reply); 501 } 502 503 504 status_t 505 get_key_repeat_rate(int32 *rate) 506 { 507 BMessage command(IS_GET_KEY_REPEAT_RATE); 508 BMessage reply; 509 510 _control_input_server_(&command, &reply); 511 512 if (reply.FindInt32("rate", rate) != B_OK) 513 *rate = 250000; 514 515 return B_OK; 516 } 517 518 519 status_t 520 set_key_repeat_rate(int32 rate) 521 { 522 BMessage command(IS_SET_KEY_REPEAT_RATE); 523 BMessage reply; 524 command.AddInt32("rate", rate); 525 return _control_input_server_(&command, &reply); 526 } 527 528 529 status_t 530 get_key_repeat_delay(bigtime_t *delay) 531 { 532 BMessage command(IS_GET_KEY_REPEAT_DELAY); 533 BMessage reply; 534 535 _control_input_server_(&command, &reply); 536 537 if (reply.FindInt64("delay", delay) != B_OK) 538 *delay = 200; 539 540 return B_OK; 541 } 542 543 544 status_t 545 set_key_repeat_delay(bigtime_t delay) 546 { 547 BMessage command(IS_SET_KEY_REPEAT_DELAY); 548 BMessage reply; 549 command.AddInt64("delay", delay); 550 return _control_input_server_(&command, &reply); 551 } 552 553 554 uint32 555 modifiers() 556 { 557 BMessage command(IS_GET_MODIFIERS); 558 BMessage reply; 559 int32 err, modifier; 560 561 _control_input_server_(&command, &reply); 562 563 if (reply.FindInt32("status", &err) != B_OK) 564 return 0; 565 566 if (reply.FindInt32("modifiers", &modifier) != B_OK) 567 return 0; 568 569 return modifier; 570 } 571 572 573 status_t 574 get_key_info(key_info *info) 575 { 576 BMessage command(IS_GET_KEY_INFO); 577 BMessage reply; 578 const void *data = 0; 579 int32 err; 580 ssize_t count; 581 582 _control_input_server_(&command, &reply); 583 584 if (reply.FindInt32("status", &err) != B_OK) 585 return B_ERROR; 586 587 if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK) 588 return B_ERROR; 589 590 memcpy(info, data, count); 591 return B_OK; 592 } 593 594 595 void 596 get_key_map(key_map **map, char **key_buffer) 597 { 598 _get_key_map(map, key_buffer, NULL); 599 } 600 601 602 void 603 _get_key_map(key_map **map, char **key_buffer, ssize_t *key_buffer_size) 604 { 605 BMessage command(IS_GET_KEY_MAP); 606 BMessage reply; 607 ssize_t map_count, key_count; 608 const void *map_array = 0, *key_array = 0; 609 if (key_buffer_size == NULL) 610 key_buffer_size = &key_count; 611 612 _control_input_server_(&command, &reply); 613 614 if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) { 615 *map = 0; *key_buffer = 0; 616 return; 617 } 618 619 if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, key_buffer_size) != B_OK) { 620 *map = 0; *key_buffer = 0; 621 return; 622 } 623 624 *map = (key_map *)malloc(map_count); 625 memcpy(*map, map_array, map_count); 626 *key_buffer = (char *)malloc(*key_buffer_size); 627 memcpy(*key_buffer, key_array, *key_buffer_size); 628 } 629 630 631 status_t 632 get_keyboard_id(uint16 *id) 633 { 634 BMessage command(IS_GET_KEYBOARD_ID); 635 BMessage reply; 636 uint16 kid; 637 638 _control_input_server_(&command, &reply); 639 640 reply.FindInt16("id", (int16 *)&kid); 641 *id = kid; 642 643 return B_OK; 644 } 645 646 647 void 648 set_modifier_key(uint32 modifier, uint32 key) 649 { 650 BMessage command(IS_SET_MODIFIER_KEY); 651 BMessage reply; 652 653 command.AddInt32("modifier", modifier); 654 command.AddInt32("key", key); 655 _control_input_server_(&command, &reply); 656 } 657 658 659 void 660 set_keyboard_locks(uint32 modifiers) 661 { 662 BMessage command(IS_SET_KEYBOARD_LOCKS); 663 BMessage reply; 664 665 command.AddInt32("locks", modifiers); 666 _control_input_server_(&command, &reply); 667 } 668 669 670 status_t 671 _restore_key_map_() 672 { 673 BMessage message(IS_RESTORE_KEY_MAP); 674 BMessage reply; 675 676 return _control_input_server_(&message, &reply); 677 } 678 679 680 rgb_color 681 keyboard_navigation_color() 682 { 683 // Queries the app_server 684 return ui_color(B_KEYBOARD_NAVIGATION_COLOR); 685 } 686 687 688 int32 689 count_workspaces() 690 { 691 int32 count = 1; 692 693 BPrivate::AppServerLink link; 694 link.StartMessage(AS_COUNT_WORKSPACES); 695 696 status_t status; 697 if (link.FlushWithReply(status) == B_OK && status == B_OK) 698 link.Read<int32>(&count); 699 700 return count; 701 } 702 703 704 void 705 set_workspace_count(int32 count) 706 { 707 BPrivate::AppServerLink link; 708 link.StartMessage(AS_SET_WORKSPACE_COUNT); 709 link.Attach<int32>(count); 710 link.Flush(); 711 } 712 713 714 int32 715 current_workspace() 716 { 717 int32 index = 0; 718 719 BPrivate::AppServerLink link; 720 link.StartMessage(AS_CURRENT_WORKSPACE); 721 722 int32 status; 723 if (link.FlushWithReply(status) == B_OK && status == B_OK) 724 link.Read<int32>(&index); 725 726 return index; 727 } 728 729 730 void 731 activate_workspace(int32 workspace) 732 { 733 BPrivate::AppServerLink link; 734 link.StartMessage(AS_ACTIVATE_WORKSPACE); 735 link.Attach<int32>(workspace); 736 link.Flush(); 737 } 738 739 740 bigtime_t 741 idle_time() 742 { 743 bigtime_t idletime = 0; 744 745 BPrivate::AppServerLink link; 746 link.StartMessage(AS_IDLE_TIME); 747 748 int32 code; 749 if (link.FlushWithReply(code) == B_OK && code == B_OK) 750 link.Read<int64>(&idletime); 751 752 return idletime; 753 } 754 755 756 void 757 run_select_printer_panel() 758 { 759 if (be_roster == NULL) 760 return; 761 762 // Launches the Printer prefs app via the Roster 763 be_roster->Launch(PRNT_SIGNATURE_TYPE); 764 } 765 766 767 void 768 run_add_printer_panel() 769 { 770 // Launches the Printer prefs app via the Roster and asks it to 771 // add a printer 772 run_select_printer_panel(); 773 774 BMessenger printerPanelMessenger(PRNT_SIGNATURE_TYPE); 775 printerPanelMessenger.SendMessage(PRINTERS_ADD_PRINTER); 776 } 777 778 779 void 780 run_be_about() 781 { 782 if (be_roster != NULL) 783 be_roster->Launch("application/x-vnd.Haiku-About"); 784 } 785 786 787 void 788 set_focus_follows_mouse(bool follow) 789 { 790 // obviously deprecated API 791 set_mouse_mode(B_WARP_MOUSE); 792 } 793 794 795 bool 796 focus_follows_mouse() 797 { 798 return mouse_mode() != B_NORMAL_MOUSE; 799 } 800 801 802 void 803 set_mouse_mode(mode_mouse mode) 804 { 805 BPrivate::AppServerLink link; 806 link.StartMessage(AS_SET_MOUSE_MODE); 807 link.Attach<mode_mouse>(mode); 808 link.Flush(); 809 } 810 811 812 mode_mouse 813 mouse_mode() 814 { 815 // Gets the focus-follows-mouse style, such as normal, B_WARP_MOUSE, etc. 816 mode_mouse mode = B_NORMAL_MOUSE; 817 818 BPrivate::AppServerLink link; 819 link.StartMessage(AS_GET_MOUSE_MODE); 820 821 int32 code; 822 if (link.FlushWithReply(code) == B_OK && code == B_OK) 823 link.Read<mode_mouse>(&mode); 824 825 return mode; 826 } 827 828 829 rgb_color 830 ui_color(color_which which) 831 { 832 int32 index = color_which_to_index(which); 833 if (index < 0 || index >= kNumColors) { 834 fprintf(stderr, "ui_color(): unknown color_which %d\n", which); 835 return make_color(0, 0, 0); 836 } 837 838 if (be_app) { 839 server_read_only_memory* shared = BApplication::Private::ServerReadOnlyMemory(); 840 return shared->colors[index]; 841 } 842 843 return kDefaultColors[index]; 844 } 845 846 847 void 848 set_ui_color(const color_which &which, const rgb_color &color) 849 { 850 int32 index = color_which_to_index(which); 851 if (index < 0 || index >= kNumColors) { 852 fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which); 853 return; 854 } 855 856 BPrivate::AppServerLink link; 857 link.StartMessage(AS_SET_UI_COLOR); 858 link.Attach<color_which>(which); 859 link.Attach<rgb_color>(color); 860 link.Flush(); 861 } 862 863 864 rgb_color 865 tint_color(rgb_color color, float tint) 866 { 867 rgb_color result; 868 869 #define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint)) 870 #define DARKEN(x) ((uint8)(x * (2 - tint))) 871 872 if (tint < 1.0f) { 873 result.red = LIGHTEN(color.red); 874 result.green = LIGHTEN(color.green); 875 result.blue = LIGHTEN(color.blue); 876 result.alpha = color.alpha; 877 } else { 878 result.red = DARKEN(color.red); 879 result.green = DARKEN(color.green); 880 result.blue = DARKEN(color.blue); 881 result.alpha = color.alpha; 882 } 883 884 #undef LIGHTEN 885 #undef DARKEN 886 887 return result; 888 } 889 890 891 rgb_color shift_color(rgb_color color, float shift); 892 893 rgb_color 894 shift_color(rgb_color color, float shift) 895 { 896 return tint_color(color, shift); 897 } 898 899 900 extern "C" status_t 901 _init_interface_kit_() 902 { 903 status_t status = BPrivate::PaletteConverter::InitializeDefault(true); 904 if (status < B_OK) 905 return status; 906 907 sem_id widthSem = create_sem(0, "BTextView WidthBuffer Sem"); 908 if (widthSem < 0) 909 return widthSem; 910 BTextView::sWidthSem = widthSem; 911 BTextView::sWidthAtom = 0; 912 BTextView::sWidths = new _BWidthBuffer_; 913 914 _init_global_fonts_(); 915 916 _menu_info_ptr_ = &BMenu::sMenuInfo; 917 918 status = get_menu_info(&BMenu::sMenuInfo); 919 920 general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR); 921 general_info.mark_color.set_to(0, 0, 0); 922 general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR); 923 general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR); 924 general_info.color_frame = true; 925 926 // TODO: fill the other static members 927 928 return status; 929 } 930 931 932 extern "C" status_t 933 _fini_interface_kit_() 934 { 935 //TODO: Implement ? 936 937 return B_OK; 938 } 939 940 941 // #pragma mark - 942 943 944 /*! 945 \brief private function used by Deskbar to set window decor 946 Note, we don't have to be compatible here, and could just change 947 the Deskbar not to use this anymore 948 \param theme The theme to choose 949 950 - \c 0: BeOS 951 - \c 1: AmigaOS 952 - \c 2: Win95 953 - \c 3: MacOS 954 */ 955 void 956 __set_window_decor(int32 theme) 957 { 958 BPrivate::AppServerLink link; 959 link.StartMessage(AS_R5_SET_DECORATOR); 960 link.Attach<int32>(theme); 961 link.Flush(); 962 } 963 964 965 namespace BPrivate { 966 967 /*! 968 \brief queries the server for the number of available decorators 969 \return the number of available decorators 970 */ 971 int32 972 count_decorators(void) 973 { 974 BPrivate::AppServerLink link; 975 link.StartMessage(AS_COUNT_DECORATORS); 976 977 int32 code; 978 int32 count = -1; 979 if (link.FlushWithReply(code) == B_OK && code == B_OK) 980 link.Read<int32>(&count); 981 982 return count; 983 } 984 985 /*! 986 \brief queries the server for the index of the current decorators 987 \return the current decorator's index 988 989 If for some bizarre reason this function fails, it returns -1 990 */ 991 int32 992 get_decorator(void) 993 { 994 BPrivate::AppServerLink link; 995 link.StartMessage(AS_GET_DECORATOR); 996 997 int32 code; 998 int32 index = -1; 999 if (link.FlushWithReply(code) == B_OK && code == B_OK) 1000 link.Read<int32>(&index); 1001 1002 return index; 1003 } 1004 1005 1006 /*! 1007 \brief queries the server for the name of the decorator with a certain index 1008 \param index The index of the decorator to get the name for 1009 \param name BString to receive the name of the decorator 1010 \return B_OK if successful, B_ERROR if not 1011 */ 1012 status_t 1013 get_decorator_name(const int32 &index, BString &name) 1014 { 1015 BPrivate::AppServerLink link; 1016 link.StartMessage(AS_GET_DECORATOR_NAME); 1017 link.Attach<int32>(index); 1018 1019 int32 code; 1020 if (link.FlushWithReply(code) == B_OK && code == B_OK) { 1021 char *string; 1022 if (link.ReadString(&string) == B_OK) { 1023 name = string; 1024 free(string); 1025 return B_OK; 1026 } 1027 } 1028 1029 return B_ERROR; 1030 } 1031 1032 /*! 1033 \brief asks the server to draw a decorator preview into a BBitmap 1034 \param index The index of the decorator to get the name for 1035 \param bitmap BBitmap to receive the preview 1036 \return B_OK if successful, B_ERROR if not. 1037 1038 This is currently unimplemented. 1039 */ 1040 status_t 1041 get_decorator_preview(const int32 &index, BBitmap *bitmap) 1042 { 1043 // TODO: implement get_decorator_preview 1044 return B_ERROR; 1045 } 1046 1047 1048 /*! 1049 \brief Private function which sets the window decorator for the system. 1050 \param index Index of the decorator to set 1051 1052 If the index is invalid, this function and the server do nothing 1053 */ 1054 status_t 1055 set_decorator(const int32 &index) 1056 { 1057 if (index < 0) 1058 return B_BAD_VALUE; 1059 1060 BPrivate::AppServerLink link; 1061 1062 link.StartMessage(AS_SET_DECORATOR); 1063 link.Attach<int32>(index); 1064 link.Flush(); 1065 1066 return B_OK; 1067 } 1068 1069 1070 status_t 1071 get_application_order(int32 workspace, team_id** _applications, 1072 int32* _count) 1073 { 1074 BPrivate::AppServerLink link; 1075 1076 link.StartMessage(AS_GET_APPLICATION_ORDER); 1077 link.Attach<int32>(workspace); 1078 1079 int32 code; 1080 status_t status = link.FlushWithReply(code); 1081 if (status != B_OK) 1082 return status; 1083 if (code != B_OK) 1084 return code; 1085 1086 int32 count; 1087 link.Read<int32>(&count); 1088 1089 *_applications = (team_id*)malloc(count * sizeof(team_id)); 1090 if (*_applications == NULL) 1091 return B_NO_MEMORY; 1092 1093 link.Read(*_applications, count * sizeof(team_id)); 1094 *_count = count; 1095 return B_OK; 1096 } 1097 1098 1099 status_t 1100 get_window_order(int32 workspace, int32** _tokens, int32* _count) 1101 { 1102 BPrivate::AppServerLink link; 1103 1104 link.StartMessage(AS_GET_WINDOW_ORDER); 1105 link.Attach<int32>(workspace); 1106 1107 int32 code; 1108 status_t status = link.FlushWithReply(code); 1109 if (status != B_OK) 1110 return status; 1111 if (code != B_OK) 1112 return code; 1113 1114 int32 count; 1115 link.Read<int32>(&count); 1116 1117 *_tokens = (int32*)malloc(count * sizeof(int32)); 1118 if (*_tokens == NULL) 1119 return B_NO_MEMORY; 1120 1121 link.Read(*_tokens, count * sizeof(int32)); 1122 *_count = count; 1123 return B_OK; 1124 } 1125 1126 1127 } // namespace BPrivate 1128 1129 // These methods were marked with "Danger, will Robinson!" in 1130 // the OpenTracker source, so we might not want to be compatible 1131 // here. 1132 // In any way, we would need to update Deskbar to use our 1133 // replacements, so we could as well just implement them... 1134 1135 void 1136 do_window_action(int32 windowToken, int32 action, BRect zoomRect, bool zoom) 1137 { 1138 BPrivate::AppServerLink link; 1139 1140 link.StartMessage(AS_WINDOW_ACTION); 1141 link.Attach<int32>(windowToken); 1142 link.Attach<int32>(action); 1143 // we don't have any zooming effect 1144 1145 link.Flush(); 1146 } 1147 1148 1149 client_window_info* 1150 get_window_info(int32 serverToken) 1151 { 1152 BPrivate::AppServerLink link; 1153 1154 link.StartMessage(AS_GET_WINDOW_INFO); 1155 link.Attach<int32>(serverToken); 1156 1157 int32 code; 1158 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1159 return NULL; 1160 1161 int32 size; 1162 link.Read<int32>(&size); 1163 1164 client_window_info* info = (client_window_info*)malloc(size); 1165 if (info == NULL) 1166 return NULL; 1167 1168 link.Read(info, size); 1169 return info; 1170 } 1171 1172 1173 int32* 1174 get_token_list(team_id team, int32* _count) 1175 { 1176 BPrivate::AppServerLink link; 1177 1178 link.StartMessage(AS_GET_WINDOW_LIST); 1179 link.Attach<team_id>(team); 1180 1181 int32 code; 1182 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1183 return NULL; 1184 1185 int32 count; 1186 link.Read<int32>(&count); 1187 1188 int32* tokens = (int32*)malloc(count * sizeof(int32)); 1189 if (tokens == NULL) 1190 return NULL; 1191 1192 link.Read(tokens, count * sizeof(int32)); 1193 *_count = count; 1194 return tokens; 1195 } 1196 1197 1198 void 1199 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom) 1200 { 1201 BPrivate::AppServerLink link; 1202 1203 link.StartMessage(AS_BRING_TEAM_TO_FRONT); 1204 link.Attach<team_id>(team); 1205 // we don't have any zooming effect 1206 1207 link.Flush(); 1208 } 1209 1210 1211 void 1212 do_minimize_team(BRect zoomRect, team_id team, bool zoom) 1213 { 1214 BPrivate::AppServerLink link; 1215 1216 link.StartMessage(AS_MINIMIZE_TEAM); 1217 link.Attach<team_id>(team); 1218 // we don't have any zooming effect 1219 1220 link.Flush(); 1221 } 1222 1223 1224 // #pragma mark - truncate string 1225 1226 1227 static char* 1228 write_ellipsis(char* dst) 1229 { 1230 strcpy(dst, B_UTF8_ELLIPSIS); 1231 // The UTF-8 character spans over 3 bytes 1232 return dst + 3; 1233 } 1234 1235 1236 static bool 1237 optional_char_fits(float escapement, float fontSize, float gap) 1238 { 1239 const float size = escapement * fontSize; 1240 if (size <= gap || fabs(size - gap) <= 0.0001) 1241 return true; 1242 return false; 1243 } 1244 1245 1246 bool 1247 truncate_end(const char* source, char* dest, uint32 numChars, 1248 const float* escapementArray, float width, float ellipsisWidth, float size) 1249 { 1250 float currentWidth = 0.0; 1251 ellipsisWidth /= size; // test if this is as accurate as escapementArray * size 1252 width /= size; 1253 uint32 lastFit = 0, c; 1254 1255 for (c = 0; c < numChars; c++) { 1256 currentWidth += escapementArray[c]; 1257 if (currentWidth + ellipsisWidth <= width) 1258 lastFit = c; 1259 1260 if (currentWidth > width) 1261 break; 1262 } 1263 1264 if (c == numChars) { 1265 // string fits into width 1266 return false; 1267 } 1268 1269 if (c == 0) { 1270 // there is no space for the ellipsis 1271 strcpy(dest, ""); 1272 return true; 1273 } 1274 1275 // copy string to destination 1276 1277 for (uint32 i = 0; i < lastFit + 1; i++) { 1278 // copy one glyph 1279 do { 1280 *dest++ = *source++; 1281 } while (IsInsideGlyph(*source)); 1282 } 1283 1284 // write ellipsis and terminate 1285 1286 dest = write_ellipsis(dest); 1287 *dest = '\0'; 1288 return true; 1289 } 1290 1291 1292 static char* 1293 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length, 1294 const float* escapementArray, float width, float ellipsisWidth, float size) 1295 { 1296 const char* originalStart = src; 1297 src += length - 1; 1298 float currentWidth = 0.0; 1299 for (int32 c = numChars - 1; c > 0; c--) { 1300 currentWidth += escapementArray[c] * size; 1301 if (currentWidth > width) { 1302 // ups, we definitely don't fit. go back until the ellipsis fits 1303 currentWidth += ellipsisWidth; 1304 // go forward again until ellipsis fits (already beyond the target) 1305 for (uint32 c2 = c; c2 < numChars; c2++) { 1306 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size); 1307 currentWidth -= escapementArray[c2] * size; 1308 do { 1309 src++; 1310 } while (IsInsideGlyph(*src)); 1311 // see if we went back enough 1312 if (currentWidth <= width) 1313 break; 1314 } 1315 break; 1316 } else { 1317 // go back one glyph 1318 do { 1319 src--; 1320 } while (IsInsideGlyph(*src)); 1321 } 1322 } 1323 // copy from the end of the string 1324 uint32 bytesToCopy = originalStart + length - src; 1325 memcpy(dst, src, bytesToCopy); 1326 dst += bytesToCopy; 1327 return dst; 1328 } 1329 1330 1331 bool 1332 truncate_middle(const char* source, char* dest, uint32 numChars, 1333 const float* escapementArray, float width, float ellipsisWidth, float size) 1334 { 1335 float mid = (width - ellipsisWidth) / 2.0; 1336 1337 uint32 left = 0; 1338 float leftWidth = 0.0; 1339 while (left < numChars && (leftWidth + (escapementArray[left] * size)) < mid) 1340 leftWidth += (escapementArray[left++] * size); 1341 1342 if (left == numChars) 1343 return false; 1344 1345 float rightWidth = 0.0; 1346 uint32 right = numChars; 1347 while (right > left && (rightWidth + (escapementArray[right - 1] * size)) < mid) 1348 rightWidth += (escapementArray[--right] * size); 1349 1350 if (left >= right) 1351 return false; 1352 1353 float stringWidth = leftWidth + rightWidth; 1354 for (uint32 i = left; i < right; ++i) 1355 stringWidth += (escapementArray[i] * size); 1356 1357 if (stringWidth <= width) 1358 return false; 1359 1360 // if there is no space for the ellipsis 1361 if (width < ellipsisWidth) { 1362 strcpy(dest, ""); 1363 return true; 1364 } 1365 1366 // The ellipsis now definitely fits, but let's 1367 // see if we can add another character 1368 float gap = width - (leftWidth + ellipsisWidth + rightWidth); 1369 if (left > numChars - right) { 1370 // try right letter first 1371 if (optional_char_fits(escapementArray[right - 1], size, gap)) { 1372 right--; 1373 } else if (optional_char_fits(escapementArray[left], size, gap)) { 1374 left++; 1375 } 1376 } else { 1377 // try left letter first 1378 if (optional_char_fits(escapementArray[left], size, gap)) { 1379 left++; 1380 } else if (optional_char_fits(escapementArray[right - 1], size, gap)) { 1381 right--; 1382 } 1383 } 1384 1385 // copy characters 1386 1387 for (uint32 i = 0; i < left; i++) { 1388 // copy one glyph 1389 do { 1390 *dest++ = *source++; 1391 } while (IsInsideGlyph(*source)); 1392 } 1393 1394 dest = write_ellipsis(dest); 1395 1396 for (uint32 i = left; i < numChars; i++) { 1397 // copy one glyph 1398 do { 1399 if (i >= right) 1400 *dest++ = *source++; 1401 else 1402 source++; 1403 } while (IsInsideGlyph(*source)); 1404 } 1405 1406 // terminate 1407 dest[0] = '\0'; 1408 return true; 1409 } 1410 1411 1412 // TODO: put into BPrivate namespace 1413 void 1414 truncate_string(const char* string, uint32 mode, float width, 1415 char* result, const float* escapementArray, float fontSize, 1416 float ellipsisWidth, int32 length, int32 numChars) 1417 { 1418 // TODO: that's actually not correct: the string could be smaller than ellipsisWidth 1419 if (string == NULL /*|| width < ellipsisWidth*/) { 1420 // we don't have room for a single glyph 1421 strcpy(result, ""); 1422 return; 1423 } 1424 1425 // iterate over glyphs and copy source into result string 1426 // one glyph at a time as long as we have room for the "…" yet 1427 char* dest = result; 1428 const char* source = string; 1429 bool truncated = true; 1430 1431 switch (mode) { 1432 case B_TRUNCATE_BEGINNING: { 1433 dest = copy_from_end(source, dest, numChars, length, 1434 escapementArray, width, ellipsisWidth, fontSize); 1435 // "dst" points to the position behind the last glyph that 1436 // was copied. 1437 int32 dist = dest - result; 1438 // we didn't terminate yet 1439 *dest = 0; 1440 if (dist < length) { 1441 // TODO: Is there a smarter way? 1442 char* temp = new char[dist + 4]; 1443 char* t = temp; 1444 // append "…" 1445 t = write_ellipsis(t); 1446 // shuffle arround strings so that "…" is prepended 1447 strcpy(t, result); 1448 strcpy(result, temp); 1449 delete[] temp; 1450 /* char t = result[3]; 1451 memmove(&result[3], result, dist + 1); 1452 write_ellipsis(result); 1453 result[3] = t;*/ 1454 } 1455 break; 1456 } 1457 1458 case B_TRUNCATE_END: 1459 truncated = truncate_end(source, dest, numChars, escapementArray, 1460 width, ellipsisWidth, fontSize); 1461 break; 1462 1463 case B_TRUNCATE_SMART: 1464 // TODO: implement, though it was never implemented on R5 1465 // FALL THROUGH (at least do something) 1466 case B_TRUNCATE_MIDDLE: 1467 default: 1468 truncated = truncate_middle(source, dest, numChars, escapementArray, 1469 width, ellipsisWidth, fontSize); 1470 break; 1471 } 1472 1473 if (!truncated) { 1474 // copy string to destination verbatim 1475 strlcpy(dest, source, length + 1); 1476 } 1477 } 1478 1479