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