Switched from hg to git, converting ignore file accordingly
[qemu-gui.git] / vncpanel.cpp
blob15cdaecd53d0e1acb8fbd5e3d3fcfd803ff93612
1 #include "debug.h"
2 #include "vncpanel.h"
3 #include "vncdisplaythread.h"
4 #include "pipedprocess.h"
5 #include <wx/rawbmp.h>
6 #include <wx/sizer.h>
8 typedef wxAlphaPixelData PixelData;
9 //typedef wxPixelFormat<unsigned char, 32, 0, 1, 2> PixelData;
11 DEFINE_EVENT_TYPE(EVT_VNC_UPDATE)
12 DEFINE_EVENT_TYPE(EVT_VNC_RESIZE)
14 BEGIN_EVENT_TABLE(VNCPanel, wxScrolledWindow)
15 EVT_PAINT(VNCPanel::OnPaint)
16 EVT_ERASE_BACKGROUND(VNCPanel::OnEraseBackground)
17 EVT_MOUSE_EVENTS(VNCPanel::OnMouseEvent)
18 EVT_KEY_DOWN(VNCPanel::OnKeyDown)
19 EVT_KEY_UP(VNCPanel::OnKeyUp)
20 EVT_COMMAND(wxID_ANY,EVT_PROCESS_TERMINATED,VNCPanel::HandleProcessTermination)
21 END_EVENT_TABLE()
23 void dummy(){};
25 extern "C" {
26 rfbBool VNCResizeCallback(rfbClient *client);
27 void VNCUpdateCallback(rfbClient* cl,int x,int y,int w,int h);
30 VNCPanel::VNCPanel(wxWindow *parent,wxString host,int display)
31 :wxScrolledWindow(parent, wxID_ANY),
32 vncclient(NULL),
33 vncdisplaythread(NULL),
34 locked(false){
37 VNCPanel::~VNCPanel(){
38 Disconnect();
41 bool VNCPanel::Connect(int display){
42 DEBUG_VNC("connecting to display: %d\n",display);
43 return Connect(wxT(""),display);
46 bool VNCPanel::Connect(wxString host,int display){
47 // 16-bit: vncclient=rfbGetClient(5,3,2);
48 // 24-bit?: vncclient = rfbGetClient(8,3,3);
49 // 32-bit?:vncclient = rfbGetClient(8,3,4);
50 vncclient = rfbGetClient(8,3,4);
51 // store this instance so we can later use it within the callbacks
52 rfbClientSetClientData(vncclient, (void *)dummy, this);
53 vncclient->serverHost = strdup("127.0.0.1");
54 vncclient->serverPort = display;
55 vncclient->MallocFrameBuffer = VNCResizeCallback;
56 vncclient->canHandleNewFBSize = true;
57 vncclient->GotFrameBufferUpdate = VNCUpdateCallback;
59 vncclient->format.redShift = 16;
60 vncclient->format.greenShift = 8;
61 vncclient->format.blueShift = 0;
64 vncclient->appData.useBGR233 = 0;
65 vncclient->appData.encodingsString = "copyrect hextile raw";
66 // vncclient->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
67 vncclient->appData.compressLevel = 0;
68 vncclient->appData.qualityLevel = 9;
70 if(vncclient->serverPort>=0 && vncclient->serverPort<5900)
71 vncclient->serverPort+=5900;
73 if(!rfbInitClient(vncclient,NULL,NULL)){
74 DEBUG_VNC("Could not initialize vncclient.\n");
75 vncclient = NULL;
76 return false;
79 vncdisplaythread = new VNCDisplayThread(this);
80 vncdisplaythread->Create();
81 vncdisplaythread->Run();
83 return true;
86 void VNCPanel::Disconnect(){
87 rfbClient *tmp = vncclient;
88 vncclient = NULL;
89 if(vncdisplaythread != NULL){
90 vncdisplaythread->Stop();
91 vncdisplaythread->Wait();
92 delete vncdisplaythread;
93 vncdisplaythread = NULL;
96 if(tmp != NULL){
97 free(tmp->frameBuffer);
98 rfbClientCleanup(tmp);
102 void VNCPanel::HandleProcessTermination(wxCommandEvent& WXUNUSED(event)){
103 Disconnect();
106 rfbClient* VNCPanel::GetVNCClient(){
107 return this->vncclient;
110 void VNCPanel::VNCUpdateRect(int x,int y,int w,int h){
111 wxBitmap *bmp = VNCGenerateBitmap(x,y,w,h);
112 if(!bmp)
113 return;
114 wxClientDC dc(this);
115 dc.DrawBitmap(*bmp,x,y,false);
116 delete bmp;
119 wxBitmap* VNCPanel::VNCGenerateBitmap(int x,int y,int w,int h){
120 // can't draw if the frame buffer doesn't exists yet
121 if(!vncclient || !vncclient->frameBuffer)
122 return NULL;
124 DEBUG_PAINT("generate bitmap: x:%d y:%d w:%d h:%d\n",x,y,w,h);
125 // create a bitmap from our pixel data
126 // wxBitmap *test = new wxBitmap((const char *)vncclient->frameBuffer,w,h,vncclient->format.bitsPerPixel);
127 // return test;
128 wxBitmap *bmp = new wxBitmap(w,h,vncclient->format.bitsPerPixel);
130 PixelData data(*bmp);
131 if(!data){
132 DEBUG_PAINT("could not access raw pixel data\n");
133 return NULL;
136 data.UseAlpha();
137 PixelData::Iterator p(data);
138 // unsigned char *rawdata=(unsigned char *)&p.Data();
139 // unsigned char *rawdata=(unsigned char *)p.m_ptr;
141 //p.m_ptr = vncclient->frameBuffer;
142 //return bmp;
144 // uint8_t *pp = (uint8_t *)&it.Data();
145 uint8_t *px = (uint8_t*)vncclient->frameBuffer;
146 // move the pointer to the beginning of the requested area
147 px+=((vncclient->width * y + x) * 4);
148 int offsetx = ((vncclient->width - w)*4);
150 for( int cy = 0; cy < h; ++cy ){
151 PixelData::Iterator rowStart = p;
152 for( int cx = 0; cx < w; ++cx ){
153 p.Red() = px[0];
154 p.Green() = px[1];
155 p.Blue() = px[2];
156 p.Alpha() = 255;
157 px+=4;
158 ++p; // same as p.OffsetX(1)
160 px+=offsetx;
161 p = rowStart;
162 p.OffsetY(data, 1);
165 return bmp;
168 rfbBool VNCPanel::VNCResize(){
169 if(!vncclient)
170 return false;
172 DEBUG_VNC("resize: w: %d h: %d\n",vncclient->width,vncclient->height);
173 if(vncclient->frameBuffer)
174 free(vncclient->frameBuffer);
176 vncclient->frameBuffer = (uint8_t*)malloc(
177 vncclient->width * vncclient->height *
178 vncclient->format.bitsPerPixel/8
181 if(vncclient->frameBuffer){
182 wxSize size(vncclient->width,vncclient->height);
183 SetSize(size);
184 SetMinSize(size);
185 SetMaxSize(size);
186 GetParent()->GetSizer()->Layout();
187 DEBUG_VNC("resize succeeded\n");
188 Paint();
189 return true;
191 DEBUG_VNC("resize failed\n");
192 return false;
195 void VNCPanel::OnPaint(wxPaintEvent& WXUNUSED(event)){
196 if(!vncclient)
197 return;
199 wxPaintDC dc(this);
200 int x,y,w,h;
201 wxRegionIterator upd(GetUpdateRegion());
203 while(upd){
204 x = upd.GetX();
205 y = upd.GetY();
206 w = upd.GetW();
207 h = upd.GetH();
208 // it is important that those values are never bigger than
209 // our framebuffer width/height otherwhise repaint the whole screen
210 if(x + w > vncclient->width || y + h > vncclient->height){
211 Paint();
212 return;
214 //printf(" SendingFrameBufferUpdateRequest(%d,%d,%d,%d)\n",x,y,w,h);
215 //SendFramebufferUpdateRequest(vncclient,x,y,w,h,false);
216 wxBitmap *bmp = VNCGenerateBitmap(x,y,w,h);
217 if(bmp){
218 dc.DrawBitmap(*bmp,x,y,false);
219 delete bmp;
222 upd++;
226 void VNCPanel::Paint(){
227 if(!vncclient)
228 return;
229 VNCUpdateRect(0,0,vncclient->width,vncclient->height);
232 void VNCPanel::OnMouseEvent(wxMouseEvent& event){
233 if(!vncclient)
234 return;
236 //wxPoint point = event.GetLogicalPosition(wxDC(this));
237 wxPoint point = event.GetPosition();
238 if(point.x < 0 || point.y < 0)
239 return;
240 // mouse just moving no buttons pressed most common case
241 if(event.Moving()){
242 DEBUG_MOUSE("moving: x:%d y:%d\n",point.x,point.y);
243 SendPointerEvent(vncclient,point.x,point.y,0);
244 return;
247 if(event.Entering()){
248 HideCursor();
249 return;
252 if(event.Leaving()){
253 ShowCursor();
254 return;
257 int button = 0;
259 if(event.LeftIsDown())
260 button |= rfbButton1Mask;
261 if(event.MiddleIsDown())
262 button |= rfbButton2Mask;
263 if(event.RightIsDown())
264 button |= rfbButton3Mask;
266 DEBUG_MOUSE("event: x:%d y:%d button:%d\n",point.x,point.y,button);
267 SendPointerEvent(vncclient,point.x,point.y,button);
270 void VNCPanel::HideCursor(){
271 wxImage image(1,1);
272 image.SetMask(true);
273 image.SetMaskColour(0,0,0);
274 wxCursor cursor(image);
275 SetCursor(cursor);
278 void VNCPanel::ShowCursor(){
279 SetCursor(wxNullCursor);
282 void VNCPanel::OnKeyDown(wxKeyEvent& event){
283 if(vncclient)
284 SendKeyEvent(vncclient,TranslateKeyCode(event),true);
287 void VNCPanel::OnKeyUp(wxKeyEvent& event){
288 if(vncclient)
289 SendKeyEvent(vncclient,TranslateKeyCode(event),false);
292 rfbKeySym VNCPanel::TranslateKeyCode(wxKeyEvent& event){
293 #if 0
294 rfbKeySym k = 0;
295 switch(event.GetKeyCode()){
296 case WXK_BACK: k = XK_BackSpace; break;
297 case WXK_TAB: k = XK_ISO_Left_Tab; break;
298 case WXK_CLEAR: k = XK_Clear; break;
299 case WXK_RETURN: k = XK_Return; break;
300 case WXK_PAUSE: k = XK_Pause; break;
301 case WXK_ESCAPE: k = XK_Escape; break;
302 case WXK_SPACE: k = XK_space; break;
303 case WXK_DELETE: k = XK_Delete; break;
304 case WXK_NUMPAD0: k = XK_KP_0; break;
305 case WXK_NUMPAD1: k = XK_KP_1; break;
306 case WXK_NUMPAD2: k = XK_KP_2; break;
307 case WXK_NUMPAD3: k = XK_KP_3; break;
308 case WXK_NUMPAD4: k = XK_KP_4; break;
309 case WXK_NUMPAD5: k = XK_KP_5; break;
310 case WXK_NUMPAD6: k = XK_KP_6; break;
311 case WXK_NUMPAD7: k = XK_KP_7; break;
312 case WXK_NUMPAD8: k = XK_KP_8; break;
313 case WXK_NUMPAD9: k = XK_KP_9; break;
314 case WXK_NUMPAD_DECIMAL: k = XK_KP_Decimal; break;
315 case WXK_NUMPAD_DIVIDE: k = XK_KP_Divide; break;
316 case WXK_NUMPAD_MULTIPLY: k = XK_KP_Multiply; break;
317 case WXK_NUMPAD_SUBTRACT: k = XK_KP_Subtract; break;
318 case WXK_NUMPAD_ADD: k = XK_KP_Add; break;
319 case WXK_NUMPAD_ENTER: k = XK_KP_Enter; break;
320 case WXK_NUMPAD_EQUAL: k = XK_KP_Equal; break;
321 case WXK_UP: k = XK_Up; break;
322 case WXK_DOWN: k = XK_Down; break;
323 case WXK_RIGHT: k = XK_Right; break;
324 case WXK_LEFT: k = XK_Left; break;
325 case WXK_INSERT: k = XK_Insert; break;
326 case WXK_HOME: k = XK_Home; break;
327 case WXK_END: k = XK_End; break;
328 case WXK_PAGEUP: k = XK_Page_Up; break;
329 case WXK_PAGEDOWN: k = XK_Page_Down; break;
330 case WXK_F1: k = XK_F1; break;
331 case WXK_F2: k = XK_F2; break;
332 case WXK_F3: k = XK_F3; break;
333 case WXK_F4: k = XK_F4; break;
334 case WXK_F5: k = XK_F5; break;
335 case WXK_F6: k = XK_F6; break;
336 case WXK_F7: k = XK_F7; break;
337 case WXK_F8: k = XK_F8; break;
338 case WXK_F9: k = XK_F9; break;
339 case WXK_F10: k = XK_F10; break;
340 case WXK_F11: k = XK_F11; break;
341 case WXK_F12: k = XK_F12; break;
342 case WXK_F13: k = XK_F13; break;
343 case WXK_F14: k = XK_F14; break;
344 case WXK_F15: k = XK_F15; break;
345 case WXK_NUMLOCK: k = XK_Num_Lock; break;
346 case WXK_CAPITAL: k = XK_Caps_Lock; break;
347 case WXK_SCROLL: k = XK_Scroll_Lock; break;
348 case WXK_SHIFT: k = XK_Shift_L; break;
349 // case SDLK_RSHIFT: k = XK_Shift_R; break;
350 // case SDLK_LSHIFT: k = XK_Shift_L; break;
351 case WXK_CONTROL: k = XK_Control_L; break;
352 // case SDLK_RCTRL: k = XK_Control_R; break;
353 // case SDLK_LCTRL: k = XK_Control_L; break;
354 case WXK_ALT: k = XK_Alt_L; break;
355 // case SDLK_RALT: k = XK_Alt_R; break;
356 // case SDLK_LALT: k = XK_Alt_L; break;
357 // case SDLK_RMETA: k = XK_Meta_R; break;
358 // case SDLK_LMETA: k = XK_Meta_L; break;
359 case WXK_WINDOWS_LEFT: k = XK_Super_L; break; /* left windows key */
360 case WXK_WINDOWS_RIGHT: k = XK_Super_R; break; /* right windows key */
361 // case SDLK_COMPOSE: k = XK_Compose; break;
362 // case SDLK_MODE: k = XK_Mode_switch; break;
363 case WXK_HELP: k = XK_Help; break;
364 case WXK_PRINT: k = XK_Print; break;
365 // case SDLK_SYSREQ: k = XK_Sys_Req; break;
366 // case WXK_PAUSE: k = XK_Break; break;
367 default:
368 k = event.GetKeyCode();
369 break;
372 return k;
373 #endif
374 rfbKeySym keycode = event.GetRawKeyCode();
375 DEBUG_KEYBOARD("keycode: %d",keycode);
376 return keycode;
379 inline void VNCPanel::OnEraseBackground(wxEraseEvent &){};
381 extern "C" void VNCUpdateCallback(rfbClient* cl,int x,int y,int w,int h) {
382 VNCPanel *panel = (VNCPanel*)rfbClientGetClientData(cl,(void *)dummy);
383 if(panel){
384 DEBUG_VNC("update callback: x:%d y:%d w:%d h:%d\n",x,y,w,h);
385 panel->VNCUpdateRect(x,y,w,h);
389 extern "C" rfbBool VNCResizeCallback(rfbClient *client){
390 DEBUG_VNC("resize callback: w:%d h:%d\n",client->width,client->height);
391 VNCPanel *panel = (VNCPanel*)rfbClientGetClientData(client,(void *)dummy);
392 if(panel)
393 return panel->VNCResize();
394 return false;