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