Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / client / Windows / wfreerdp.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Windows Client
4  *
5  * Copyright 2009-2011 Jay Sorg
6  * Copyright 2010-2011 Vic Lee
7  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27
28 #ifdef _MSC_VER
29 #include <intrin.h>
30 #endif
31
32 #include <freerdp/freerdp.h>
33 #include <freerdp/constants.h>
34 #include <freerdp/utils/args.h>
35 #include <freerdp/utils/event.h>
36 #include <freerdp/utils/memory.h>
37 #include <freerdp/channels/channels.h>
38
39 #include "wf_gdi.h"
40 #include "wf_graphics.h"
41
42 #include "wfreerdp.h"
43
44 struct _thread_data
45 {
46         freerdp* instance;
47 };
48 typedef struct _thread_data thread_data;
49
50 HANDLE g_done_event;
51 HINSTANCE g_hInstance;
52 HCURSOR g_default_cursor;
53 volatile int g_thread_count = 0;
54 LPCTSTR g_wnd_class_name = L"wfreerdp";
55
56 void wf_context_new(freerdp* instance, rdpContext* context)
57 {
58         context->channels = freerdp_channels_new();
59 }
60
61 void wf_context_free(freerdp* instance, rdpContext* context)
62 {
63
64 }
65
66 int wf_create_console(void)
67 {
68         if (!AllocConsole())
69                 return 1;
70
71         freopen("CONOUT$", "w", stdout);
72         printf("Debug console created.\n");
73
74         return 0;
75 }
76
77 void wf_sw_begin_paint(rdpContext* context)
78 {
79         rdpGdi* gdi = context->gdi;
80         gdi->primary->hdc->hwnd->invalid->null = 1;
81         gdi->primary->hdc->hwnd->ninvalid = 0;
82 }
83
84 void wf_sw_end_paint(rdpContext* context)
85 {
86         int i;
87         rdpGdi* gdi;
88         wfInfo* wfi;
89         sint32 x, y;
90         uint32 w, h;
91         int ninvalid;
92         RECT update_rect;
93         HGDI_RGN cinvalid;
94
95         gdi = context->gdi;
96         wfi = ((wfContext*) context)->wfi;
97
98         if (gdi->primary->hdc->hwnd->ninvalid < 1)
99                 return;
100
101         ninvalid = gdi->primary->hdc->hwnd->ninvalid;
102         cinvalid = gdi->primary->hdc->hwnd->cinvalid;
103
104         for (i = 0; i < ninvalid; i++)
105         {
106                 x = cinvalid[i].x;
107                 y = cinvalid[i].y;
108                 w = cinvalid[i].w;
109                 h = cinvalid[i].h;
110
111                 update_rect.left = x;
112                 update_rect.top = y;
113                 update_rect.right = x + w - 1;
114                 update_rect.bottom = y + h - 1;
115
116                 InvalidateRect(wfi->hwnd, &update_rect, FALSE);
117         }
118 }
119
120 void wf_hw_begin_paint(rdpContext* context)
121 {
122         wfInfo* wfi = ((wfContext*) context)->wfi;
123         wfi->hdc->hwnd->invalid->null = 1;
124         wfi->hdc->hwnd->ninvalid = 0;
125 }
126
127 void wf_hw_end_paint(rdpContext* context)
128 {
129
130 }
131
132 boolean wf_pre_connect(freerdp* instance)
133 {
134         int i1;
135         wfInfo* wfi;
136         wfContext* context;
137         rdpSettings* settings;
138
139         wfi = (wfInfo*) xzalloc(sizeof(wfInfo));
140         context = (wfContext*) instance->context;
141         wfi->instance = instance;
142         context->wfi = wfi;
143
144         settings = instance->settings;
145
146         settings->os_major_type = OSMAJORTYPE_WINDOWS;
147         settings->os_minor_type = OSMINORTYPE_WINDOWS_NT;
148         settings->order_support[NEG_DSTBLT_INDEX] = true;
149         settings->order_support[NEG_PATBLT_INDEX] = true;
150         settings->order_support[NEG_SCRBLT_INDEX] = true;
151         settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
152         settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
153         settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
154         settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
155         settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
156         settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = true;
157         settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
158         settings->order_support[NEG_LINETO_INDEX] = true;
159         settings->order_support[NEG_POLYLINE_INDEX] = true;
160         settings->order_support[NEG_MEMBLT_INDEX] = true;
161         settings->order_support[NEG_MEM3BLT_INDEX] = false;
162         settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
163         settings->order_support[NEG_GLYPH_INDEX_INDEX] = false;
164         settings->order_support[NEG_FAST_INDEX_INDEX] = false;
165         settings->order_support[NEG_FAST_GLYPH_INDEX] = false;
166         settings->order_support[NEG_POLYGON_SC_INDEX] = false;
167         settings->order_support[NEG_POLYGON_CB_INDEX] = false;
168         settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
169         settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
170
171         settings->glyph_cache = false;
172
173         wfi->cursor = g_default_cursor;
174
175         wfi->fullscreen = settings->fullscreen;
176         wfi->fs_toggle = wfi->fullscreen;
177         wfi->sw_gdi = settings->sw_gdi;
178
179         wfi->clrconv = (HCLRCONV) xzalloc(sizeof(CLRCONV));
180         wfi->clrconv->palette = NULL;
181         wfi->clrconv->alpha = 0;
182
183         instance->context->cache = cache_new(settings);
184
185         if (wfi->percentscreen > 0)
186         {
187                 i1 = (GetSystemMetrics(SM_CXSCREEN) * wfi->percentscreen) / 100;
188                 settings->width = i1;
189
190                 i1 = (GetSystemMetrics(SM_CYSCREEN) * wfi->percentscreen) / 100;
191                 settings->height = i1;
192         }
193
194         if (wfi->fs_toggle)
195         {
196                 settings->width = GetSystemMetrics(SM_CXSCREEN);
197                 settings->height = GetSystemMetrics(SM_CYSCREEN);
198         }
199
200         i1 = settings->width;
201         i1 = (i1 + 3) & (~3);
202         settings->width = i1;
203
204         if ((settings->width < 64) || (settings->height < 64) ||
205                 (settings->width > 4096) || (settings->height > 4096))
206         {
207                 printf("wf_pre_connect: invalid dimensions %d %d\n", settings->width, settings->height);
208                 return 1;
209         }
210
211         settings->kbd_layout = (int) GetKeyboardLayout(0) & 0x0000FFFF;
212         freerdp_channels_pre_connect(instance->context->channels, instance);
213
214         return true;
215 }
216
217 void cpuid(unsigned info, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
218 {
219 #if defined(__GNUC__)
220 #if defined(__i386__) || defined(__x86_64__)
221         *eax = info;
222         __asm volatile
223                 ("mov %%ebx, %%edi;" /* 32bit PIC: don't clobber ebx */
224                  "cpuid;"
225                  "mov %%ebx, %%esi;"
226                  "mov %%edi, %%ebx;"
227                  :"+a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
228                  : :"edi");
229 #endif
230 #elif defined(_MSC_VER)
231         int a[4];
232         __cpuid(a, info);
233         *eax = a[0];
234         *ebx = a[1];
235         *ecx = a[2];
236         *edx = a[3];
237 #endif
238 }
239  
240 uint32 wfi_detect_cpu()
241 {
242         uint32 cpu_opt = 0;
243         unsigned int eax, ebx, ecx, edx = 0;
244
245         cpuid(1, &eax, &ebx, &ecx, &edx);
246
247         if (edx & (1<<26))
248         {
249                 cpu_opt |= CPU_SSE2;
250         }
251
252         return cpu_opt;
253 }
254
255 boolean wf_post_connect(freerdp* instance)
256 {
257         rdpGdi* gdi;
258         wfInfo* wfi;
259         rdpCache* cache;
260         wfContext* context;
261         int width, height;
262         wchar_t win_title[64];
263         rdpSettings* settings;
264
265         settings = instance->settings;
266         context = (wfContext*) instance->context;
267         cache = instance->context->cache;
268         wfi = context->wfi;
269
270         wfi->dstBpp = 32;
271         width = settings->width;
272         height = settings->height;
273
274         if (wfi->sw_gdi)
275         {
276                 gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_32BPP, NULL);
277                 gdi = instance->context->gdi;
278                 wfi->hdc = gdi->primary->hdc;
279                 wfi->primary = wf_image_new(wfi, width, height, wfi->dstBpp, gdi->primary_buffer);
280
281                 rfx_context_set_cpu_opt(gdi->rfx_context, wfi_detect_cpu());
282         }
283         else
284         {
285                 wf_gdi_register_update_callbacks(instance->update);
286                 wfi->srcBpp = instance->settings->color_depth;
287                 wfi->primary = wf_image_new(wfi, width, height, wfi->dstBpp, NULL);
288
289                 wfi->hdc = gdi_GetDC();
290                 wfi->hdc->bitsPerPixel = wfi->dstBpp;
291                 wfi->hdc->bytesPerPixel = wfi->dstBpp / 8;
292
293                 wfi->hdc->alpha = wfi->clrconv->alpha;
294                 wfi->hdc->invert = wfi->clrconv->invert;
295
296                 wfi->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
297                 wfi->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
298                 wfi->hdc->hwnd->invalid->null = 1;
299
300                 wfi->hdc->hwnd->count = 32;
301                 wfi->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * wfi->hdc->hwnd->count);
302                 wfi->hdc->hwnd->ninvalid = 0;
303
304                 wfi->image = wf_bitmap_new(wfi, 64, 64, 32, NULL);
305                 wfi->image->_bitmap.data = NULL;
306
307                 if (settings->rfx_codec)
308                 {
309                         wfi->tile = wf_bitmap_new(wfi, 64, 64, 32, NULL);
310                         wfi->rfx_context = rfx_context_new();
311                         rfx_context_set_cpu_opt(wfi->rfx_context, wfi_detect_cpu());
312                 }
313
314                 if (settings->ns_codec)
315                         wfi->nsc_context = nsc_context_new();
316         }
317
318         if (settings->window_title != NULL)
319                 _snwprintf(win_title, sizeof(win_title), L"%S", settings->window_title);
320         else if (settings->port == 3389)
321                 _snwprintf(win_title, sizeof(win_title) / sizeof(win_title[0]), L"FreeRDP: %S", settings->hostname);
322         else
323                 _snwprintf(win_title, sizeof(win_title) / sizeof(win_title[0]), L"FreeRDP: %S:%d", settings->hostname, settings->port);
324
325         if (wfi->hwnd == 0)
326         {
327                 wfi->hwnd = CreateWindowEx((DWORD) NULL, g_wnd_class_name, win_title,
328                                 0, 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL);
329
330                 SetWindowLongPtr(wfi->hwnd, GWLP_USERDATA, (LONG_PTR) wfi);
331         }
332
333         if (wfi->fullscreen)
334         {
335                 SetWindowLongPtr(wfi->hwnd, GWL_STYLE, WS_POPUP);
336                 SetWindowPos(wfi->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
337         }
338         else
339         {
340                 POINT diff;
341                 RECT rc_client, rc_wnd;
342
343                 SetWindowLongPtr(wfi->hwnd, GWL_STYLE, WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX);
344                 /* Now resize to get full canvas size and room for caption and borders */
345                 SetWindowPos(wfi->hwnd, HWND_TOP, 10, 10, width, height, SWP_FRAMECHANGED);
346                 GetClientRect(wfi->hwnd, &rc_client);
347                 GetWindowRect(wfi->hwnd, &rc_wnd);
348                 diff.x = (rc_wnd.right - rc_wnd.left) - rc_client.right;
349                 diff.y = (rc_wnd.bottom - rc_wnd.top) - rc_client.bottom;
350                 SetWindowPos(wfi->hwnd, HWND_TOP, -1, -1, width + diff.x, height + diff.y, SWP_NOMOVE | SWP_FRAMECHANGED);
351         }
352
353         BitBlt(wfi->primary->hdc, 0, 0, width, height, NULL, 0, 0, BLACKNESS);
354         wfi->drawing = wfi->primary;
355
356         ShowWindow(wfi->hwnd, SW_SHOWNORMAL);
357         UpdateWindow(wfi->hwnd);
358
359         if (wfi->sw_gdi)
360         {
361                 instance->update->BeginPaint = wf_sw_begin_paint;
362                 instance->update->EndPaint = wf_sw_end_paint;
363         }
364         else
365         {
366                 instance->update->BeginPaint = wf_hw_begin_paint;
367                 instance->update->EndPaint = wf_hw_end_paint;
368         }
369
370         pointer_cache_register_callbacks(instance->update);
371
372         if (wfi->sw_gdi != true)
373         {
374                 brush_cache_register_callbacks(instance->update);
375                 bitmap_cache_register_callbacks(instance->update);
376                 offscreen_cache_register_callbacks(instance->update);
377         }
378
379         wf_register_graphics(instance->context->graphics);
380
381         freerdp_channels_post_connect(instance->context->channels, instance);
382
383         return true;
384 }
385
386 boolean wf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
387 {
388         return true;
389 }
390
391 int wf_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size)
392 {
393         return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
394 }
395
396 void wf_process_channel_event(rdpChannels* channels, freerdp* instance)
397 {
398         RDP_EVENT* event;
399
400         event = freerdp_channels_pop_event(channels);
401
402         if (event)
403                 freerdp_event_free(event);
404 }
405
406 boolean wf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
407 {
408         return true;
409 }
410
411 boolean wf_check_fds(freerdp* instance)
412 {
413         return true;
414 }
415
416 int wf_process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data)
417 {
418         rdpChannels* channels = (rdpChannels*) user_data;
419
420         printf("loading plugin %s\n", name);
421         freerdp_channels_load_plugin(channels, settings, name, plugin_data);
422
423         return 1;
424 }
425
426 int wf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data)
427 {
428         return 0;
429 }
430
431 int wfreerdp_run(freerdp* instance)
432 {
433         MSG msg;
434         int index;
435         int rcount;
436         int wcount;
437         BOOL msg_ret;
438         int quit_msg;
439         void* rfds[32];
440         void* wfds[32];
441         int fds_count;
442         HANDLE fds[64];
443         rdpChannels* channels;
444
445         memset(rfds, 0, sizeof(rfds));
446         memset(wfds, 0, sizeof(wfds));
447
448         if (freerdp_connect(instance) != true)
449                 return 0;
450
451         channels = instance->context->channels;
452
453         while (1)
454         {
455                 rcount = 0;
456                 wcount = 0;
457
458                 if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
459                 {
460                         printf("Failed to get FreeRDP file descriptor\n");
461                         break;
462                 }
463                 if (wf_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
464                 {
465                         printf("Failed to get wfreerdp file descriptor\n");
466                         break;
467                 }
468                 if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true)
469                 {
470                         printf("Failed to get channel manager file descriptor\n");
471                         break;
472                 }
473
474                 fds_count = 0;
475                 /* setup read fds */
476                 for (index = 0; index < rcount; index++)
477                 {
478                         fds[fds_count++] = rfds[index];
479                 }
480                 /* setup write fds */
481                 for (index = 0; index < wcount; index++)
482                 {
483                         fds[fds_count++] = wfds[index];
484                 }
485                 /* exit if nothing to do */
486                 if (fds_count == 0)
487                 {
488                         printf("wfreerdp_run: fds_count is zero\n");
489                         break;
490                 }
491
492                 /* do the wait */
493                 if (MsgWaitForMultipleObjects(fds_count, fds, FALSE, 1, QS_ALLINPUT) == WAIT_FAILED)
494                 {
495                         printf("wfreerdp_run: WaitForMultipleObjects failed: 0x%04X\n", GetLastError());
496                         break;
497                 }
498
499                 if (freerdp_check_fds(instance) != true)
500                 {
501                         printf("Failed to check FreeRDP file descriptor\n");
502                         break;
503                 }
504                 if (wf_check_fds(instance) != true)
505                 {
506                         printf("Failed to check wfreerdp file descriptor\n");
507                         break;
508                 }
509                 if (freerdp_channels_check_fds(channels, instance) != true)
510                 {
511                         printf("Failed to check channel manager file descriptor\n");
512                         break;
513                 }
514                 wf_process_channel_event(channels, instance);
515
516                 quit_msg = FALSE;
517                 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
518                 {
519                         msg_ret = GetMessage(&msg, NULL, 0, 0);
520
521                         if (msg_ret == 0 || msg_ret == -1)
522                         {
523                                 quit_msg = TRUE;
524                                 break;
525                         }
526
527                         TranslateMessage(&msg);
528                         DispatchMessage(&msg);
529                 }
530
531                 if (quit_msg)
532                         break;
533         }
534
535         /* cleanup */
536         freerdp_channels_free(channels);
537         freerdp_free(instance);
538         
539         return 0;
540 }
541
542 static DWORD WINAPI thread_func(LPVOID lpParam)
543 {
544         wfInfo* wfi;
545         freerdp* instance;
546         thread_data* data;
547
548         data = (thread_data*) lpParam;
549         instance = data->instance;
550
551         wfi = (wfInfo*) xzalloc(sizeof(wfInfo));
552         ((wfContext*) instance->context)->wfi = wfi;
553         wfi->instance = instance;
554
555         wfreerdp_run(instance);
556
557         g_thread_count--;
558
559         if (g_thread_count < 1)
560                 SetEvent(g_done_event);
561
562         return (DWORD) NULL;
563 }
564
565 static DWORD WINAPI kbd_thread_func(LPVOID lpParam)
566 {
567         MSG msg;
568         BOOL status;
569         HHOOK hook_handle;
570
571         hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, g_hInstance, 0);
572
573         if (hook_handle)
574         {
575                 while ((status = GetMessage( &msg, NULL, 0, 0 )) != 0)
576                 {
577                         if (status == -1)
578                         {
579                                 printf("keyboard thread error getting message\n");
580                                 break;
581                         }
582                         else
583                         {
584                                 TranslateMessage(&msg);
585                                 DispatchMessage(&msg);
586                         }
587                 }
588                 UnhookWindowsHookEx(hook_handle);
589         }
590         else
591                 printf("failed to install keyboard hook\n");
592
593         return (DWORD) NULL;
594 }
595
596 INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
597 {
598         freerdp* instance;
599         thread_data* data;
600         WSADATA wsa_data;
601         WNDCLASSEX wnd_cls;
602
603         if (NULL == getenv("HOME"))
604         {
605                 char home[MAX_PATH * 2] = "HOME=";
606                 strcat(home, getenv("HOMEDRIVE"));
607                 strcat(home, getenv("HOMEPATH"));
608                 _putenv(home);
609         }
610
611         if (WSAStartup(0x101, &wsa_data) != 0)
612                 return 1;
613
614         g_done_event = CreateEvent(0, 1, 0, 0);
615
616 #if defined(WITH_DEBUG) || defined(_DEBUG)
617         wf_create_console();
618 #endif
619
620         g_default_cursor = LoadCursor(NULL, IDC_ARROW);
621
622         wnd_cls.cbSize        = sizeof(WNDCLASSEX);
623         wnd_cls.style         = CS_HREDRAW | CS_VREDRAW;
624         wnd_cls.lpfnWndProc   = wf_event_proc;
625         wnd_cls.cbClsExtra    = 0;
626         wnd_cls.cbWndExtra    = 0;
627         wnd_cls.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
628         wnd_cls.hCursor       = g_default_cursor;
629         wnd_cls.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
630         wnd_cls.lpszMenuName  = NULL;
631         wnd_cls.lpszClassName = g_wnd_class_name;
632         wnd_cls.hInstance     = hInstance;
633         wnd_cls.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
634         RegisterClassEx(&wnd_cls);
635
636         g_hInstance = hInstance;
637         freerdp_channels_global_init();
638
639         instance = freerdp_new();
640         instance->PreConnect = wf_pre_connect;
641         instance->PostConnect = wf_post_connect;
642         instance->VerifyCertificate = wf_verify_certificate;
643         instance->ReceiveChannelData = wf_receive_channel_data;
644
645         instance->context_size = sizeof(wfContext);
646         instance->ContextNew = wf_context_new;
647         instance->ContextFree = wf_context_free;
648         freerdp_context_new(instance);
649
650         instance->context->argc = __argc;
651         instance->context->argv = __argv;
652
653         if (!CreateThread(NULL, 0, kbd_thread_func, NULL, 0, NULL))
654                 printf("error creating keyboard handler thread");
655
656         //while (1)
657         {
658                 data = (thread_data*) xzalloc(sizeof(thread_data)); 
659                 data->instance = instance;
660
661                 freerdp_parse_args(instance->settings, __argc, __argv,
662                         wf_process_plugin_args, instance->context->channels, wf_process_client_args, NULL);
663
664                 if (CreateThread(NULL, 0, thread_func, data, 0, NULL) != 0)
665                         g_thread_count++;
666         }
667
668         if (g_thread_count > 0)
669                 WaitForSingleObject(g_done_event, INFINITE);
670         else
671                 MessageBox(GetConsoleWindow(),
672                         L"Failed to start wfreerdp.\n\nPlease check the debug output.",
673                         L"FreeRDP Error", MB_ICONSTOP);
674
675         WSACleanup();
676
677 #ifdef _DEBUG
678         system("pause");
679 #endif
680
681         return 0;
682 }