Remmina - The GTK+ Remote Desktop Client  v1.4.2
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
rdp_graphics.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010 Jay Sorg
4  * Copyright (C) 2010-2011 Vic Lee
5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
7  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  * In addition, as a special exception, the copyright holders give
25  * permission to link the code of portions of this program with the
26  * OpenSSL library under certain conditions as described in each
27  * individual source file, and distribute linked combinations
28  * including the two.
29  * You must obey the GNU General Public License in all respects
30  * for all of the code used other than OpenSSL. * If you modify
31  * file(s) with this exception, you may extend this exception to your
32  * version of the file(s), but you are not obligated to do so. * If you
33  * do not wish to do so, delete this exception statement from your
34  * version. * If you delete this exception statement from all source
35  * files in the program, then also delete it here.
36  *
37  */
38 
39 #include "rdp_plugin.h"
40 #include "rdp_event.h"
41 #include "rdp_graphics.h"
42 
43 #include <freerdp/codec/color.h>
44 #include <freerdp/codec/bitmap.h>
45 #include <winpr/memory.h>
46 
47 //#define RF_BITMAP
48 //#define RF_GLYPH
49 
50 /* Bitmap Class */
51 
52 BOOL rf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
53 {
54  TRACE_CALL(__func__);
55 #ifdef RF_BITMAP
56  UINT8* data;
57  Pixmap pixmap;
58  XImage* image;
59  rfContext* rfi = (rfContext*)context;
60 
61  XSetFunction(rfi->display, rfi->gc, GXcopy);
62  pixmap = XCreatePixmap(rfi->display, rfi->drawable, bitmap->width, bitmap->height, rfi->depth);
63 
64  if (bitmap->data != NULL) {
65  data = freerdp_image_convert(bitmap->data, NULL,
66  bitmap->width, bitmap->height, rfi->srcBpp, rfi->bpp, rfi->clrconv);
67 
68  if (bitmap->ephemeral != TRUE) {
69  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
70  ZPixmap, 0, (char*)data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
71 
72  XPutImage(rfi->display, pixmap, rfi->gc, image, 0, 0, 0, 0, bitmap->width, bitmap->height);
73  XFree(image);
74 
75  if (data != bitmap->data) && (data != NULL)
76  free(data);
77  }else {
78  if (data != bitmap->data) && (data != NULL)
79  free(bitmap->data);
80 
81  bitmap->data = data;
82  }
83  }
84 
85  ((rfBitmap*)bitmap)->pixmap = pixmap;
86 #endif
87  return TRUE;
88 }
89 
90 void rf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
91 {
92  TRACE_CALL(__func__);
93 #ifdef RF_BITMAP
94  rfContext* rfi = (rfContext*)context;
95 
96  printf("rf_Bitmap_Free\n");
97 
98  if (((rfBitmap*)bitmap)->pixmap != 0)
99  XFreePixmap(rfi->display, ((rfBitmap*)bitmap)->pixmap);
100 #endif
101 }
102 
103 BOOL rf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
104 {
105  TRACE_CALL(__func__);
106 #ifdef RF_BITMAP
107  XImage* image;
108  int width, height;
109  rfContext* rfi = (rfContext*)context;
110 
111  printf("rf_Bitmap_Paint\n");
112 
113  width = bitmap->right - bitmap->left + 1;
114  height = bitmap->bottom - bitmap->top + 1;
115 
116  XSetFunction(rfi->display, rfi->gc, GXcopy);
117 
118  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
119  ZPixmap, 0, (char*)bitmap->data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
120 
121  XPutImage(rfi->display, rfi->primary, rfi->gc,
122  image, 0, 0, bitmap->left, bitmap->top, width, height);
123 
124  XFree(image);
125 
126  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc,
127  // bitmap->left, bitmap->top, width, height, bitmap->left, bitmap->top);
128 
129  //gdi_InvalidateRegion(rfi->hdc, bitmap->left, bitmap->top, width, height);
130 #endif
131  return FALSE;
132 }
133 
134 BOOL rf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
135  const BYTE* data, UINT32 width, UINT32 height, UINT32 bpp, UINT32 length, BOOL compressed, UINT32 codec_id)
136 {
137  TRACE_CALL(__func__);
138 #ifdef RF_BITMAP
139  UINT16 size;
140 
141  printf("rf_Bitmap_Decompress\n");
142 
143  size = width * height * (bpp + 7) / 8;
144 
145  if (bitmap->data == NULL)
146  bitmap->data = (UINT8*)xmalloc(size);
147  else
148  bitmap->data = (UINT8*)xrealloc(bitmap->data, size);
149 
150  if (compressed) {
151  BOOL status;
152 
153  status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp);
154 
155  if (status != TRUE) {
156  printf("Bitmap Decompression Failed\n");
157  }
158  }else {
159  freerdp_image_flip(data, bitmap->data, width, height, bpp);
160  }
161 
162  bitmap->compressed = FALSE;
163  bitmap->length = size;
164  bitmap->bpp = bpp;
165 #endif
166  return TRUE;
167 }
168 
169 BOOL rf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
170 {
171  TRACE_CALL(__func__);
172 #ifdef RF_BITMAP
173  rfContext* rfi = (rfContext*)context;
174 
175  if (primary)
176  rfi->drawing = rfi->primary;
177  else
178  rfi->drawing = ((rfBitmap*)bitmap)->pixmap;
179 #endif
180  return TRUE;
181 }
182 
183 /* Pointer Class */
184 
185 BOOL rf_Pointer_New(rdpContext* context, rdpPointer* pointer)
186 {
187  TRACE_CALL(__func__);
189  rfContext* rfi = (rfContext*)context;
190 
191  if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0)) {
192  ui = g_new0(RemminaPluginRdpUiObject, 1);
194  ui->cursor.context = context;
195  ui->cursor.pointer = (rfPointer*)pointer;
196  ui->cursor.type = REMMINA_RDP_POINTER_NEW;
197  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
198  }
199  return FALSE;
200 }
201 
202 void rf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
203 {
204  TRACE_CALL(__func__);
206  rfContext* rfi = (rfContext*)context;
207 
208  if (G_IS_OBJECT(((rfPointer*)pointer)->cursor))
209  {
210  ui = g_new0(RemminaPluginRdpUiObject, 1);
212  ui->cursor.context = context;
213  ui->cursor.pointer = (rfPointer*)pointer;
214  ui->cursor.type = REMMINA_RDP_POINTER_FREE;
216  }
217 }
218 
219 BOOL rf_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
220 {
221  TRACE_CALL(__func__);
223  rfContext* rfi = (rfContext*)context;
224 
225  ui = g_new0(RemminaPluginRdpUiObject, 1);
227  ui->cursor.pointer = (rfPointer*)pointer;
228  ui->cursor.type = REMMINA_RDP_POINTER_SET;
229 
230  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
231 
232 }
233 
234 BOOL rf_Pointer_SetNull(rdpContext* context)
235 {
236  TRACE_CALL(__func__);
238  rfContext* rfi = (rfContext*)context;
239 
240  ui = g_new0(RemminaPluginRdpUiObject, 1);
242  ui->cursor.type = REMMINA_RDP_POINTER_NULL;
243 
244  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
245 }
246 
247 BOOL rf_Pointer_SetDefault(rdpContext* context)
248 {
249  TRACE_CALL(__func__);
251  rfContext* rfi = (rfContext*)context;
252 
253  ui = g_new0(RemminaPluginRdpUiObject, 1);
256 
257  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
258 }
259 
260 BOOL rf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
261 {
262  TRACE_CALL(__func__);
264  rfContext* rfi = (rfContext*)context;
265  ui = g_new0(RemminaPluginRdpUiObject, 1);
268  ui->pos.x = x;
269  ui->pos.y = y;
270 
271  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
272 }
273 
274 /* Glyph Class */
275 
276 BOOL rf_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
277 {
278  TRACE_CALL(__func__);
279 #ifdef RF_GLYPH
280  int scanline;
281  XImage* image;
282  rfContext* rfi;
283  rfGlyph* rf_glyph;
284 
285  rf_glyph = (rfGlyph*)glyph;
286  rfi = (rfContext*)context;
287 
288  scanline = (glyph->cx + 7) / 8;
289 
290  rf_glyph->pixmap = XCreatePixmap(rfi->display, rfi->drawing, glyph->cx, glyph->cy, 1);
291 
292  image = XCreateImage(rfi->display, rfi->visual, 1,
293  ZPixmap, 0, (char*)glyph->aj, glyph->cx, glyph->cy, 8, scanline);
294 
295  image->byte_order = MSBFirst;
296  image->bitmap_bit_order = MSBFirst;
297 
298  XInitImage(image);
299  XPutImage(rfi->display, rf_glyph->pixmap, rfi->gc_mono, image, 0, 0, 0, 0, glyph->cx, glyph->cy);
300  XFree(image);
301 #endif
302  return TRUE;
303 }
304 
305 void rf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
306 {
307  TRACE_CALL(__func__);
308 #ifdef RF_GLYPH
309  rfContext* rfi = (rfContext*)context;
310 
311  if (((rfGlyph*)glyph)->pixmap != 0)
312  XFreePixmap(rfi->display, ((rfGlyph*)glyph)->pixmap);
313 #endif
314 }
315 
316 static BOOL rf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x,
317  INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy,
318  BOOL fOpRedundant)
319 {
320  TRACE_CALL(__func__);
321 #ifdef RF_GLYPH
322  rfGlyph* rf_glyph;
323  rfContext* rfi = (rfContext*)context;
324 
325  rf_glyph = (rfGlyph*)glyph;
326 
327  XSetStipple(rfi->display, rfi->gc, rf_glyph->pixmap);
328  XSetTSOrigin(rfi->display, rfi->gc, x, y);
329  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, glyph->cx, glyph->cy);
330  XSetStipple(rfi->display, rfi->gc, rfi->bitmap_mono);
331 #endif
332  return TRUE;
333 }
334 
335 static BOOL rf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y,
336  INT32 width, INT32 height, UINT32 bgcolor,
337  UINT32 fgcolor, BOOL fOpRedundant)
338 {
339  TRACE_CALL(__func__);
340 #ifdef RF_GLYPH
341  rfContext* rfi = (rfContext*)context;
342 
343  bgcolor = (rfi->clrconv->invert) ?
344  freerdp_color_convert_var_bgr(bgcolor, rfi->srcBpp, 32, rfi->clrconv) :
345  freerdp_color_convert_var_rgb(bgcolor, rfi->srcBpp, 32, rfi->clrconv);
346 
347  fgcolor = (rfi->clrconv->invert) ?
348  freerdp_color_convert_var_bgr(fgcolor, rfi->srcBpp, 32, rfi->clrconv) :
349  freerdp_color_convert_var_rgb(fgcolor, rfi->srcBpp, 32, rfi->clrconv);
350 
351  XSetFunction(rfi->display, rfi->gc, GXcopy);
352  XSetFillStyle(rfi->display, rfi->gc, FillSolid);
353  XSetForeground(rfi->display, rfi->gc, fgcolor);
354  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, width, height);
355 
356  XSetForeground(rfi->display, rfi->gc, bgcolor);
357  XSetBackground(rfi->display, rfi->gc, fgcolor);
358  XSetFillStyle(rfi->display, rfi->gc, FillStippled);
359 #endif
360  return TRUE;
361 }
362 
363 static BOOL rf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y,
364  INT32 width, INT32 height,
365  UINT32 bgcolor, UINT32 fgcolor)
366 {
367  TRACE_CALL(__func__);
368 #ifdef RF_GLYPH
369  rfContext* rfi = (rfContext*)context;
370 
371  if (rfi->drawing == rfi->primary) {
372  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc, x, y, width, height, x, y);
373  //gdi_InvalidateRegion(rfi->hdc, x, y, width, height);
374  }
375 #endif
376  return TRUE;
377 }
378 
379 /* Graphics Module */
380 
381 void rf_register_graphics(rdpGraphics* graphics)
382 {
383  TRACE_CALL(__func__);
384  rdpBitmap* bitmap;
385  rdpPointer* pointer;
386  rdpGlyph* glyph;
387 
388  bitmap = (rdpBitmap*)malloc(sizeof(rdpBitmap));
389  ZeroMemory(bitmap, sizeof(rdpBitmap));
390  bitmap->size = sizeof(rfBitmap);
391 
392  bitmap->New = rf_Bitmap_New;
393  bitmap->Free = rf_Bitmap_Free;
394  bitmap->Paint = rf_Bitmap_Paint;
395  bitmap->Decompress = rf_Bitmap_Decompress;
396  bitmap->SetSurface = rf_Bitmap_SetSurface;
397 
398  graphics_register_bitmap(graphics, bitmap);
399  free(bitmap);
400 
401  pointer = (rdpPointer*)malloc(sizeof(rdpPointer));
402  ZeroMemory(pointer, sizeof(rdpPointer));
403 
404  pointer->size = sizeof(rfPointer);
405 
406  pointer->New = rf_Pointer_New;
407  pointer->Free = rf_Pointer_Free;
408  pointer->Set = rf_Pointer_Set;
409  pointer->SetNull = rf_Pointer_SetNull;
410  pointer->SetDefault = rf_Pointer_SetDefault;
411  pointer->SetPosition = rf_Pointer_SetPosition;
412 
413  graphics_register_pointer(graphics, pointer);
414 
415  free(pointer);
416 
417  glyph = (rdpGlyph*)malloc(sizeof(rdpGlyph));
418  ZeroMemory(glyph, sizeof(rdpGlyph));
419 
420  glyph->size = sizeof(rfGlyph);
421 
422  glyph->New = rf_Glyph_New;
423  glyph->Free = rf_Glyph_Free;
424  glyph->Draw = rf_Glyph_Draw;
425  glyph->BeginDraw = rf_Glyph_BeginDraw;
426  glyph->EndDraw = rf_Glyph_EndDraw;
427 
428  graphics_register_glyph(graphics, glyph);
429 
430  free(glyph);
431 }
void rf_Glyph_Free(rdpContext *context, rdpGlyph *glyph)
Definition: rdp_graphics.c:305
BOOL rf_Glyph_New(rdpContext *context, const rdpGlyph *glyph)
Definition: rdp_graphics.c:276
BOOL rf_Bitmap_New(rdpContext *context, rdpBitmap *bitmap)
Definition: rdp_graphics.c:52
BOOL rf_Pointer_New(rdpContext *context, rdpPointer *pointer)
Definition: rdp_graphics.c:185
BOOL rf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y)
Definition: rdp_graphics.c:260
void rf_Pointer_Free(rdpContext *context, rdpPointer *pointer)
Definition: rdp_graphics.c:202
struct rf_glyph rfGlyph
Definition: rdp_plugin.h:104
GdkDisplay * display
Definition: rdp_plugin.h:288
struct rf_bitmap rfBitmap
Definition: rdp_plugin.h:98
BOOL rf_Bitmap_Decompress(rdpContext *context, rdpBitmap *bitmap, const BYTE *data, UINT32 width, UINT32 height, UINT32 bpp, UINT32 length, BOOL compressed, UINT32 codec_id)
Definition: rdp_graphics.c:134
void rf_register_graphics(rdpGraphics *graphics)
Definition: rdp_graphics.c:381
struct rf_pointer rfPointer
Definition: rdp_plugin.h:91
RemminaProtocolWidget * protocol_widget
Definition: rdp_plugin.h:247
BOOL rf_Bitmap_SetSurface(rdpContext *context, rdpBitmap *bitmap, BOOL primary)
Definition: rdp_graphics.c:169
BOOL rf_Pointer_Set(rdpContext *context, const rdpPointer *pointer)
Definition: rdp_graphics.c:219
GdkVisual * visual
Definition: rdp_plugin.h:289
static BOOL rf_Glyph_EndDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor)
Definition: rdp_graphics.c:363
Pixmap pixmap
Definition: rdp_plugin.h:102
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1268
gint scanline_pad
Definition: rdp_plugin.h:293
static BOOL rf_Glyph_BeginDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
Definition: rdp_graphics.c:335
BOOL rf_Bitmap_Paint(rdpContext *context, rdpBitmap *bitmap)
Definition: rdp_graphics.c:103
BOOL rf_Pointer_SetNull(rdpContext *context)
Definition: rdp_graphics.c:234
gint srcBpp
Definition: rdp_plugin.h:287
BOOL rf_Pointer_SetDefault(rdpContext *context)
Definition: rdp_graphics.c:247
struct remmina_plugin_rdp_ui_object::@48::@51 cursor
struct remmina_plugin_rdp_ui_object::@48::@56 pos
static BOOL rf_Glyph_Draw(rdpContext *context, const rdpGlyph *glyph, INT32 x, INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
Definition: rdp_graphics.c:316
void rf_Bitmap_Free(rdpContext *context, rdpBitmap *bitmap)
Definition: rdp_graphics.c:90
RemminaPluginRdpUiType type
Definition: rdp_plugin.h:190