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