Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / client / DirectFB / dfreerdp.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * DirectFB Client
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 #include <errno.h>
21 #include <pthread.h>
22 #include <locale.h>
23 #include <freerdp/utils/args.h>
24 #include <freerdp/utils/memory.h>
25 #include <freerdp/utils/semaphore.h>
26 #include <freerdp/utils/event.h>
27 #include <freerdp/constants.h>
28 #include <freerdp/plugins/cliprdr.h>
29
30 #include "df_event.h"
31 #include "df_graphics.h"
32
33 #include "dfreerdp.h"
34
35 static freerdp_sem g_sem;
36 static int g_thread_count = 0;
37
38 struct thread_data
39 {
40         freerdp* instance;
41 };
42
43 void df_context_new(freerdp* instance, rdpContext* context)
44 {
45         context->channels = freerdp_channels_new();
46 }
47
48 void df_context_free(freerdp* instance, rdpContext* context)
49 {
50
51 }
52
53 void df_begin_paint(rdpContext* context)
54 {
55         rdpGdi* gdi = context->gdi;
56         gdi->primary->hdc->hwnd->invalid->null = 1;
57 }
58
59 void df_end_paint(rdpContext* context)
60 {
61         rdpGdi* gdi;
62         dfInfo* dfi;
63
64         gdi = context->gdi;
65         dfi = ((dfContext*) context)->dfi;
66
67         if (gdi->primary->hdc->hwnd->invalid->null)
68                 return;
69
70 #if 1
71         dfi->update_rect.x = gdi->primary->hdc->hwnd->invalid->x;
72         dfi->update_rect.y = gdi->primary->hdc->hwnd->invalid->y;
73         dfi->update_rect.w = gdi->primary->hdc->hwnd->invalid->w;
74         dfi->update_rect.h = gdi->primary->hdc->hwnd->invalid->h;
75 #else
76         dfi->update_rect.x = 0;
77         dfi->update_rect.y = 0;
78         dfi->update_rect.w = gdi->width;
79         dfi->update_rect.h = gdi->height;
80 #endif
81
82         dfi->primary->Blit(dfi->primary, dfi->surface, &(dfi->update_rect), dfi->update_rect.x, dfi->update_rect.y);
83 }
84
85 boolean df_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
86 {
87         dfInfo* dfi;
88
89         dfi = ((dfContext*) instance->context)->dfi;
90
91         rfds[*rcount] = (void*)(long)(dfi->read_fds);
92         (*rcount)++;
93
94         return true;
95 }
96
97 boolean df_check_fds(freerdp* instance, fd_set* set)
98 {
99         dfInfo* dfi;
100
101         dfi = ((dfContext*) instance->context)->dfi;
102
103         if (!FD_ISSET(dfi->read_fds, set))
104                 return true;
105
106         if (read(dfi->read_fds, &(dfi->event), sizeof(dfi->event)) > 0)
107                 df_event_process(instance, &(dfi->event));
108
109         return true;
110 }
111
112 boolean df_pre_connect(freerdp* instance)
113 {
114         dfInfo* dfi;
115         boolean bitmap_cache;
116         dfContext* context;
117         rdpSettings* settings;
118
119         dfi = (dfInfo*) xzalloc(sizeof(dfInfo));
120         context = ((dfContext*) instance->context);
121         context->dfi = dfi;
122
123         settings = instance->settings;
124         bitmap_cache = settings->bitmap_cache;
125
126         settings->order_support[NEG_DSTBLT_INDEX] = true;
127         settings->order_support[NEG_PATBLT_INDEX] = true;
128         settings->order_support[NEG_SCRBLT_INDEX] = true;
129         settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
130         settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
131         settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
132         settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
133         settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
134         settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = true;
135         settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
136         settings->order_support[NEG_LINETO_INDEX] = true;
137         settings->order_support[NEG_POLYLINE_INDEX] = true;
138         settings->order_support[NEG_MEMBLT_INDEX] = bitmap_cache;
139         settings->order_support[NEG_MEM3BLT_INDEX] = false;
140         settings->order_support[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
141         settings->order_support[NEG_MEM3BLT_V2_INDEX] = false;
142         settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
143         settings->order_support[NEG_GLYPH_INDEX_INDEX] = false;
144         settings->order_support[NEG_FAST_INDEX_INDEX] = false;
145         settings->order_support[NEG_FAST_GLYPH_INDEX] = false;
146         settings->order_support[NEG_POLYGON_SC_INDEX] = false;
147         settings->order_support[NEG_POLYGON_CB_INDEX] = false;
148         settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
149         settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
150
151         dfi->clrconv = xnew(CLRCONV);
152         dfi->clrconv->alpha = 1;
153         dfi->clrconv->invert = 0;
154         dfi->clrconv->rgb555 = 0;
155         dfi->clrconv->palette = xnew(rdpPalette);
156
157         freerdp_channels_pre_connect(instance->context->channels, instance);
158
159         return true;
160 }
161
162 boolean df_post_connect(freerdp* instance)
163 {
164         rdpGdi* gdi;
165         dfInfo* dfi;
166         dfContext* context;
167
168         context = ((dfContext*) instance->context);
169         dfi = context->dfi;
170
171         gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_16BPP | CLRBUF_32BPP, NULL);
172         gdi = instance->context->gdi;
173
174         dfi->err = DirectFBCreate(&(dfi->dfb));
175
176         dfi->dsc.flags = DSDESC_CAPS;
177         dfi->dsc.caps = DSCAPS_PRIMARY;
178         dfi->err = dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->primary));
179         dfi->err = dfi->primary->GetSize(dfi->primary, &(gdi->width), &(gdi->height));
180         dfi->dfb->SetVideoMode(dfi->dfb, gdi->width, gdi->height, gdi->dstBpp);
181         dfi->dfb->CreateInputEventBuffer(dfi->dfb, DICAPS_ALL, DFB_TRUE, &(dfi->event_buffer));
182         dfi->event_buffer->CreateFileDescriptor(dfi->event_buffer, &(dfi->read_fds));
183
184         dfi->dfb->GetDisplayLayer(dfi->dfb, 0, &(dfi->layer));
185         dfi->layer->EnableCursor(dfi->layer, 1);
186
187         dfi->dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT;
188         dfi->dsc.caps = DSCAPS_SYSTEMONLY;
189         dfi->dsc.width = gdi->width;
190         dfi->dsc.height = gdi->height;
191
192         if (gdi->dstBpp == 32 || gdi->dstBpp == 24)
193                 dfi->dsc.pixelformat = DSPF_AiRGB;
194         else if (gdi->dstBpp == 16 || gdi->dstBpp == 15)
195                 dfi->dsc.pixelformat = DSPF_RGB16;
196         else if (gdi->dstBpp == 8)
197                 dfi->dsc.pixelformat = DSPF_RGB332;
198         else
199                 dfi->dsc.pixelformat = DSPF_AiRGB;
200
201         dfi->dsc.preallocated[0].data = gdi->primary_buffer;
202         dfi->dsc.preallocated[0].pitch = gdi->width * gdi->bytesPerPixel;
203         dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->surface));
204
205         instance->update->BeginPaint = df_begin_paint;
206         instance->update->EndPaint = df_end_paint;
207
208         df_keyboard_init();
209
210         pointer_cache_register_callbacks(instance->update);
211         df_register_graphics(instance->context->graphics);
212
213         freerdp_channels_post_connect(instance->context->channels, instance);
214
215         return true;
216 }
217
218 static int df_process_plugin_args(rdpSettings* settings, const char* name,
219         RDP_PLUGIN_DATA* plugin_data, void* user_data)
220 {
221         rdpChannels* channels = (rdpChannels*) user_data;
222
223         printf("loading plugin %s\n", name);
224         freerdp_channels_load_plugin(channels, settings, name, plugin_data);
225
226         return 1;
227 }
228
229 boolean df_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
230 {
231         printf("Certificate details:\n");
232         printf("\tSubject: %s\n", subject);
233         printf("\tIssuer: %s\n", issuer);
234         printf("\tThumbprint: %s\n", fingerprint);
235         printf("The above X.509 certificate could not be verified, possibly because you do not have "
236                 "the CA certificate in your certificate store, or the certificate has expired. "
237                 "Please look at the documentation on how to create local certificate store for a private CA.\n");
238
239         char answer;
240         while (1)
241         {
242                 printf("Do you trust the above certificate? (Y/N) ");
243                 answer = fgetc(stdin);
244
245                 if (answer == 'y' || answer == 'Y')
246                 {
247                         return true;
248                 }
249                 else if (answer == 'n' || answer == 'N')
250                 {
251                         break;
252                 }
253         }
254
255         return false;
256 }
257
258 static int
259 df_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size)
260 {
261         return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
262 }
263
264 static void
265 df_process_cb_monitor_ready_event(rdpChannels* channels, freerdp* instance)
266 {
267         RDP_EVENT* event;
268         RDP_CB_FORMAT_LIST_EVENT* format_list_event;
269
270         event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL);
271
272         format_list_event = (RDP_CB_FORMAT_LIST_EVENT*)event;
273         format_list_event->num_formats = 0;
274
275         freerdp_channels_send_event(channels, event);
276 }
277
278 static void
279 df_process_channel_event(rdpChannels* channels, freerdp* instance)
280 {
281         RDP_EVENT* event;
282
283         event = freerdp_channels_pop_event(channels);
284
285         if (event)
286         {
287                 switch (event->event_type)
288                 {
289                         case RDP_EVENT_TYPE_CB_MONITOR_READY:
290                                 df_process_cb_monitor_ready_event(channels, instance);
291                                 break;
292                         default:
293                                 printf("df_process_channel_event: unknown event type %d\n", event->event_type);
294                                 break;
295                 }
296
297                 freerdp_event_free(event);
298         }
299 }
300
301 static void df_free(dfInfo* dfi)
302 {
303         dfi->dfb->Release(dfi->dfb);
304         xfree(dfi);
305 }
306
307 int dfreerdp_run(freerdp* instance)
308 {
309         int i;
310         int fds;
311         int max_fds;
312         int rcount;
313         int wcount;
314         void* rfds[32];
315         void* wfds[32];
316         fd_set rfds_set;
317         fd_set wfds_set;
318         dfInfo* dfi;
319         dfContext* context;
320         rdpChannels* channels;
321
322         memset(rfds, 0, sizeof(rfds));
323         memset(wfds, 0, sizeof(wfds));
324
325         if (!freerdp_connect(instance))
326                 return 0;
327
328         context = (dfContext*) instance->context;
329
330         dfi = context->dfi;
331         channels = instance->context->channels;
332
333         while (1)
334         {
335                 rcount = 0;
336                 wcount = 0;
337
338                 if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
339                 {
340                         printf("Failed to get FreeRDP file descriptor\n");
341                         break;
342                 }
343                 if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true)
344                 {
345                         printf("Failed to get channel manager file descriptor\n");
346                         break;
347                 }
348                 if (df_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
349                 {
350                         printf("Failed to get dfreerdp file descriptor\n");
351                         break;
352                 }
353
354                 max_fds = 0;
355                 FD_ZERO(&rfds_set);
356                 FD_ZERO(&wfds_set);
357
358                 for (i = 0; i < rcount; i++)
359                 {
360                         fds = (int)(long)(rfds[i]);
361
362                         if (fds > max_fds)
363                                 max_fds = fds;
364
365                         FD_SET(fds, &rfds_set);
366                 }
367
368                 if (max_fds == 0)
369                         break;
370
371                 if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
372                 {
373                         /* these are not really errors */
374                         if (!((errno == EAGAIN) ||
375                                 (errno == EWOULDBLOCK) ||
376                                 (errno == EINPROGRESS) ||
377                                 (errno == EINTR))) /* signal occurred */
378                         {
379                                 printf("dfreerdp_run: select failed\n");
380                                 break;
381                         }
382                 }
383
384                 if (freerdp_check_fds(instance) != true)
385                 {
386                         printf("Failed to check FreeRDP file descriptor\n");
387                         break;
388                 }
389                 if (df_check_fds(instance, &rfds_set) != true)
390                 {
391                         printf("Failed to check dfreerdp file descriptor\n");
392                         break;
393                 }
394                 if (freerdp_channels_check_fds(channels, instance) != true)
395                 {
396                         printf("Failed to check channel manager file descriptor\n");
397                         break;
398                 }
399                 df_process_channel_event(channels, instance);
400         }
401
402         freerdp_channels_close(channels, instance);
403         freerdp_channels_free(channels);
404         df_free(dfi);
405         gdi_free(instance);
406         freerdp_disconnect(instance);
407         freerdp_free(instance);
408
409         return 0;
410 }
411
412 void* thread_func(void* param)
413 {
414         struct thread_data* data;
415         data = (struct thread_data*) param;
416
417         dfreerdp_run(data->instance);
418
419         xfree(data);
420
421         pthread_detach(pthread_self());
422
423         g_thread_count--;
424
425         if (g_thread_count < 1)
426                 freerdp_sem_signal(g_sem);
427
428         return NULL;
429 }
430
431 int main(int argc, char* argv[])
432 {
433         pthread_t thread;
434         freerdp* instance;
435         dfContext* context;
436         rdpChannels* channels;
437         struct thread_data* data;
438
439         setlocale(LC_ALL, "");
440
441         freerdp_channels_global_init();
442
443         g_sem = freerdp_sem_new(1);
444
445         instance = freerdp_new();
446         instance->PreConnect = df_pre_connect;
447         instance->PostConnect = df_post_connect;
448         instance->VerifyCertificate = df_verify_certificate;
449         instance->ReceiveChannelData = df_receive_channel_data;
450
451         instance->context_size = sizeof(dfContext);
452         instance->ContextNew = df_context_new;
453         instance->ContextFree = df_context_free;
454         freerdp_context_new(instance);
455
456         context = (dfContext*) instance->context;
457         channels = instance->context->channels;
458
459         DirectFBInit(&argc, &argv);
460         freerdp_parse_args(instance->settings, argc, argv, df_process_plugin_args, channels, NULL, NULL);
461
462         data = (struct thread_data*) xzalloc(sizeof(struct thread_data));
463         data->instance = instance;
464
465         g_thread_count++;
466         pthread_create(&thread, 0, thread_func, data);
467
468         while (g_thread_count > 0)
469         {
470                 freerdp_sem_wait(g_sem);
471         }
472
473         freerdp_channels_global_uninit();
474
475         return 0;
476 }