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