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