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