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