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