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