1 /* 2 * Copyright 2009, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include "NetReceiver.h" 10 #include "NetSender.h" 11 #include "RemoteMessage.h" 12 #include "RemoteView.h" 13 #include "StreamingRingBuffer.h" 14 15 #include <Application.h> 16 #include <Autolock.h> 17 #include <Bitmap.h> 18 #include <Message.h> 19 #include <NetEndpoint.h> 20 #include <Region.h> 21 #include <Shape.h> 22 #include <Window.h> 23 24 #include <new> 25 #include <stdio.h> 26 27 28 static const uint8 kCursorData[] = { 16 /* size, 16x16 */, 29 1 /* depth, 1 bit per pixel */, 0, 0, /* hot spot at 0, 0 */ 30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 38 }; 39 40 41 #define TRACE(x...) /*printf("RemoteView: "x)*/ 42 #define TRACE_ALWAYS(x...) printf("RemoteView: "x) 43 #define TRACE_ERROR(x...) printf("RemoteView: "x) 44 45 46 typedef struct engine_state { 47 uint32 token; 48 BView * view; 49 ::pattern pattern; 50 BRegion clipping_region; 51 float pen_size; 52 bool sync_drawing; 53 } engine_state; 54 55 56 RemoteView::RemoteView(BRect frame, uint16 listenPort) 57 : 58 BView(frame, "RemoteView", B_FOLLOW_NONE, B_WILL_DRAW), 59 fInitStatus(B_NO_INIT), 60 fIsConnected(false), 61 fReceiveBuffer(NULL), 62 fSendBuffer(NULL), 63 fReceiveEndpoint(NULL), 64 fSendEndpoint(NULL), 65 fReceiver(NULL), 66 fSender(NULL), 67 fStopThread(false), 68 fOffscreenBitmap(NULL), 69 fOffscreen(NULL), 70 fViewCursor(kCursorData), 71 fCursorBitmap(NULL), 72 fCursorVisible(false) 73 { 74 fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 75 if (fReceiveBuffer == NULL) { 76 fInitStatus = B_NO_MEMORY; 77 return; 78 } 79 80 fInitStatus = fReceiveBuffer->InitCheck(); 81 if (fInitStatus != B_OK) 82 return; 83 84 fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 85 if (fSendBuffer == NULL) { 86 fInitStatus = B_NO_MEMORY; 87 return; 88 } 89 90 fInitStatus = fSendBuffer->InitCheck(); 91 if (fInitStatus != B_OK) 92 return; 93 94 fReceiveEndpoint = new(std::nothrow) BNetEndpoint(); 95 if (fReceiveEndpoint == NULL) { 96 fInitStatus = B_NO_MEMORY; 97 return; 98 } 99 100 fInitStatus = fReceiveEndpoint->Bind(listenPort); 101 if (fInitStatus != B_OK) 102 return; 103 104 fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer); 105 if (fReceiver == NULL) { 106 fInitStatus = B_NO_MEMORY; 107 return; 108 } 109 110 fSendEndpoint = new(std::nothrow) BNetEndpoint(); 111 if (fSendEndpoint == NULL) { 112 fInitStatus = B_NO_MEMORY; 113 return; 114 } 115 116 fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer); 117 if (fSender == NULL) { 118 fInitStatus = B_NO_MEMORY; 119 return; 120 } 121 122 BRect bounds = frame.OffsetToCopy(0, 0); 123 fOffscreenBitmap = new(std::nothrow) BBitmap(bounds, B_BITMAP_ACCEPTS_VIEWS, 124 B_RGB32); 125 if (fOffscreenBitmap == NULL) { 126 fInitStatus = B_NO_MEMORY; 127 return; 128 } 129 130 fOffscreen = new(std::nothrow) BView(bounds, "offscreen remote view", 131 B_FOLLOW_NONE, B_WILL_DRAW); 132 if (fOffscreen == NULL) { 133 fInitStatus = B_NO_MEMORY; 134 return; 135 } 136 137 fOffscreenBitmap->AddChild(fOffscreen); 138 fOffscreen->SetDrawingMode(B_OP_COPY); 139 140 fDrawThread = spawn_thread(&_DrawEntry, "draw thread", B_NORMAL_PRIORITY, 141 this); 142 if (fDrawThread < 0) { 143 fInitStatus = fDrawThread; 144 return; 145 } 146 147 resume_thread(fDrawThread); 148 } 149 150 151 RemoteView::~RemoteView() 152 { 153 fStopThread = true; 154 155 delete fReceiver; 156 delete fReceiveBuffer; 157 158 delete fSendBuffer; 159 delete fSender; 160 161 delete fReceiveEndpoint; 162 delete fSendEndpoint; 163 164 delete fOffscreenBitmap; 165 delete fCursorBitmap; 166 167 int32 result; 168 wait_for_thread(fDrawThread, &result); 169 } 170 171 172 status_t 173 RemoteView::InitCheck() 174 { 175 return fInitStatus; 176 } 177 178 179 void 180 RemoteView::AttachedToWindow() 181 { 182 SetViewColor(B_TRANSPARENT_COLOR); 183 SetViewCursor(&fViewCursor); 184 } 185 186 187 void 188 RemoteView::Draw(BRect updateRect) 189 { 190 SetDrawingMode(B_OP_COPY); 191 fOffscreenBitmap->Lock(); 192 fOffscreen->Sync(); 193 194 DrawBitmap(fOffscreenBitmap, updateRect, updateRect); 195 196 if (fCursorVisible && fCursorBitmap != NULL 197 && fCursorFrame.Intersects(updateRect)) { 198 DrawBitmap(fOffscreenBitmap, fCursorFrame, fCursorFrame); 199 SetDrawingMode(B_OP_ALPHA); 200 DrawBitmap(fCursorBitmap, fCursorFrame.LeftTop()); 201 } 202 203 fOffscreenBitmap->Unlock(); 204 } 205 206 207 void 208 RemoteView::MouseMoved(BPoint where, uint32 code, const BMessage *dragMessage) 209 { 210 if (!fIsConnected) 211 return; 212 213 _SendMouseMessage(RP_MOUSE_MOVED, where); 214 } 215 216 217 void 218 RemoteView::MouseDown(BPoint where) 219 { 220 if (!fIsConnected) 221 return; 222 223 _SendMouseMessage(RP_MOUSE_DOWN, where); 224 } 225 226 227 void 228 RemoteView::MouseUp(BPoint where) 229 { 230 if (!fIsConnected) 231 return; 232 233 _SendMouseMessage(RP_MOUSE_UP, where); 234 } 235 236 237 void 238 RemoteView::KeyDown(const char *bytes, int32 numBytes) 239 { 240 if (!fIsConnected) 241 return; 242 243 _SendKeyMessage(RP_KEY_DOWN, bytes, numBytes); 244 } 245 246 247 void 248 RemoteView::KeyUp(const char *bytes, int32 numBytes) 249 { 250 if (!fIsConnected) 251 return; 252 253 _SendKeyMessage(RP_KEY_UP, bytes, numBytes); 254 } 255 256 257 void 258 RemoteView::MessageReceived(BMessage *message) 259 { 260 if (!fIsConnected) { 261 BView::MessageReceived(message); 262 return; 263 } 264 265 switch (message->what) { 266 case B_UNMAPPED_KEY_DOWN: 267 case B_UNMAPPED_KEY_UP: 268 // these are easily repeated and then cause a flood of messages 269 // so we might not want them. 270 break; 271 272 case B_MODIFIERS_CHANGED: 273 { 274 uint32 modifiers = 0; 275 message->FindInt32("modifiers", (int32 *)&modifiers); 276 RemoteMessage message(NULL, fSendBuffer); 277 message.Start(RP_MODIFIERS_CHANGED); 278 message.Add(modifiers); 279 break; 280 } 281 282 case B_MOUSE_WHEEL_CHANGED: 283 { 284 float xDelta, yDelta; 285 if (message->FindFloat("be:wheel_delta_x", &xDelta) != B_OK) 286 xDelta = 0; 287 if (message->FindFloat("be:wheel_delta_y", &yDelta) != B_OK) 288 yDelta = 0; 289 290 RemoteMessage message(NULL, fSendBuffer); 291 message.Start(RP_MOUSE_WHEEL_CHANGED); 292 message.Add(xDelta); 293 message.Add(yDelta); 294 break; 295 } 296 } 297 298 BView::MessageReceived(message); 299 } 300 301 302 void 303 RemoteView::_SendMouseMessage(uint16 code, BPoint where) 304 { 305 RemoteMessage message(NULL, fSendBuffer); 306 message.Start(code); 307 message.Add(where); 308 309 if (code == RP_MOUSE_MOVED) 310 return; 311 312 BMessage *event = Window()->CurrentMessage(); 313 314 int32 buttons = 0; 315 event->FindInt32("buttons", &buttons); 316 message.Add(buttons); 317 318 if (code == RP_MOUSE_DOWN) 319 return; 320 321 int32 clicks; 322 event->FindInt32("clicks", &clicks); 323 message.Add(clicks); 324 } 325 326 327 void 328 RemoteView::_SendKeyMessage(uint16 code, const char *bytes, int32 numBytes) 329 { 330 RemoteMessage message(NULL, fSendBuffer); 331 message.Start(code); 332 message.Add(numBytes); 333 message.AddList(bytes, numBytes); 334 335 BMessage *event = Window()->CurrentMessage(); 336 337 int32 rawChar, key; 338 event->FindInt32("raw_char", &rawChar); 339 event->FindInt32("key", &key); 340 341 message.Add(rawChar); 342 message.Add(key); 343 } 344 345 346 int 347 RemoteView::_StateCompareByKey(const uint32 *key, const engine_state *state) 348 { 349 if (state->token == *key) 350 return 0; 351 352 if (state->token < *key) 353 return -1; 354 355 return 1; 356 } 357 358 359 void 360 RemoteView::_CreateState(uint32 token) 361 { 362 int32 index = fStates.BinarySearchIndexByKey(token, &_StateCompareByKey); 363 if (index >= 0) { 364 TRACE_ERROR("state for token %lu already in list\n", token); 365 return; 366 } 367 368 engine_state *state = new(std::nothrow) engine_state; 369 if (state == NULL) { 370 TRACE_ERROR("failed to allocate engine state\n"); 371 return; 372 } 373 374 fOffscreenBitmap->Lock(); 375 BView *offscreen = new(std::nothrow) BView(fOffscreenBitmap->Bounds(), 376 "offscreen remote view", B_FOLLOW_NONE, B_WILL_DRAW); 377 if (offscreen == NULL) { 378 TRACE_ERROR("failed to allocate offscreen view\n"); 379 fOffscreenBitmap->Unlock(); 380 delete state; 381 return; 382 } 383 384 fOffscreenBitmap->AddChild(offscreen); 385 fOffscreenBitmap->Unlock(); 386 387 state->token = token; 388 state->view = offscreen; 389 state->pattern = B_SOLID_HIGH; 390 state->clipping_region.MakeEmpty(); 391 state->pen_size = 0; 392 state->sync_drawing = true; 393 394 fStates.AddItem(state, -index - 1); 395 } 396 397 398 void 399 RemoteView::_DeleteState(uint32 token) 400 { 401 int32 index = fStates.BinarySearchIndexByKey(token, &_StateCompareByKey); 402 if (index < 0) 403 return; 404 405 engine_state *state = fStates.RemoveItemAt(index); 406 407 fOffscreenBitmap->RemoveChild(state->view); 408 delete state->view; 409 delete state; 410 } 411 412 413 engine_state * 414 RemoteView::_FindState(uint32 token) 415 { 416 return fStates.BinarySearchByKey(token, &_StateCompareByKey); 417 } 418 419 420 int32 421 RemoteView::_DrawEntry(void *data) 422 { 423 ((RemoteView *)data)->_DrawThread(); 424 return 0; 425 } 426 427 428 void 429 RemoteView::_DrawThread() 430 { 431 RemoteMessage reply(NULL, fSendBuffer); 432 RemoteMessage message(fReceiveBuffer, NULL); 433 434 // cursor 435 BPoint cursorHotSpot(0, 0); 436 437 while (!fStopThread) { 438 uint16 code; 439 status_t status = message.NextMessage(code); 440 if (status != B_OK) { 441 TRACE_ERROR("failed to read message from receiver\n"); 442 break; 443 } 444 445 TRACE("code %u with %ld bytes data\n", code, message.DataLeft()); 446 447 BAutolock locker(this->Looper()); 448 if (!locker.IsLocked()) 449 break; 450 451 // handle stuff that doesn't go to a specicifc engine 452 switch (code) { 453 case RP_INIT_CONNECTION: 454 { 455 uint16 port; 456 status_t result = message.Read(port); 457 if (result != B_OK) { 458 TRACE_ERROR("failed to read remote port\n"); 459 continue; 460 } 461 462 BNetEndpoint *endpoint = fReceiver->Endpoint(); 463 if (endpoint == NULL) { 464 TRACE_ERROR("receiver not connected anymore\n"); 465 continue; 466 } 467 468 in_addr remoteHost; 469 char hostName[MAXHOSTNAMELEN + 1]; 470 BNetAddress address(endpoint->RemoteAddr()); 471 address.GetAddr(remoteHost); 472 address.GetAddr(hostName, NULL); 473 address.SetTo(remoteHost, port); 474 475 TRACE("connecting to host \"%s\" port %u\n", hostName, port); 476 result = fSendEndpoint->Connect(address); 477 if (result != B_OK) { 478 TRACE_ERROR("failed to connect to host \"%s\" port %u\n", 479 hostName, port); 480 continue; 481 } 482 483 BRect bounds = fOffscreenBitmap->Bounds(); 484 reply.Start(RP_UPDATE_DISPLAY_MODE); 485 reply.Add(bounds.IntegerWidth() + 1); 486 reply.Add(bounds.IntegerHeight() + 1); 487 if (reply.Flush() == B_OK) 488 fIsConnected = true; 489 490 continue; 491 } 492 493 case RP_CLOSE_CONNECTION: 494 { 495 be_app->PostMessage(B_QUIT_REQUESTED); 496 continue; 497 } 498 499 case RP_CREATE_STATE: 500 case RP_DELETE_STATE: 501 { 502 uint32 token; 503 message.Read(token); 504 505 if (code == RP_CREATE_STATE) 506 _CreateState(token); 507 else 508 _DeleteState(token); 509 510 continue; 511 } 512 513 case RP_SET_CURSOR: 514 { 515 BBitmap *bitmap; 516 BPoint oldHotSpot = cursorHotSpot; 517 message.Read(cursorHotSpot); 518 if (message.ReadBitmap(&bitmap) != B_OK) 519 continue; 520 521 delete fCursorBitmap; 522 fCursorBitmap = bitmap; 523 524 Invalidate(fCursorFrame); 525 526 BRect bounds = fCursorBitmap->Bounds(); 527 fCursorFrame.right = fCursorFrame.left 528 + bounds.IntegerWidth() + 1; 529 fCursorFrame.bottom = fCursorFrame.bottom 530 + bounds.IntegerHeight() + 1; 531 532 fCursorFrame.OffsetBy(oldHotSpot - cursorHotSpot); 533 534 Invalidate(fCursorFrame); 535 continue; 536 } 537 538 case RP_SET_CURSOR_VISIBLE: 539 { 540 bool wasVisible = fCursorVisible; 541 message.Read(fCursorVisible); 542 if (wasVisible != fCursorVisible) 543 Invalidate(fCursorFrame); 544 continue; 545 } 546 547 case RP_MOVE_CURSOR_TO: 548 { 549 BPoint position; 550 message.Read(position); 551 552 if (fCursorVisible) 553 Invalidate(fCursorFrame); 554 555 fCursorFrame.OffsetTo(position - cursorHotSpot); 556 557 Invalidate(fCursorFrame); 558 continue; 559 } 560 561 case RP_INVALIDATE_RECT: 562 { 563 BRect rect; 564 if (message.Read(rect) != B_OK) 565 continue; 566 567 Invalidate(rect); 568 continue; 569 } 570 571 case RP_INVALIDATE_REGION: 572 { 573 BRegion region; 574 if (message.ReadRegion(region) != B_OK) 575 continue; 576 577 Invalidate(®ion); 578 continue; 579 } 580 581 case RP_FILL_REGION_COLOR_NO_CLIPPING: 582 { 583 BRegion region; 584 rgb_color color; 585 586 message.ReadRegion(region); 587 if (message.Read(color) != B_OK) 588 continue; 589 590 fOffscreen->LockLooper(); 591 fOffscreen->SetHighColor(color); 592 fOffscreen->FillRegion(®ion); 593 fOffscreen->UnlockLooper(); 594 Invalidate(®ion); 595 continue; 596 } 597 598 case RP_COPY_RECT_NO_CLIPPING: 599 { 600 int32 xOffset, yOffset; 601 BRect rect; 602 603 message.Read(xOffset); 604 message.Read(yOffset); 605 if (message.Read(rect) != B_OK) 606 continue; 607 608 BRect dest = rect.OffsetByCopy(xOffset, yOffset); 609 fOffscreen->LockLooper(); 610 fOffscreen->CopyBits(rect, dest); 611 fOffscreen->UnlockLooper(); 612 continue; 613 } 614 } 615 616 uint32 token; 617 message.Read(token); 618 619 engine_state *state = _FindState(token); 620 if (state == NULL) { 621 TRACE_ERROR("didn't find state for token %lu\n", token); 622 continue; 623 } 624 625 BView *offscreen = state->view; 626 ::pattern &pattern = state->pattern; 627 BRegion &clippingRegion = state->clipping_region; 628 float &penSize = state->pen_size; 629 bool &syncDrawing = state->sync_drawing; 630 BRegion invalidRegion; 631 632 BAutolock offscreenLocker(offscreen->Looper()); 633 if (!offscreenLocker.IsLocked()) 634 break; 635 636 switch (code) { 637 case RP_ENABLE_SYNC_DRAWING: 638 syncDrawing = true; 639 continue; 640 641 case RP_DISABLE_SYNC_DRAWING: 642 syncDrawing = false; 643 continue; 644 645 case RP_SET_OFFSETS: 646 { 647 int32 xOffset, yOffset; 648 message.Read(xOffset); 649 if (message.Read(yOffset) != B_OK) 650 continue; 651 652 offscreen->MovePenTo(xOffset, yOffset); 653 break; 654 } 655 656 case RP_SET_HIGH_COLOR: 657 case RP_SET_LOW_COLOR: 658 { 659 rgb_color color; 660 if (message.Read(color) != B_OK) 661 continue; 662 663 if (code == RP_SET_HIGH_COLOR) 664 offscreen->SetHighColor(color); 665 else 666 offscreen->SetLowColor(color); 667 668 break; 669 } 670 671 case RP_SET_PEN_SIZE: 672 { 673 float newPenSize; 674 if (message.Read(newPenSize) != B_OK) 675 continue; 676 677 offscreen->SetPenSize(newPenSize); 678 penSize = newPenSize / 2; 679 break; 680 } 681 682 case RP_SET_STROKE_MODE: 683 { 684 cap_mode capMode; 685 join_mode joinMode; 686 float miterLimit; 687 688 message.Read(capMode); 689 message.Read(joinMode); 690 if (message.Read(miterLimit) != B_OK) 691 continue; 692 693 offscreen->SetLineMode(capMode, joinMode, miterLimit); 694 break; 695 } 696 697 case RP_SET_BLENDING_MODE: 698 { 699 source_alpha sourceAlpha; 700 alpha_function alphaFunction; 701 702 message.Read(sourceAlpha); 703 if (message.Read(alphaFunction) != B_OK) 704 continue; 705 706 offscreen->SetBlendingMode(sourceAlpha, alphaFunction); 707 break; 708 } 709 710 case RP_SET_PATTERN: 711 { 712 if (message.Read(pattern) != B_OK) 713 continue; 714 break; 715 } 716 717 case RP_SET_DRAWING_MODE: 718 { 719 drawing_mode drawingMode; 720 if (message.Read(drawingMode) != B_OK) 721 continue; 722 723 offscreen->SetDrawingMode(drawingMode); 724 break; 725 } 726 727 case RP_SET_FONT: 728 { 729 BFont font; 730 if (message.ReadFontState(font) != B_OK) 731 continue; 732 733 offscreen->SetFont(&font); 734 break; 735 } 736 737 case RP_CONSTRAIN_CLIPPING_REGION: 738 { 739 if (message.ReadRegion(clippingRegion) != B_OK) 740 continue; 741 742 offscreen->ConstrainClippingRegion(&clippingRegion); 743 break; 744 } 745 746 case RP_INVERT_RECT: 747 { 748 BRect rect; 749 if (message.Read(rect) != B_OK) 750 continue; 751 752 offscreen->InvertRect(rect); 753 invalidRegion.Include(rect); 754 break; 755 } 756 757 case RP_DRAW_BITMAP: 758 { 759 BBitmap *bitmap; 760 BRect bitmapRect, viewRect; 761 uint32 options; 762 763 message.Read(bitmapRect); 764 message.Read(viewRect); 765 message.Read(options); 766 if (message.ReadBitmap(&bitmap) != B_OK || bitmap == NULL) 767 continue; 768 769 offscreen->DrawBitmap(bitmap, bitmapRect, viewRect, options); 770 invalidRegion.Include(viewRect); 771 delete bitmap; 772 break; 773 } 774 775 case RP_STROKE_ARC: 776 case RP_FILL_ARC: 777 case RP_FILL_ARC_GRADIENT: 778 { 779 BRect rect; 780 float angle, span; 781 782 message.Read(rect); 783 message.Read(angle); 784 if (message.Read(span) != B_OK) 785 continue; 786 787 if (code == RP_STROKE_ARC) { 788 offscreen->StrokeArc(rect, angle, span, pattern); 789 rect.InsetBy(-penSize, -penSize); 790 } else if (code == RP_FILL_ARC) 791 offscreen->FillArc(rect, angle, span, pattern); 792 else { 793 BGradient *gradient; 794 if (message.ReadGradient(&gradient) != B_OK) 795 continue; 796 797 offscreen->FillArc(rect, angle, span, *gradient); 798 delete gradient; 799 } 800 801 invalidRegion.Include(rect); 802 break; 803 } 804 805 case RP_STROKE_BEZIER: 806 case RP_FILL_BEZIER: 807 case RP_FILL_BEZIER_GRADIENT: 808 { 809 BPoint points[4]; 810 if (message.ReadList(points, 4) != B_OK) 811 continue; 812 813 BRect bounds = _BuildInvalidateRect(points, 4); 814 if (code == RP_STROKE_BEZIER) { 815 offscreen->StrokeBezier(points, pattern); 816 bounds.InsetBy(-penSize, -penSize); 817 } else if (code == RP_FILL_BEZIER) 818 offscreen->FillBezier(points, pattern); 819 else { 820 BGradient *gradient; 821 if (message.ReadGradient(&gradient) != B_OK) 822 continue; 823 824 offscreen->FillBezier(points, *gradient); 825 delete gradient; 826 } 827 828 invalidRegion.Include(bounds); 829 break; 830 } 831 832 case RP_STROKE_ELLIPSE: 833 case RP_FILL_ELLIPSE: 834 case RP_FILL_ELLIPSE_GRADIENT: 835 { 836 BRect rect; 837 if (message.Read(rect) != B_OK) 838 continue; 839 840 if (code == RP_STROKE_ELLIPSE) { 841 offscreen->StrokeEllipse(rect, pattern); 842 rect.InsetBy(-penSize, -penSize); 843 } else if (code == RP_FILL_ELLIPSE) 844 offscreen->FillEllipse(rect, pattern); 845 else { 846 BGradient *gradient; 847 if (message.ReadGradient(&gradient) != B_OK) 848 continue; 849 850 offscreen->FillEllipse(rect, *gradient); 851 delete gradient; 852 } 853 854 invalidRegion.Include(rect); 855 break; 856 } 857 858 case RP_STROKE_POLYGON: 859 case RP_FILL_POLYGON: 860 case RP_FILL_POLYGON_GRADIENT: 861 { 862 BRect bounds; 863 bool closed; 864 int32 numPoints; 865 866 message.Read(bounds); 867 message.Read(closed); 868 if (message.Read(numPoints) != B_OK) 869 continue; 870 871 BPoint points[numPoints]; 872 for (int32 i = 0; i < numPoints; i++) 873 message.Read(points[i]); 874 875 if (code == RP_STROKE_POLYGON) { 876 offscreen->StrokePolygon(points, numPoints, bounds, closed, 877 pattern); 878 bounds.InsetBy(-penSize, -penSize); 879 } else if (code == RP_FILL_POLYGON) 880 offscreen->FillPolygon(points, numPoints, bounds, pattern); 881 else { 882 BGradient *gradient; 883 if (message.ReadGradient(&gradient) != B_OK) 884 continue; 885 886 offscreen->FillPolygon(points, numPoints, bounds, 887 *gradient); 888 delete gradient; 889 } 890 891 invalidRegion.Include(bounds); 892 break; 893 } 894 895 case RP_STROKE_RECT: 896 case RP_FILL_RECT: 897 case RP_FILL_RECT_GRADIENT: 898 { 899 BRect rect; 900 if (message.Read(rect) != B_OK) 901 continue; 902 903 if (code == RP_STROKE_RECT) { 904 offscreen->StrokeRect(rect, pattern); 905 rect.InsetBy(-penSize, -penSize); 906 } else if (code == RP_FILL_RECT) 907 offscreen->FillRect(rect, pattern); 908 else { 909 BGradient *gradient; 910 if (message.ReadGradient(&gradient) != B_OK) 911 continue; 912 913 offscreen->FillRect(rect, *gradient); 914 delete gradient; 915 } 916 917 invalidRegion.Include(rect); 918 break; 919 } 920 921 case RP_STROKE_ROUND_RECT: 922 case RP_FILL_ROUND_RECT: 923 case RP_FILL_ROUND_RECT_GRADIENT: 924 { 925 BRect rect; 926 float xRadius, yRadius; 927 928 message.Read(rect); 929 message.Read(xRadius); 930 if (message.Read(yRadius) != B_OK) 931 continue; 932 933 if (code == RP_STROKE_ROUND_RECT) { 934 offscreen->StrokeRoundRect(rect, xRadius, yRadius, 935 pattern); 936 rect.InsetBy(-penSize, -penSize); 937 } else if (code == RP_FILL_ROUND_RECT) 938 offscreen->FillRoundRect(rect, xRadius, yRadius, pattern); 939 else { 940 BGradient *gradient; 941 if (message.ReadGradient(&gradient) != B_OK) 942 continue; 943 944 offscreen->FillRoundRect(rect, xRadius, yRadius, 945 *gradient); 946 delete gradient; 947 } 948 949 invalidRegion.Include(rect); 950 break; 951 } 952 953 case RP_STROKE_SHAPE: 954 case RP_FILL_SHAPE: 955 case RP_FILL_SHAPE_GRADIENT: 956 { 957 BRect bounds; 958 int32 opCount, pointCount; 959 960 message.Read(bounds); 961 if (message.Read(opCount) != B_OK) 962 continue; 963 964 BMessage archive; 965 for (int32 i = 0; i < opCount; i++) { 966 int32 op; 967 message.Read(op); 968 archive.AddInt32("ops", op); 969 } 970 971 if (message.Read(pointCount) != B_OK) 972 continue; 973 974 for (int32 i = 0; i < pointCount; i++) { 975 BPoint point; 976 message.Read(point); 977 archive.AddPoint("pts", point); 978 } 979 980 // the shape is in absolute coordinates 981 offscreen->MovePenTo(0, 0); 982 983 BShape shape(&archive); 984 if (code == RP_STROKE_SHAPE) { 985 offscreen->StrokeShape(&shape, pattern); 986 bounds.InsetBy(-penSize, -penSize); 987 } else if (code == RP_FILL_SHAPE) 988 offscreen->FillShape(&shape, pattern); 989 else { 990 BGradient *gradient; 991 if (message.ReadGradient(&gradient) != B_OK) 992 continue; 993 994 offscreen->FillShape(&shape, *gradient); 995 delete gradient; 996 } 997 998 invalidRegion.Include(bounds); 999 break; 1000 } 1001 1002 case RP_STROKE_TRIANGLE: 1003 case RP_FILL_TRIANGLE: 1004 case RP_FILL_TRIANGLE_GRADIENT: 1005 { 1006 BRect bounds; 1007 BPoint points[3]; 1008 1009 message.ReadList(points, 3); 1010 if (message.Read(bounds) != B_OK) 1011 continue; 1012 1013 if (code == RP_STROKE_TRIANGLE) { 1014 offscreen->StrokeTriangle(points[0], points[1], points[2], 1015 bounds, pattern); 1016 bounds.InsetBy(-penSize, -penSize); 1017 } else if (code == RP_FILL_TRIANGLE) { 1018 offscreen->FillTriangle(points[0], points[1], points[2], 1019 bounds, pattern); 1020 } else { 1021 BGradient *gradient; 1022 if (message.ReadGradient(&gradient) != B_OK) 1023 continue; 1024 1025 offscreen->FillTriangle(points[0], points[1], points[2], 1026 bounds, *gradient); 1027 delete gradient; 1028 } 1029 1030 invalidRegion.Include(bounds); 1031 break; 1032 } 1033 1034 case RP_STROKE_LINE: 1035 { 1036 BPoint points[2]; 1037 if (message.ReadList(points, 2) != B_OK) 1038 continue; 1039 1040 offscreen->StrokeLine(points[0], points[1], pattern); 1041 1042 BRect bounds = _BuildInvalidateRect(points, 2); 1043 invalidRegion.Include(bounds.InsetBySelf(-penSize, -penSize)); 1044 break; 1045 } 1046 1047 case RP_STROKE_LINE_ARRAY: 1048 { 1049 int32 numLines; 1050 if (message.Read(numLines) != B_OK) 1051 continue; 1052 1053 BRect bounds; 1054 offscreen->BeginLineArray(numLines); 1055 for (int32 i = 0; i < numLines; i++) { 1056 rgb_color color; 1057 BPoint start, end; 1058 message.ReadArrayLine(start, end, color); 1059 offscreen->AddLine(start, end, color); 1060 1061 bounds.left = min_c(bounds.left, min_c(start.x, end.x)); 1062 bounds.top = min_c(bounds.top, min_c(start.y, end.y)); 1063 bounds.right = max_c(bounds.right, max_c(start.x, end.x)); 1064 bounds.bottom = max_c(bounds.bottom, max_c(start.y, end.y)); 1065 } 1066 1067 offscreen->EndLineArray(); 1068 invalidRegion.Include(bounds); 1069 break; 1070 } 1071 1072 case RP_FILL_REGION: 1073 case RP_FILL_REGION_GRADIENT: 1074 { 1075 BRegion region; 1076 if (message.ReadRegion(region) != B_OK) 1077 continue; 1078 1079 if (code == RP_FILL_REGION) 1080 offscreen->FillRegion(®ion, pattern); 1081 else { 1082 BGradient *gradient; 1083 if (message.ReadGradient(&gradient) != B_OK) 1084 continue; 1085 1086 offscreen->FillRegion(®ion, *gradient); 1087 delete gradient; 1088 } 1089 1090 invalidRegion.Include(®ion); 1091 break; 1092 } 1093 1094 case RP_STROKE_POINT_COLOR: 1095 { 1096 BPoint point; 1097 rgb_color color; 1098 1099 message.Read(point); 1100 if (message.Read(color) != B_OK) 1101 continue; 1102 1103 rgb_color oldColor = offscreen->HighColor(); 1104 offscreen->SetHighColor(color); 1105 offscreen->StrokeLine(point, point); 1106 offscreen->SetHighColor(oldColor); 1107 1108 invalidRegion.Include( 1109 BRect(point, point).InsetBySelf(-penSize, -penSize)); 1110 break; 1111 } 1112 1113 case RP_STROKE_LINE_1PX_COLOR: 1114 { 1115 BPoint points[2]; 1116 rgb_color color; 1117 1118 message.ReadList(points, 2); 1119 if (message.Read(color) != B_OK) 1120 continue; 1121 1122 float oldSize = offscreen->PenSize(); 1123 rgb_color oldColor = offscreen->HighColor(); 1124 drawing_mode oldMode = offscreen->DrawingMode(); 1125 offscreen->SetPenSize(1); 1126 offscreen->SetHighColor(color); 1127 offscreen->SetDrawingMode(B_OP_OVER); 1128 1129 offscreen->StrokeLine(points[0], points[1]); 1130 1131 offscreen->SetDrawingMode(oldMode); 1132 offscreen->SetHighColor(oldColor); 1133 offscreen->SetPenSize(oldSize); 1134 1135 invalidRegion.Include(_BuildInvalidateRect(points, 2)); 1136 break; 1137 } 1138 1139 case RP_STROKE_RECT_1PX_COLOR: 1140 case RP_FILL_RECT_COLOR: 1141 { 1142 BRect rect; 1143 rgb_color color; 1144 1145 message.Read(rect); 1146 if (message.Read(color) != B_OK) 1147 continue; 1148 1149 rgb_color oldColor = offscreen->HighColor(); 1150 offscreen->SetHighColor(color); 1151 1152 if (code == RP_STROKE_RECT_1PX_COLOR) { 1153 float oldSize = PenSize(); 1154 offscreen->SetPenSize(1); 1155 offscreen->StrokeRect(rect); 1156 offscreen->SetPenSize(oldSize); 1157 } else 1158 offscreen->FillRect(rect); 1159 1160 offscreen->SetHighColor(oldColor); 1161 invalidRegion.Include(rect); 1162 break; 1163 } 1164 1165 case RP_DRAW_STRING: 1166 { 1167 BPoint point; 1168 size_t length; 1169 char *string; 1170 bool hasDelta; 1171 1172 message.Read(point); 1173 message.ReadString(&string, length); 1174 if (message.Read(hasDelta) != B_OK) { 1175 free(string); 1176 continue; 1177 } 1178 1179 if (hasDelta) { 1180 escapement_delta delta[length]; 1181 message.ReadList(delta, length); 1182 offscreen->DrawString(string, point, delta); 1183 } else 1184 offscreen->DrawString(string, point); 1185 1186 free(string); 1187 reply.Start(RP_DRAW_STRING_RESULT); 1188 reply.Add(token); 1189 reply.Add(offscreen->PenLocation()); 1190 reply.Flush(); 1191 1192 font_height height; 1193 offscreen->GetFontHeight(&height); 1194 1195 BRect bounds(point, offscreen->PenLocation()); 1196 bounds.top -= height.ascent; 1197 bounds.bottom += height.descent; 1198 invalidRegion.Include(bounds); 1199 break; 1200 } 1201 1202 case RP_READ_BITMAP: 1203 { 1204 BRect bounds; 1205 bool drawCursor; 1206 1207 message.Read(bounds); 1208 if (message.Read(drawCursor) != B_OK) 1209 continue; 1210 1211 // TODO: support the drawCursor flag 1212 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_RGB32); 1213 bitmap.ImportBits(fOffscreenBitmap, bounds.LeftTop(), 1214 BPoint(0, 0), bounds.IntegerWidth() + 1, 1215 bounds.IntegerHeight() + 1); 1216 1217 reply.Start(RP_READ_BITMAP_RESULT); 1218 reply.Add(token); 1219 reply.AddBitmap(&bitmap); 1220 reply.Flush(); 1221 break; 1222 } 1223 1224 default: 1225 TRACE_ERROR("unknown protocol code: %u\n", code); 1226 break; 1227 } 1228 1229 if (syncDrawing) { 1230 offscreen->Sync(); 1231 Invalidate(&invalidRegion); 1232 } 1233 } 1234 } 1235 1236 1237 BRect 1238 RemoteView::_BuildInvalidateRect(BPoint *points, int32 pointCount) 1239 { 1240 BRect bounds(1000000, 1000000, 0, 0); 1241 for (int32 i = 0; i < pointCount; i++) { 1242 bounds.left = min_c(bounds.left, points[i].x); 1243 bounds.top = min_c(bounds.top, points[i].y); 1244 bounds.right = max_c(bounds.right, points[i].x); 1245 bounds.bottom = max_c(bounds.bottom, points[i].y); 1246 } 1247 1248 return bounds; 1249 } 1250