2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 #include <X11/Xutil.h>
23 #include <freerdp/gdi/gdi.h>
24 #include <freerdp/codec/rfx.h>
25 #include <freerdp/codec/nsc.h>
26 #include <freerdp/constants.h>
27 #include <freerdp/utils/memory.h>
28 #include <freerdp/codec/color.h>
29 #include <freerdp/codec/bitmap.h>
33 static const uint8 xf_rop2_table[] =
38 GXandInverted, /* DPna */
39 GXcopyInverted, /* Pn */
40 GXandReverse, /* PDna */
47 GXorInverted, /* DPno */
49 GXorReverse, /* PDno */
54 boolean xf_set_rop2(xfInfo* xfi, int rop2)
56 if ((rop2 < 0x01) || (rop2 > 0x10))
58 printf("Unsupported ROP2: %d\n", rop2);
62 XSetFunction(xfi->display, xfi->gc, xf_rop2_table[rop2]);
66 boolean xf_set_rop3(xfInfo* xfi, int rop3)
81 function = GXandInverted;
85 function = GXcopyInverted;
93 function = GXandInverted;
97 function = GXcopyInverted;
101 function = GXandReverse;
105 function = GXandReverse;
149 function = GXorInverted;
153 function = GXorInverted;
161 function = GXorReverse;
173 function = GXorReverse;
190 printf("Unsupported ROP3: 0x%08X\n", rop3);
191 XSetFunction(xfi->display, xfi->gc, GXclear);
195 XSetFunction(xfi->display, xfi->gc, function);
200 Pixmap xf_brush_new(xfInfo* xfi, int width, int height, int bpp, uint8* data)
206 bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, xfi->depth);
210 GC gc; // FIXME, should cache
212 cdata = freerdp_image_convert(data, NULL, width, height, bpp, xfi->bpp, xfi->clrconv);
213 image = XCreateImage(xfi->display, xfi->visual, xfi->depth,
214 ZPixmap, 0, (char*) cdata, width, height, xfi->scanline_pad, 0);
216 gc = XCreateGC(xfi->display, xfi->drawable, 0, NULL);
217 XPutImage(xfi->display, bitmap, gc, image, 0, 0, 0, 0, width, height);
222 XFreeGC(xfi->display, gc);
228 Pixmap xf_mono_bitmap_new(xfInfo* xfi, int width, int height, uint8* data)
234 scanline = (width + 7) / 8;
236 bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, 1);
238 image = XCreateImage(xfi->display, xfi->visual, 1,
239 ZPixmap, 0, (char*) data, width, height, 8, scanline);
241 XPutImage(xfi->display, bitmap, xfi->gc_mono, image, 0, 0, 0, 0, width, height);
247 Pixmap xf_glyph_new(xfInfo* xfi, int width, int height, uint8* data)
253 scanline = (width + 7) / 8;
255 bitmap = XCreatePixmap(xfi->display, xfi->drawable, width, height, 1);
257 image = XCreateImage(xfi->display, xfi->visual, 1,
258 ZPixmap, 0, (char*) data, width, height, 8, scanline);
260 image->byte_order = MSBFirst;
261 image->bitmap_bit_order = MSBFirst;
264 XPutImage(xfi->display, bitmap, xfi->gc_mono, image, 0, 0, 0, 0, width, height);
270 void xf_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette)
272 xfInfo* xfi = ((xfContext*) context)->xfi;
273 xfi->clrconv->palette->count = palette->number;
274 xfi->clrconv->palette->entries = palette->entries;
277 void xf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
280 xfInfo* xfi = ((xfContext*) context)->xfi;
284 clip.x = bounds->left;
285 clip.y = bounds->top;
286 clip.width = bounds->right - bounds->left + 1;
287 clip.height = bounds->bottom - bounds->top + 1;
288 XSetClipRectangles(xfi->display, xfi->gc, 0, 0, &clip, 1, YXBanded);
292 XSetClipMask(xfi->display, xfi->gc, None);
296 void xf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
298 xfInfo* xfi = ((xfContext*) context)->xfi;
300 xf_set_rop3(xfi, gdi_rop3_code(dstblt->bRop));
302 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
303 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
304 dstblt->nLeftRect, dstblt->nTopRect,
305 dstblt->nWidth, dstblt->nHeight);
307 if (xfi->drawing == xfi->primary)
309 if (xfi->remote_app != true)
311 XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
312 dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
315 gdi_InvalidateRegion(xfi->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
317 XSetFunction(xfi->display, xfi->gc, GXcopy);
320 void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
326 xfInfo* xfi = ((xfContext*) context)->xfi;
328 brush = &patblt->brush;
329 xf_set_rop3(xfi, gdi_rop3_code(patblt->bRop));
331 foreColor = freerdp_color_convert_rgb(patblt->foreColor, xfi->srcBpp, 32, xfi->clrconv);
332 backColor = freerdp_color_convert_rgb(patblt->backColor, xfi->srcBpp, 32, xfi->clrconv);
334 if (brush->style == GDI_BS_SOLID)
336 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
337 XSetForeground(xfi->display, xfi->gc, foreColor);
339 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
340 patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
342 else if (brush->style == GDI_BS_PATTERN)
346 pattern = xf_brush_new(xfi, 8, 8, brush->bpp, brush->data);
348 XSetFillStyle(xfi->display, xfi->gc, FillTiled);
349 XSetTile(xfi->display, xfi->gc, pattern);
350 XSetTSOrigin(xfi->display, xfi->gc, brush->x, brush->y);
352 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
353 patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
355 XSetTile(xfi->display, xfi->gc, xfi->primary);
357 XFreePixmap(xfi->display, pattern);
361 pattern = xf_mono_bitmap_new(xfi, 8, 8, brush->data);
363 XSetForeground(xfi->display, xfi->gc, backColor);
364 XSetBackground(xfi->display, xfi->gc, foreColor);
365 XSetFillStyle(xfi->display, xfi->gc, FillOpaqueStippled);
366 XSetStipple(xfi->display, xfi->gc, pattern);
367 XSetTSOrigin(xfi->display, xfi->gc, brush->x, brush->y);
369 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
370 patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
372 XFreePixmap(xfi->display, pattern);
377 printf("unimplemented brush style:%d\n", brush->style);
380 if (xfi->drawing == xfi->primary)
382 XSetFunction(xfi->display, xfi->gc, GXcopy);
384 if (xfi->remote_app != true)
386 XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, patblt->nLeftRect, patblt->nTopRect,
387 patblt->nWidth, patblt->nHeight, patblt->nLeftRect, patblt->nTopRect);
390 gdi_InvalidateRegion(xfi->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
393 XSetFunction(xfi->display, xfi->gc, GXcopy);
396 void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
398 xfInfo* xfi = ((xfContext*) context)->xfi;
400 xf_set_rop3(xfi, gdi_rop3_code(scrblt->bRop));
402 XCopyArea(xfi->display, xfi->primary, xfi->drawing, xfi->gc, scrblt->nXSrc, scrblt->nYSrc,
403 scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect);
405 if (xfi->drawing == xfi->primary)
407 if (xfi->remote_app != true)
411 XCopyArea(xfi->display, xfi->drawable, xfi->drawable, xfi->gc,
412 scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight,
413 scrblt->nLeftRect, scrblt->nTopRect);
417 XSetFunction(xfi->display, xfi->gc, GXcopy);
418 XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
419 scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight,
420 scrblt->nLeftRect, scrblt->nTopRect);
424 gdi_InvalidateRegion(xfi->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
427 XSetFunction(xfi->display, xfi->gc, GXcopy);
430 void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
433 xfInfo* xfi = ((xfContext*) context)->xfi;
435 color = freerdp_color_convert_var(opaque_rect->color, xfi->srcBpp, 32, xfi->clrconv);
437 XSetFunction(xfi->display, xfi->gc, GXcopy);
438 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
439 XSetForeground(xfi->display, xfi->gc, color);
441 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
442 opaque_rect->nLeftRect, opaque_rect->nTopRect,
443 opaque_rect->nWidth, opaque_rect->nHeight);
445 if (xfi->drawing == xfi->primary)
447 if (xfi->remote_app != true)
449 XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
450 opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight);
453 gdi_InvalidateRegion(xfi->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect,
454 opaque_rect->nWidth, opaque_rect->nHeight);
458 void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
462 DELTA_RECT* rectangle;
463 xfInfo* xfi = ((xfContext*) context)->xfi;
465 color = freerdp_color_convert_var(multi_opaque_rect->color, xfi->srcBpp, 32, xfi->clrconv);
467 XSetFunction(xfi->display, xfi->gc, GXcopy);
468 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
469 XSetForeground(xfi->display, xfi->gc, color);
471 for (i = 1; i < multi_opaque_rect->numRectangles + 1; i++)
473 rectangle = &multi_opaque_rect->rectangles[i];
475 XFillRectangle(xfi->display, xfi->drawing, xfi->gc,
476 rectangle->left, rectangle->top,
477 rectangle->width, rectangle->height);
479 if (xfi->drawing == xfi->primary)
481 if (xfi->remote_app != true)
483 XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
484 rectangle->left, rectangle->top, rectangle->width, rectangle->height);
487 gdi_InvalidateRegion(xfi->hdc, rectangle->left, rectangle->top, rectangle->width, rectangle->height);
492 void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
495 xfInfo* xfi = ((xfContext*) context)->xfi;
497 xf_set_rop2(xfi, line_to->bRop2);
498 color = freerdp_color_convert_rgb(line_to->penColor, xfi->srcBpp, 32, xfi->clrconv);
500 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
501 XSetForeground(xfi->display, xfi->gc, color);
503 XDrawLine(xfi->display, xfi->drawing, xfi->gc,
504 line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd);
506 if (xfi->drawing == xfi->primary)
510 if (xfi->remote_app != true)
512 XDrawLine(xfi->display, xfi->drawable, xfi->gc,
513 line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd);
516 width = line_to->nXStart - line_to->nXEnd;
517 height = line_to->nYStart - line_to->nYEnd;
525 gdi_InvalidateRegion(xfi->hdc, line_to->nXStart, line_to->nYStart, width, height);
529 XSetFunction(xfi->display, xfi->gc, GXcopy);
532 void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
542 xfInfo* xfi = ((xfContext*) context)->xfi;
544 xf_set_rop2(xfi, polyline->bRop2);
545 color = freerdp_color_convert_rgb(polyline->penColor, xfi->srcBpp, 32, xfi->clrconv);
547 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
548 XSetForeground(xfi->display, xfi->gc, color);
550 npoints = polyline->numPoints + 1;
551 points = xmalloc(sizeof(XPoint) * npoints);
553 points[0].x = polyline->xStart;
554 points[0].y = polyline->yStart;
556 for (i = 0; i < polyline->numPoints; i++)
558 points[i + 1].x = polyline->points[i].x;
559 points[i + 1].y = polyline->points[i].y;
562 XDrawLines(xfi->display, xfi->drawing, xfi->gc, points, npoints, CoordModePrevious);
564 if (xfi->drawing == xfi->primary)
566 if (xfi->remote_app != true)
567 XDrawLines(xfi->display, xfi->drawable, xfi->gc, points, npoints, CoordModePrevious);
572 for (i = 1; i < npoints; i++)
574 x2 = points[i].x + x1;
575 y2 = points[i].y + y1;
577 x = (x2 < x1) ? x2 : x1;
578 width = (x2 > x1) ? x2 - x1 : x1 - x2;
580 y = (y2 < y1) ? y2 : y1;
581 height = (y2 > y1) ? y2 - y1 : y1 - y2;
586 gdi_InvalidateRegion(xfi->hdc, x, y, width, height);
590 XSetFunction(xfi->display, xfi->gc, GXcopy);
594 void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
597 xfInfo* xfi = ((xfContext*) context)->xfi;
599 bitmap = (xfBitmap*) memblt->bitmap;
600 xf_set_rop3(xfi, gdi_rop3_code(memblt->bRop));
602 XCopyArea(xfi->display, bitmap->pixmap, xfi->drawing, xfi->gc,
603 memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight,
604 memblt->nLeftRect, memblt->nTopRect);
606 if (xfi->drawing == xfi->primary)
608 if (xfi->remote_app != true)
610 XCopyArea(xfi->display, bitmap->pixmap, xfi->drawable, xfi->gc,
611 memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight,
612 memblt->nLeftRect, memblt->nTopRect);
615 gdi_InvalidateRegion(xfi->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight);
618 XSetFunction(xfi->display, xfi->gc, GXcopy);
621 void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
626 void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker)
631 void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command)
635 RFX_MESSAGE* message;
636 xfInfo* xfi = ((xfContext*) context)->xfi;
637 RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) xfi->rfx_context;
638 NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) xfi->nsc_context;
640 if (surface_bits_command->codecID == CODEC_ID_REMOTEFX)
642 message = rfx_process_message(rfx_context,
643 surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
645 XSetFunction(xfi->display, xfi->gc, GXcopy);
646 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
648 XSetClipRectangles(xfi->display, xfi->gc,
649 surface_bits_command->destLeft, surface_bits_command->destTop,
650 (XRectangle*) message->rects, message->num_rects, YXBanded);
652 /* Draw the tiles to primary surface, each is 64x64. */
653 for (i = 0; i < message->num_tiles; i++)
655 image = XCreateImage(xfi->display, xfi->visual, 24, ZPixmap, 0,
656 (char*) message->tiles[i]->data, 64, 64, 32, 0);
658 tx = message->tiles[i]->x + surface_bits_command->destLeft;
659 ty = message->tiles[i]->y + surface_bits_command->destTop;
661 XPutImage(xfi->display, xfi->primary, xfi->gc, image, 0, 0, tx, ty, 64, 64);
665 /* Copy the updated region from backstore to the window. */
666 for (i = 0; i < message->num_rects; i++)
668 tx = message->rects[i].x + surface_bits_command->destLeft;
669 ty = message->rects[i].y + surface_bits_command->destTop;
671 if (xfi->remote_app != true)
673 XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
674 tx, ty, message->rects[i].width, message->rects[i].height, tx, ty);
677 gdi_InvalidateRegion(xfi->hdc, tx, ty, message->rects[i].width, message->rects[i].height);
680 XSetClipMask(xfi->display, xfi->gc, None);
681 rfx_message_free(rfx_context, message);
683 else if (surface_bits_command->codecID == CODEC_ID_NSCODEC)
685 nsc_context->width = surface_bits_command->width;
686 nsc_context->height = surface_bits_command->height;
687 nsc_process_message(nsc_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
688 XSetFunction(xfi->display, xfi->gc, GXcopy);
689 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
691 xfi->bmp_codec_nsc = (uint8*) xrealloc(xfi->bmp_codec_nsc,
692 surface_bits_command->width * surface_bits_command->height * 4);
694 freerdp_image_flip(nsc_context->bmpdata, xfi->bmp_codec_nsc,
695 surface_bits_command->width, surface_bits_command->height, 32);
697 image = XCreateImage(xfi->display, xfi->visual, 24, ZPixmap, 0,
698 (char*) xfi->bmp_codec_nsc, surface_bits_command->width, surface_bits_command->height, 32, 0);
700 XPutImage(xfi->display, xfi->primary, xfi->gc, image, 0, 0,
701 surface_bits_command->destLeft, surface_bits_command->destTop,
702 surface_bits_command->width, surface_bits_command->height);
704 if (xfi->remote_app != true)
706 XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
707 surface_bits_command->destLeft, surface_bits_command->destTop,
708 surface_bits_command->width, surface_bits_command->height,
709 surface_bits_command->destLeft, surface_bits_command->destTop);
712 gdi_InvalidateRegion(xfi->hdc, surface_bits_command->destLeft, surface_bits_command->destTop,
713 surface_bits_command->width, surface_bits_command->height);
715 XSetClipMask(xfi->display, xfi->gc, None);
716 nsc_context_destroy(nsc_context);
718 else if (surface_bits_command->codecID == CODEC_ID_NONE)
720 XSetFunction(xfi->display, xfi->gc, GXcopy);
721 XSetFillStyle(xfi->display, xfi->gc, FillSolid);
723 xfi->bmp_codec_none = (uint8*) xrealloc(xfi->bmp_codec_none,
724 surface_bits_command->width * surface_bits_command->height * 4);
726 freerdp_image_flip(surface_bits_command->bitmapData, xfi->bmp_codec_none,
727 surface_bits_command->width, surface_bits_command->height, 32);
729 image = XCreateImage(xfi->display, xfi->visual, 24, ZPixmap, 0,
730 (char*) xfi->bmp_codec_none, surface_bits_command->width, surface_bits_command->height, 32, 0);
732 XPutImage(xfi->display, xfi->primary, xfi->gc, image, 0, 0,
733 surface_bits_command->destLeft, surface_bits_command->destTop,
734 surface_bits_command->width, surface_bits_command->height);
736 if (xfi->remote_app != true)
738 XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc,
739 surface_bits_command->destLeft, surface_bits_command->destTop,
740 surface_bits_command->width, surface_bits_command->height,
741 surface_bits_command->destLeft, surface_bits_command->destTop);
744 gdi_InvalidateRegion(xfi->hdc, surface_bits_command->destLeft, surface_bits_command->destTop,
745 surface_bits_command->width, surface_bits_command->height);
747 XSetClipMask(xfi->display, xfi->gc, None);
751 printf("Unsupported codecID %d\n", surface_bits_command->codecID);
755 void xf_gdi_register_update_callbacks(rdpUpdate* update)
757 rdpPrimaryUpdate* primary = update->primary;
759 update->Palette = xf_gdi_palette_update;
760 update->SetBounds = xf_gdi_set_bounds;
762 primary->DstBlt = xf_gdi_dstblt;
763 primary->PatBlt = xf_gdi_patblt;
764 primary->ScrBlt = xf_gdi_scrblt;
765 primary->OpaqueRect = xf_gdi_opaque_rect;
766 primary->DrawNineGrid = NULL;
767 primary->MultiDstBlt = NULL;
768 primary->MultiPatBlt = NULL;
769 primary->MultiScrBlt = NULL;
770 primary->MultiOpaqueRect = xf_gdi_multi_opaque_rect;
771 primary->MultiDrawNineGrid = NULL;
772 primary->LineTo = xf_gdi_line_to;
773 primary->Polyline = xf_gdi_polyline;
774 primary->MemBlt = xf_gdi_memblt;
775 primary->Mem3Blt = xf_gdi_mem3blt;
776 primary->SaveBitmap = NULL;
777 primary->GlyphIndex = NULL;
778 primary->FastIndex = NULL;
779 primary->FastGlyph = NULL;
780 primary->PolygonSC = NULL;
781 primary->PolygonCB = NULL;
782 primary->EllipseSC = NULL;
783 primary->EllipseCB = NULL;
785 update->SurfaceBits = xf_gdi_surface_bits;
786 update->SurfaceFrameMarker = xf_gdi_surface_frame_marker;