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_RAW_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_RAW_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 void 741 set_ui_color(const color_which &which, const rgb_color &color) 742 { 743 int32 index = color_which_to_index(which); 744 if (index < 0 || index >= kNumColors) { 745 fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which); 746 return; 747 } 748 749 BPrivate::AppServerLink link; 750 link.StartMessage(AS_SET_UI_COLOR); 751 link.Attach<color_which>(which); 752 link.Attach<rgb_color>(color); 753 link.Flush(); 754 } 755 756 757 _IMPEXP_BE rgb_color 758 tint_color(rgb_color color, float tint) 759 { 760 rgb_color result; 761 762 #define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint)) 763 #define DARKEN(x) ((uint8)(x * (2 - tint))) 764 765 if (tint < 1.0f) { 766 result.red = LIGHTEN(color.red); 767 result.green = LIGHTEN(color.green); 768 result.blue = LIGHTEN(color.blue); 769 result.alpha = color.alpha; 770 } else { 771 result.red = DARKEN(color.red); 772 result.green = DARKEN(color.green); 773 result.blue = DARKEN(color.blue); 774 result.alpha = color.alpha; 775 } 776 777 #undef LIGHTEN 778 #undef DARKEN 779 780 return result; 781 } 782 783 784 rgb_color shift_color(rgb_color color, float shift); 785 786 rgb_color 787 shift_color(rgb_color color, float shift) 788 { 789 return tint_color(color, shift); 790 } 791 792 793 extern "C" status_t 794 _init_interface_kit_() 795 { 796 sem_id widthSem = create_sem(0, "BTextView WidthBuffer Sem"); 797 if (widthSem < 0) 798 return widthSem; 799 BTextView::sWidthSem = widthSem; 800 BTextView::sWidthAtom = 0; 801 BTextView::sWidths = new _BWidthBuffer_; 802 803 _init_global_fonts_(); 804 805 _menu_info_ptr_ = &BMenu::sMenuInfo; 806 status_t status = get_menu_info(&BMenu::sMenuInfo); 807 808 general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR); 809 general_info.mark_color.set_to(0, 0, 0); 810 general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR); 811 general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR); 812 general_info.color_frame = true; 813 814 // TODO: fill the other static members 815 816 return status; 817 } 818 819 820 extern "C" status_t 821 _fini_interface_kit_() 822 { 823 //TODO: Implement ? 824 825 return B_OK; 826 } 827 828 829 // #pragma mark - 830 831 832 /*! 833 \brief private function used by Deskbar to set window decor 834 Note, we don't have to be compatible here, and could just change 835 the Deskbar not to use this anymore 836 \param theme The theme to choose 837 838 - \c 0: BeOS 839 - \c 1: AmigaOS 840 - \c 2: Win95 841 - \c 3: MacOS 842 */ 843 void 844 __set_window_decor(int32 theme) 845 { 846 BPrivate::AppServerLink link; 847 link.StartMessage(AS_R5_SET_DECORATOR); 848 link.Attach<int32>(theme); 849 link.Flush(); 850 } 851 852 853 namespace BPrivate { 854 855 /*! 856 \brief queries the server for the number of available decorators 857 \return the number of available decorators 858 */ 859 int32 860 count_decorators(void) 861 { 862 BPrivate::AppServerLink link; 863 link.StartMessage(AS_COUNT_DECORATORS); 864 865 int32 code; 866 int32 count = -1; 867 if (link.FlushWithReply(code) == B_OK && code == B_OK) 868 link.Read<int32>(&count); 869 870 return count; 871 } 872 873 /*! 874 \brief queries the server for the index of the current decorators 875 \return the current decorator's index 876 877 If for some bizarre reason this function fails, it returns -1 878 */ 879 int32 880 get_decorator(void) 881 { 882 BPrivate::AppServerLink link; 883 link.StartMessage(AS_GET_DECORATOR); 884 885 int32 code; 886 int32 index = -1; 887 if (link.FlushWithReply(code) == B_OK && code == B_OK) 888 link.Read<int32>(&index); 889 890 return index; 891 } 892 893 894 /*! 895 \brief queries the server for the name of the decorator with a certain index 896 \param index The index of the decorator to get the name for 897 \param name BString to receive the name of the decorator 898 \return B_OK if successful, B_ERROR if not 899 */ 900 status_t 901 get_decorator_name(const int32 &index, BString &name) 902 { 903 BPrivate::AppServerLink link; 904 link.StartMessage(AS_GET_DECORATOR_NAME); 905 link.Attach<int32>(index); 906 907 int32 code; 908 if (link.FlushWithReply(code) == B_OK && code == B_OK) { 909 char *string; 910 if (link.ReadString(&string) == B_OK) { 911 name = string; 912 free(string); 913 return B_OK; 914 } 915 } 916 917 return B_ERROR; 918 } 919 920 /*! 921 \brief asks the server to draw a decorator preview into a BBitmap 922 \param index The index of the decorator to get the name for 923 \param bitmap BBitmap to receive the preview 924 \return B_OK if successful, B_ERROR if not. 925 926 This is currently unimplemented. 927 */ 928 status_t 929 get_decorator_preview(const int32 &index, BBitmap *bitmap) 930 { 931 // TODO: implement get_decorator_preview 932 return B_ERROR; 933 } 934 935 936 /*! 937 \brief Private function which sets the window decorator for the system. 938 \param index Index of the decorator to set 939 940 If the index is invalid, this function and the server do nothing 941 */ 942 status_t 943 set_decorator(const int32 &index) 944 { 945 if (index < 0) 946 return B_BAD_VALUE; 947 948 BPrivate::AppServerLink link; 949 950 link.StartMessage(AS_SET_DECORATOR); 951 link.Attach<int32>(index); 952 link.Flush(); 953 954 return B_OK; 955 } 956 957 } // namespace BPrivate 958 959 // These methods were marked with "Danger, will Robinson!" in 960 // the OpenTracker source, so we might not want to be compatible 961 // here. 962 // In any way, we would need to update Deskbar to use our 963 // replacements, so we could as well just implement them... 964 // 965 // They are defined (also the complete window_info structure) in 966 // src/apps/deskbar/WindowMenuItem.h 967 968 struct window_info; 969 970 void do_window_action(int32 window_id, int32 action, 971 BRect zoomRect, bool zoom); 972 window_info *get_window_info(int32 a_token); 973 int32 *get_token_list(team_id app, int32 *count); 974 void do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom); 975 void do_minimize_team(BRect zoomRect, team_id team, bool zoom); 976 977 978 void 979 do_window_action(int32 windowToken, int32 action, 980 BRect zoomRect, bool zoom) 981 { 982 BPrivate::AppServerLink link; 983 984 link.StartMessage(AS_WINDOW_ACTION); 985 link.Attach<int32>(windowToken); 986 link.Attach<int32>(action); 987 // we don't have any zooming effect 988 989 link.Flush(); 990 } 991 992 993 window_info * 994 get_window_info(int32 serverToken) 995 { 996 BPrivate::AppServerLink link; 997 998 link.StartMessage(AS_GET_WINDOW_INFO); 999 link.Attach<int32>(serverToken); 1000 1001 int32 code; 1002 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1003 return NULL; 1004 1005 int32 size; 1006 link.Read<int32>(&size); 1007 1008 client_window_info* info = (client_window_info*)malloc(size); 1009 if (info == NULL) 1010 return NULL; 1011 1012 link.Read(info, size); 1013 return info; 1014 } 1015 1016 1017 int32 * 1018 get_token_list(team_id team, int32 *_count) 1019 { 1020 BPrivate::AppServerLink link; 1021 1022 link.StartMessage(AS_GET_WINDOW_LIST); 1023 link.Attach<team_id>(team); 1024 1025 int32 code; 1026 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1027 return NULL; 1028 1029 int32 count; 1030 link.Read<int32>(&count); 1031 1032 int32* tokens = (int32*)malloc(count * sizeof(int32)); 1033 if (tokens == NULL) 1034 return NULL; 1035 1036 link.Read(tokens, count * sizeof(int32)); 1037 *_count = count; 1038 return tokens; 1039 } 1040 1041 1042 void 1043 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom) 1044 { 1045 BPrivate::AppServerLink link; 1046 1047 link.StartMessage(AS_BRING_TEAM_TO_FRONT); 1048 link.Attach<team_id>(team); 1049 // we don't have any zooming effect 1050 1051 link.Flush(); 1052 } 1053 1054 1055 void 1056 do_minimize_team(BRect zoomRect, team_id team, bool zoom) 1057 { 1058 BPrivate::AppServerLink link; 1059 1060 link.StartMessage(AS_MINIMIZE_TEAM); 1061 link.Attach<team_id>(team); 1062 // we don't have any zooming effect 1063 1064 link.Flush(); 1065 } 1066 1067 1068 // #pragma mark - truncate string 1069 1070 1071 static char* 1072 write_ellipsis(char* dst) 1073 { 1074 strcpy(dst, B_UTF8_ELLIPSIS); 1075 // The UTF-8 character spans over 3 bytes 1076 return dst + 3; 1077 } 1078 1079 1080 bool 1081 truncate_end(const char* source, char* dest, uint32 numChars, 1082 const float* escapementArray, float width, float ellipsisWidth, float size) 1083 { 1084 float currentWidth = 0.0; 1085 ellipsisWidth /= size; // test if this is as accurate as escapementArray * size 1086 width /= size; 1087 uint32 lastFit = 0, c; 1088 1089 for (c = 0; c < numChars; c++) { 1090 currentWidth += escapementArray[c]; 1091 if (currentWidth + ellipsisWidth <= width) 1092 lastFit = c; 1093 1094 if (currentWidth > width) 1095 break; 1096 } 1097 1098 if (c == numChars) { 1099 // string fits into width 1100 return false; 1101 } 1102 1103 if (c == 0) { 1104 // there is no space for the ellipsis 1105 strcpy(dest, ""); 1106 return true; 1107 } 1108 1109 // copy string to destination 1110 1111 for (uint32 i = 0; i < lastFit + 1; i++) { 1112 // copy one glyph 1113 do { 1114 *dest++ = *source++; 1115 } while (IsInsideGlyph(*source)); 1116 } 1117 1118 // write ellipsis and terminate 1119 1120 dest = write_ellipsis(dest); 1121 *dest = '\0'; 1122 return true; 1123 } 1124 1125 1126 static char* 1127 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length, 1128 const float* escapementArray, float width, float ellipsisWidth, float size) 1129 { 1130 const char* originalStart = src; 1131 src += length - 1; 1132 float currentWidth = 0.0; 1133 for (int32 c = numChars - 1; c > 0; c--) { 1134 currentWidth += escapementArray[c] * size; 1135 if (currentWidth > width) { 1136 // ups, we definitely don't fit. go back until the ellipsis fits 1137 currentWidth += ellipsisWidth; 1138 // go forward again until ellipsis fits (already beyond the target) 1139 for (uint32 c2 = c; c2 < numChars; c2++) { 1140 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size); 1141 currentWidth -= escapementArray[c2] * size; 1142 do { 1143 src++; 1144 } while (IsInsideGlyph(*src)); 1145 // see if we went back enough 1146 if (currentWidth <= width) 1147 break; 1148 } 1149 break; 1150 } else { 1151 // go back one glyph 1152 do { 1153 src--; 1154 } while (IsInsideGlyph(*src)); 1155 } 1156 } 1157 // copy from the end of the string 1158 uint32 bytesToCopy = originalStart + length - src; 1159 memcpy(dst, src, bytesToCopy); 1160 dst += bytesToCopy; 1161 return dst; 1162 } 1163 1164 1165 bool 1166 truncate_middle(const char* source, char* dest, uint32 numChars, 1167 const float* escapementArray, float width, float ellipsisWidth, float size) 1168 { 1169 // find visual center 1170 1171 ellipsisWidth /= size; // test if this is as accurate as escapementArray * size 1172 width /= size; 1173 1174 float halfWidth = (width - ellipsisWidth) / 2.0; 1175 float leftWidth = 0.0, rightWidth = 0.0; 1176 uint32 left, right; 1177 1178 // coming from left... 1179 1180 for (left = 0; left < numChars; left++) { 1181 if (leftWidth + escapementArray[left] > halfWidth) 1182 break; 1183 1184 leftWidth += escapementArray[left]; 1185 } 1186 1187 if (left == numChars) { 1188 // string is smaller than half of the maximum width 1189 return false; 1190 } 1191 1192 // coming from right... 1193 1194 for (right = numChars; right-- > left; ) { 1195 if (rightWidth + escapementArray[right] > halfWidth) 1196 break; 1197 1198 rightWidth += escapementArray[right]; 1199 } 1200 1201 if (left >= right) { 1202 // string is smaller than the maximum width 1203 return false; 1204 } 1205 1206 if (left == 0 || right >= numChars - 1) { 1207 // there is no space for the ellipsis 1208 strcpy(dest, ""); 1209 return true; 1210 } 1211 1212 // see if the gap between left/right is smaller than the ellipsis 1213 1214 float totalWidth = rightWidth + leftWidth; 1215 1216 for (uint32 i = left; i < right; i++) { 1217 totalWidth += escapementArray[i]; 1218 if (totalWidth > width) 1219 break; 1220 } 1221 1222 if (totalWidth <= width) { 1223 // the whole string fits! 1224 return false; 1225 } 1226 1227 // The ellipsis now definitely fits, but let's 1228 // see if we can add another character 1229 1230 totalWidth = ellipsisWidth + rightWidth + leftWidth; 1231 1232 if (left > numChars - right) { 1233 // try right letter first 1234 if (escapementArray[right] + totalWidth <= width) 1235 right--; 1236 else if (escapementArray[left] + totalWidth <= width) 1237 left++; 1238 } else { 1239 // try left letter first 1240 if (escapementArray[left] + totalWidth <= width) 1241 left++; 1242 else if (escapementArray[right] + totalWidth <= width) 1243 right--; 1244 } 1245 1246 // copy characters 1247 1248 for (uint32 i = 0; i < left; i++) { 1249 // copy one glyph 1250 do { 1251 *dest++ = *source++; 1252 } while (IsInsideGlyph(*source)); 1253 } 1254 1255 dest = write_ellipsis(dest); 1256 1257 for (uint32 i = left; i < numChars; i++) { 1258 // copy one glyph 1259 do { 1260 if (i >= right) 1261 *dest++ = *source++; 1262 else 1263 source++; 1264 } while (IsInsideGlyph(*source)); 1265 } 1266 1267 // terminate 1268 dest[0] = '\0'; 1269 return true; 1270 } 1271 1272 1273 // ToDo: put into BPrivate namespace 1274 void 1275 truncate_string(const char* string, uint32 mode, float width, 1276 char* result, const float* escapementArray, float fontSize, 1277 float ellipsisWidth, int32 length, int32 numChars) 1278 { 1279 // ToDo: that's actually not correct: the string could be smaller than ellipsisWidth 1280 if (string == NULL /*|| width < ellipsisWidth*/) { 1281 // we don't have room for a single glyph 1282 strcpy(result, ""); 1283 return; 1284 } 1285 1286 // iterate over glyphs and copy source into result string 1287 // one glyph at a time as long as we have room for the "…" yet 1288 char* dest = result; 1289 const char* source = string; 1290 bool truncated = true; 1291 1292 switch (mode) { 1293 case B_TRUNCATE_BEGINNING: { 1294 dest = copy_from_end(source, dest, numChars, length, 1295 escapementArray, width, ellipsisWidth, fontSize); 1296 // "dst" points to the position behind the last glyph that 1297 // was copied. 1298 int32 dist = dest - result; 1299 // we didn't terminate yet 1300 *dest = 0; 1301 if (dist < length) { 1302 // TODO: Is there a smarter way? 1303 char* temp = new char[dist + 4]; 1304 char* t = temp; 1305 // append "…" 1306 t = write_ellipsis(t); 1307 // shuffle arround strings so that "…" is prepended 1308 strcpy(t, result); 1309 strcpy(result, temp); 1310 delete[] temp; 1311 /* char t = result[3]; 1312 memmove(&result[3], result, dist + 1); 1313 write_ellipsis(result); 1314 result[3] = t;*/ 1315 } 1316 break; 1317 } 1318 1319 case B_TRUNCATE_END: 1320 truncated = truncate_end(source, dest, numChars, escapementArray, 1321 width, ellipsisWidth, fontSize); 1322 break; 1323 1324 case B_TRUNCATE_SMART: 1325 // TODO: implement, though it was never implemented on R5 1326 // FALL THROUGH (at least do something) 1327 case B_TRUNCATE_MIDDLE: 1328 truncated = truncate_middle(source, dest, numChars, escapementArray, 1329 width, ellipsisWidth, fontSize); 1330 break; 1331 } 1332 1333 if (!truncated) { 1334 // copy string to destination verbatim 1335 strlcpy(dest, source, length + 1); 1336 } 1337 } 1338 1339