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