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