diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index d6fb0e6d..f61c320b 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -227,6 +227,9 @@ #define RDP_CAPSET_FONT 14 #define RDP_CAPLEN_FONT 0x04 +#define RDP_CAPSET_BRUSHCACHE 15 +#define RDP_CAPLEN_BRUSHCACHE 0x08 + #define RDP_CAPSET_BITMAP_OFFSCREEN 18 #define RDP_CAPLEN_BITMAP_OFFSCREEN 0x08 @@ -414,6 +417,7 @@ #define RDP_ORDER_FONTCACHE 3 #define RDP_ORDER_RAW_BMPCACHE2 4 #define RDP_ORDER_BMPCACHE2 5 +#define RDP_ORDER_BRUSHCACHE 7 /* drawable types */ #define WND_TYPE_BITMAP 0 diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 70e88646..d46b0a08 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -716,3 +716,14 @@ libxrdp_send_to_channel(struct xrdp_session* session, int channel_id, free_stream(s); return 0; } + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_brush(struct xrdp_session* session, + int width, int height, int bpp, int type, + int size, char* data, int cache_id) +{ + return xrdp_orders_send_brush((struct xrdp_orders*)session->orders, + width, height, bpp, type, size, data, + cache_id); +} diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index 9fb44391..e996b094 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -379,6 +379,9 @@ int APP_CC xrdp_orders_send_bitmap2(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx); +int APP_CC +xrdp_orders_send_brush(struct xrdp_orders* self, int width, int height, + int bpp, int type, int size, char* data, int cache_id); /* xrdp_bitmap_compress.c */ int APP_CC diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 9797a582..8e12642d 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -61,6 +61,8 @@ struct xrdp_client_info int sound_code; /* 1 = leave sound at server */ int is_mce; int rdp5_performanceflags; + int brush_cache_code; /* 0 = no cache 1 = 8x8 standard cache + 2 = arbitrary dimensions */ }; struct xrdp_brush @@ -207,5 +209,9 @@ libxrdp_get_channel_id(struct xrdp_session* session, char* name); int DEFAULT_CC libxrdp_send_to_channel(struct xrdp_session* session, int channel_id, char* data, int data_len); +int DEFAULT_CC +libxrdp_orders_send_brush(struct xrdp_session* session, + int width, int height, int bpp, int type, + int size, char* data, int cache_id); #endif diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c index 5695bb80..686d9034 100644 --- a/libxrdp/xrdp_orders.c +++ b/libxrdp/xrdp_orders.c @@ -1841,3 +1841,31 @@ height(%d)", lines_sending, height); free_stream(temp_s); return 0; } + +/*****************************************************************************/ +/* returns error */ +/* send a brush cache entry */ +int APP_CC +xrdp_orders_send_brush(struct xrdp_orders* self, int width, int height, + int bpp, int type, int size, char* data, int cache_id) +{ + int order_flags; + int len; + + xrdp_orders_check(self, size + 12); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (size + 6) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 0); /* flags */ + out_uint8(self->out_s, RDP_ORDER_BRUSHCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8(self->out_s, bpp); + out_uint8(self->out_s, width); + out_uint8(self->out_s, height); + out_uint8(self->out_s, type); + out_uint8(self->out_s, size); + out_uint8a(self->out_s, data, size); + return 0; +} diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 2b0a30c2..bb9a6fc5 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -695,6 +695,19 @@ xrdp_process_capset_pointercache(struct xrdp_rdp* self, struct stream* s, return 0; } +/*****************************************************************************/ +/* get the type of client brush cache */ +static int APP_CC +xrdp_process_capset_brushcache(struct xrdp_rdp* self, struct stream* s, + int len) +{ + int code; + + in_uint32_le(s, code); + self->client_info.brush_cache_code = code; + return 0; +} + /*****************************************************************************/ int APP_CC xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s) @@ -762,8 +775,8 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s) case 14: /* 14 */ DEBUG(("--14")); break; - case 15: /* 15 */ - DEBUG(("--15")); + case RDP_CAPSET_BRUSHCACHE: /* 15 */ + xrdp_process_capset_brushcache(self, s, len); break; case 16: /* 16 */ DEBUG(("--16")); diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index e41c050a..2d804106 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -72,6 +72,9 @@ int APP_CC xrdp_cache_add_pointer_static(struct xrdp_cache* self, struct xrdp_pointer_item* pointer_item, int index); +int APP_CC +xrdp_cache_add_brush(struct xrdp_cache* self, + char* brush_item_data); /* xrdp_wm.c */ struct xrdp_wm* APP_CC diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index ad59403a..d92cdab6 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -486,3 +486,49 @@ xrdp_cache_add_pointer_static(struct xrdp_cache* self, DEBUG(("adding pointer at %d", index)); return index; } + +/*****************************************************************************/ +/* this does not take owership of brush_item_data, it makes a copy */ +int APP_CC +xrdp_cache_add_brush(struct xrdp_cache* self, + char* brush_item_data) +{ + int i; + int oldest; + int index; + + if (self == 0) + { + return 0; + } + self->brush_stamp++; + /* look for match */ + for (i = 0; i < 64; i++) + { + if (g_memcmp(self->brush_items[i].pattern, + brush_item_data, 8) == 0) + { + self->brush_items[i].stamp = self->brush_stamp; + DEBUG(("found brush at %d", i)); + return i; + } + } + /* look for oldest */ + index = 0; + oldest = 0x7fffffff; + for (i = 0; i < 64; i++) + { + if (self->brush_items[i].stamp < oldest) + { + oldest = self->brush_items[i].stamp; + index = i; + } + } + g_memcpy(self->brush_items[index].pattern, + brush_item_data, 8); + self->brush_items[index].stamp = self->brush_stamp; + libxrdp_orders_send_brush(self->session, 8, 8, 1, 0x81, 8, + self->brush_items[index].pattern, index); + DEBUG(("adding brush at %d", index)); + return index; +} diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 564054bb..f68627d1 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -229,6 +229,28 @@ xrdp_painter_text_height(struct xrdp_painter* self, char* text) return rv; } +/*****************************************************************************/ +static int APP_CC +xrdp_painter_setup_brush(struct xrdp_painter* self, + struct xrdp_brush* out_brush, + struct xrdp_brush* in_brush) +{ + int cache_id; + + g_memcpy(out_brush, in_brush, sizeof(struct xrdp_brush)); + if (in_brush->style == 3) + { + if (self->session->client_info->brush_cache_code == 1) + { + cache_id = xrdp_cache_add_brush(self->wm->cache, in_brush->pattern); + g_memset(out_brush->pattern, 0, 8); + out_brush->pattern[0] = cache_id; + out_brush->style = 0x81; + } + } + return 0; +} + /*****************************************************************************/ /* fill in an area of the screen with one color */ int APP_CC @@ -240,6 +262,7 @@ xrdp_painter_fill_rect(struct xrdp_painter* self, struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region* region; + struct xrdp_brush brush; int k; int dx; int dy; @@ -314,13 +337,14 @@ xrdp_painter_fill_rect(struct xrdp_painter* self, break; } } + xrdp_painter_setup_brush(self, &brush, &self->brush); while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_pat_blt(self->session, x, y, cx, cy, rop, self->bg_color, self->fg_color, - &self->brush, &draw_rect); + &brush, &draw_rect); } k++; } diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 20884b1b..7d2b2b7c 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -130,6 +130,14 @@ struct xrdp_pointer_item char mask[32 * 32 / 8]; }; +struct xrdp_brush_item +{ + int stamp; + /* expand this to a structure to handle more complicated brushes + for now its 8x8 1bpp brushes only */ + char pattern[8]; +}; + /* differnce caches */ struct xrdp_cache { @@ -157,6 +165,8 @@ struct xrdp_cache int pointer_stamp; struct xrdp_pointer_item pointer_items[32]; int pointer_cache_entries; + int brush_stamp; + struct xrdp_brush_item brush_items[64]; }; struct xrdp_mm