Formatting cleanup
[qemu-gui.git] / vncpanel.cpp
blob064f544815f6004eecb3b16452b9afaa88d45155
1 #include "vncpanel.h"
2 #include "vncdisplaythread.h"
3 #include "pipedprocess.h"
4 #include <wx/rawbmp.h>
5 #include <wx/log.h>
6 #include <wx/sizer.h>
8 #define DEBUG_MOUSE
9 //#define DEBUG_KEYBOARD
10 //#define DEBUG_VNC_CALLBACKS
11 //#define DEBUG_PAINT
13 typedef wxAlphaPixelData PixelData;
14 // typedef wxPixelFormat<unsigned char, 32, 0, 1, 2> PixelData;
16 DEFINE_EVENT_TYPE(EVT_VNC_UPDATE)
17 DEFINE_EVENT_TYPE(EVT_VNC_RESIZE)
19 BEGIN_EVENT_TABLE(VNCPanel, wxScrolledWindow)
20 EVT_PAINT(VNCPanel::OnPaint)
21 EVT_ERASE_BACKGROUND(VNCPanel::OnEraseBackground)
22 EVT_MOUSE_EVENTS(VNCPanel::OnMouseEvent)
23 EVT_KEY_DOWN(VNCPanel::OnKeyDown)
24 EVT_KEY_UP(VNCPanel::OnKeyUp)
25 EVT_COMMAND(wxID_ANY,EVT_PROCESS_TERMINATED,VNCPanel::HandleProcessTermination)
26 END_EVENT_TABLE()
28 void dummy(){};
30 extern "C" {
31 rfbBool VNCResizeCallback(rfbClient *client);
32 void VNCUpdateCallback(rfbClient* cl,int x,int y,int w,int h);
35 VNCPanel::VNCPanel(wxWindow *parent,wxString host,int display)
36 :wxScrolledWindow(parent, wxID_ANY),
37 vncclient(NULL),
38 vncdisplaythread(NULL),
39 locked(false){
42 VNCPanel::~VNCPanel(){
43 Disconnect();
46 bool VNCPanel::Connect(int display){
47 wxLogDebug(wxT("Try to connect to display: %d"),display);
48 return Connect(wxT(""),display);
51 bool VNCPanel::Connect(wxString host,int display){
52 // 16-bit: vncclient=rfbGetClient(5,3,2);
53 // 24-bit?: vncclient = rfbGetClient(8,3,3);
54 // 32-bit?:vncclient = rfbGetClient(8,3,4);
55 vncclient = rfbGetClient(8,3,4);
56 // store this instance so we can later use it within the callbacks
57 rfbClientSetClientData(vncclient, (void *)dummy, this);
58 vncclient->serverHost = strdup("127.0.0.1");
59 vncclient->serverPort = display;
60 vncclient->MallocFrameBuffer = VNCResizeCallback;
61 vncclient->canHandleNewFBSize = true;
62 vncclient->GotFrameBufferUpdate = VNCUpdateCallback;
64 if(vncclient->serverPort>=0 && vncclient->serverPort<5900)
65 vncclient->serverPort+=5900;
67 if(!rfbInitClient(vncclient,NULL,NULL)){
68 vncclient = NULL;
69 wxLogDebug(wxT("Could not init vncclient."));
70 return false;
73 vncdisplaythread = new VNCDisplayThread(this);
74 vncdisplaythread->Create();
75 vncdisplaythread->Run();
77 return true;
80 void VNCPanel::Disconnect(){
81 rfbClient *tmp = vncclient;
82 vncclient = NULL;
83 wxLogDebug(wxT("vncclient set to NULL"));
84 if(vncdisplaythread != NULL){
85 vncdisplaythread->Stop();
86 vncdisplaythread->Wait();
87 delete vncdisplaythread;
88 vncdisplaythread = NULL;
91 if(tmp != NULL){
92 free(tmp->frameBuffer);
93 rfbClientCleanup(tmp);
96 wxLogDebug(wxT("disconnected"));
99 void VNCPanel::HandleProcessTermination(wxCommandEvent& WXUNUSED(event)){
100 Disconnect();
103 rfbClient* VNCPanel::GetVNCClient(){
104 return this->vncclient;
107 void VNCPanel::VNCUpdateRect(int x,int y,int w,int h){
108 wxBitmap *bmp = VNCGenerateBitmap(x,y,w,h);
109 if(!bmp)
110 return;
111 wxClientDC dc(this);
112 dc.DrawBitmap(*bmp,x,y,false);
113 delete bmp;
116 wxBitmap* VNCPanel::VNCGenerateBitmap(int x,int y,int w,int h){
117 // can't draw if the frame buffer doesn't exists yet
118 if(!vncclient || !vncclient->frameBuffer)
119 return NULL;
121 // create a bitmap from our pixel data
122 #ifdef DEBUG_PAINT
123 wxLogDebug(wxT("generate bitmap: x:%d y:%d w:%d h:%d"),x,y,w,h);
124 #endif
125 //wxCriticalSectionLocker locker(lock);
127 wxBitmap *bmp = new wxBitmap(w,h,vncclient->format.bitsPerPixel);
129 PixelData data(*bmp);
130 if(!data){
131 printf("could not access raw pixel data\n");
132 return NULL;
135 PixelData::Iterator p(data);
136 // data.UseAlpha();
137 // unsigned char *rawdata=(unsigned char *)&p.Data();
138 // unsigned char *rawdata=(unsigned char *)p.m_ptr;
140 uint8_t *px = (uint8_t*)vncclient->frameBuffer;
141 // move the pointer to the beginning of the requested area
142 px+=((vncclient->width * y + x) * 4);
143 int offsetx = ((vncclient->width - w)*4);
144 for( int cy = 0; cy < h; ++cy )
146 PixelData::Iterator rowStart = p;
148 for( int cx = 0; cx < w; ++cx ){
149 p.Red() = px[0];
150 p.Green() = px[1];
151 p.Blue() = px[2];
152 p.Alpha() = 255;
153 px+=4;
154 ++p; // same as p.OffsetX(1)
156 px+=offsetx;
157 p = rowStart;
158 p.OffsetY(data, 1);
161 return bmp;
164 rfbBool VNCPanel::VNCResize(){
165 if(!vncclient)
166 return false;
168 //wxCriticalSectionLocker locker(lock);
170 if(vncclient->frameBuffer)
171 free(vncclient->frameBuffer);
173 vncclient->frameBuffer = (uint8_t*)malloc(
174 vncclient->width * vncclient->height *
175 vncclient->format.bitsPerPixel/8
178 wxLogDebug(wxT("VNCResize: w: %d h: %d"),vncclient->width,vncclient->height);
179 if(vncclient->frameBuffer){
180 wxSize size(vncclient->width,vncclient->height);
181 SetSize(size);
182 SetMinSize(size);
183 SetMaxSize(size);
184 GetParent()->GetSizer()->Layout();
186 GetParent()->SetSize(size);
187 GetParent()->SetMinSize(size);
188 GetParent()->SetMaxSize(size);
190 printf("Size adjusted...\n");
191 Paint();
192 return true;
194 printf("Could not adjust size\n");
195 return false;
198 void VNCPanel::OnPaint(wxPaintEvent& WXUNUSED(event)){
199 if(!vncclient)
200 return;
201 printf("OnPaint()\n");
202 wxPaintDC dc(this);
204 // Dimensions of client area in pixels
205 int x,y,w,h;
206 // get the update rect list
207 wxRegionIterator upd(GetUpdateRegion());
208 wxCriticalSectionLocker locker(lock);
210 while(upd){
211 x = upd.GetX();
212 y = upd.GetY();
213 w = upd.GetW();
214 h = upd.GetH();
215 // it is important that those values are never bigger than
216 // our framebuffer width/height
217 if(x + w > vncclient->width || y + h > vncclient->height){
218 Paint();
219 upd++;
220 continue;
222 //printf(" SendingFrameBufferUpdateRequest(%d,%d,%d,%d)\n",x,y,w,h);
223 SendFramebufferUpdateRequest(vncclient,x,y,w,h,false);
224 wxBitmap *bmp = VNCGenerateBitmap(x,y,w,h);
225 if(bmp){
226 dc.DrawBitmap(*bmp,x,y,false);
227 delete bmp;
230 upd++;
234 void VNCPanel::Paint(){
235 printf("Paint()\n");
236 // can't draw if the frame buffer doesn't exists yet
237 if(!vncclient)
238 return;
239 VNCUpdateRect(0,0,vncclient->width,vncclient->height);
242 void VNCPanel::OnMouseEvent(wxMouseEvent& event){
244 if(!vncclient)
245 return;
247 //wxPoint point = event.GetLogicalPosition(wxDC(this));
248 wxPoint point = event.GetPosition();
249 if(point.x < 0 || point.y < 0)
250 return;
251 // mouse just moving no buttons pressed most common case
252 if(event.Moving()){
253 #ifdef DEBUG_MOUSE
254 wxLogDebug(wxT("mouse moving: x:%d y:%d"),point.x,point.y);
255 #endif
256 SendPointerEvent(vncclient,point.x,point.y,0);
257 return;
260 int button = 0;
262 if(event.LeftIsDown())
263 button |= rfbButton1Mask;
264 if(event.MiddleIsDown())
265 button |= rfbButton2Mask;
266 if(event.RightIsDown())
267 button |= rfbButton3Mask;
269 #ifdef DEBUG_MOUSE
270 wxLogDebug(wxT("mouse event: x:%d y:%d button:%d\n"),point.x,point.y,button);
271 #endif
272 SendPointerEvent(vncclient,point.x,point.y,button);
275 void VNCPanel::OnKeyDown(wxKeyEvent& event){
276 if(vncclient)
277 SendKeyEvent(vncclient,TranslateKeyCode(event),true);
280 void VNCPanel::OnKeyUp(wxKeyEvent& event){
281 if(vncclient)
282 SendKeyEvent(vncclient,TranslateKeyCode(event),false);
285 rfbKeySym VNCPanel::TranslateKeyCode(wxKeyEvent& event){
286 #if 0
287 rfbKeySym k = 0;
288 switch(event.GetKeyCode()){
289 case WXK_BACK: k = XK_BackSpace; break;
290 case WXK_TAB: k = XK_ISO_Left_Tab; break;
291 case WXK_CLEAR: k = XK_Clear; break;
292 case WXK_RETURN: k = XK_Return; break;
293 case WXK_PAUSE: k = XK_Pause; break;
294 case WXK_ESCAPE: k = XK_Escape; break;
295 case WXK_SPACE: k = XK_space; break;
296 case WXK_DELETE: k = XK_Delete; break;
297 case WXK_NUMPAD0: k = XK_KP_0; break;
298 case WXK_NUMPAD1: k = XK_KP_1; break;
299 case WXK_NUMPAD2: k = XK_KP_2; break;
300 case WXK_NUMPAD3: k = XK_KP_3; break;
301 case WXK_NUMPAD4: k = XK_KP_4; break;
302 case WXK_NUMPAD5: k = XK_KP_5; break;
303 case WXK_NUMPAD6: k = XK_KP_6; break;
304 case WXK_NUMPAD7: k = XK_KP_7; break;
305 case WXK_NUMPAD8: k = XK_KP_8; break;
306 case WXK_NUMPAD9: k = XK_KP_9; break;
307 case WXK_NUMPAD_DECIMAL: k = XK_KP_Decimal; break;
308 case WXK_NUMPAD_DIVIDE: k = XK_KP_Divide; break;
309 case WXK_NUMPAD_MULTIPLY: k = XK_KP_Multiply; break;
310 case WXK_NUMPAD_SUBTRACT: k = XK_KP_Subtract; break;
311 case WXK_NUMPAD_ADD: k = XK_KP_Add; break;
312 case WXK_NUMPAD_ENTER: k = XK_KP_Enter; break;
313 case WXK_NUMPAD_EQUAL: k = XK_KP_Equal; break;
314 case WXK_UP: k = XK_Up; break;
315 case WXK_DOWN: k = XK_Down; break;
316 case WXK_RIGHT: k = XK_Right; break;
317 case WXK_LEFT: k = XK_Left; break;
318 case WXK_INSERT: k = XK_Insert; break;
319 case WXK_HOME: k = XK_Home; break;
320 case WXK_END: k = XK_End; break;
321 case WXK_PAGEUP: k = XK_Page_Up; break;
322 case WXK_PAGEDOWN: k = XK_Page_Down; break;
323 case WXK_F1: k = XK_F1; break;
324 case WXK_F2: k = XK_F2; break;
325 case WXK_F3: k = XK_F3; break;
326 case WXK_F4: k = XK_F4; break;
327 case WXK_F5: k = XK_F5; break;
328 case WXK_F6: k = XK_F6; break;
329 case WXK_F7: k = XK_F7; break;
330 case WXK_F8: k = XK_F8; break;
331 case WXK_F9: k = XK_F9; break;
332 case WXK_F10: k = XK_F10; break;
333 case WXK_F11: k = XK_F11; break;
334 case WXK_F12: k = XK_F12; break;
335 case WXK_F13: k = XK_F13; break;
336 case WXK_F14: k = XK_F14; break;
337 case WXK_F15: k = XK_F15; break;
338 case WXK_NUMLOCK: k = XK_Num_Lock; break;
339 case WXK_CAPITAL: k = XK_Caps_Lock; break;
340 case WXK_SCROLL: k = XK_Scroll_Lock; break;
341 case WXK_SHIFT: k = XK_Shift_L; break;
342 // case SDLK_RSHIFT: k = XK_Shift_R; break;
343 // case SDLK_LSHIFT: k = XK_Shift_L; break;
344 case WXK_CONTROL: k = XK_Control_L; break;
345 // case SDLK_RCTRL: k = XK_Control_R; break;
346 // case SDLK_LCTRL: k = XK_Control_L; break;
347 case WXK_ALT: k = XK_Alt_L; break;
348 // case SDLK_RALT: k = XK_Alt_R; break;
349 // case SDLK_LALT: k = XK_Alt_L; break;
350 // case SDLK_RMETA: k = XK_Meta_R; break;
351 // case SDLK_LMETA: k = XK_Meta_L; break;
352 case WXK_WINDOWS_LEFT: k = XK_Super_L; break; /* left windows key */
353 case WXK_WINDOWS_RIGHT: k = XK_Super_R; break; /* right windows key */
354 // case SDLK_COMPOSE: k = XK_Compose; break;
355 // case SDLK_MODE: k = XK_Mode_switch; break;
356 case WXK_HELP: k = XK_Help; break;
357 case WXK_PRINT: k = XK_Print; break;
358 // case SDLK_SYSREQ: k = XK_Sys_Req; break;
359 // case WXK_PAUSE: k = XK_Break; break;
360 default:
361 k = event.GetKeyCode();
362 break;
365 return k;
366 #endif
367 rfbKeySym keycode = event.GetRawKeyCode();
368 #ifdef DEBUG_KEYBOARD
369 wxLogDebug(wxT("Keycode: %d"),keycode);
370 #endif
371 return keycode;
374 inline void VNCPanel::OnEraseBackground(wxEraseEvent &){};
376 wxCriticalSection& VNCPanel::GetCriticalSection(){
377 return lock;
380 extern "C" void VNCUpdateCallback(rfbClient* cl,int x,int y,int w,int h) {
381 VNCPanel *panel = (VNCPanel*)rfbClientGetClientData(cl,(void *)dummy);
382 if(panel){
383 #ifdef DEBUG_VNC_CALLBACKS
384 wxLogDebug(wxT("VNCUpdate callback: x:%d y:%d w:%d h:%d"),x,y,w,h);
385 #endif
386 //if(!wxIsMainThread())
387 // wxMutexGuiEnter();
388 panel->VNCUpdateRect(x,y,w,h);
389 //if(!wxIsMainThread())
390 // wxMutexGuiLeave();
394 extern "C" rfbBool VNCResizeCallback(rfbClient *client){
395 #ifdef DEBUG_VNC_CALLBACKS
396 wxLogDebug(wxT("VNCResize callback: w:%d h:%d"),client->width,client->height);
397 #endif
398 VNCPanel *panel = (VNCPanel*)rfbClientGetClientData(client,(void *)dummy);
399 if(panel){
400 //if(!wxIsMainThread())
401 // wxMutexGuiEnter();
402 rfbBool success = panel->VNCResize();
403 //if(!wxIsMainThread())
404 // wxMutexGuiLeave();
405 return success;
407 return false;