/* -*-c++-*- OpenSceneGraph - Copyright (C) 1999-2008 Robert Osfield * * This software is open source and may be redistributed and/or modified under * the terms of the GNU General Public License (GPL) version 2.0. * The full license is in LICENSE.txt file included with this distribution,. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * include LICENSE.txt for more details. */ #include #include #include #include #include extern "C" { #include } class LibVncImage : public osgWidget::VncImage { public: LibVncImage(); bool connect(const std::string& hostname); void close(); virtual bool sendPointerEvent(int x, int y, int buttonMask); double getTimeOfLastUpdate() const { return _timeOfLastUpdate; } double getTimeOfLastRender() const { return _timeOfLastRender; } double time() const { return osg::Timer::instance()->time_s(); } virtual bool sendKeyEvent(int key, bool keyDown); virtual void setFrameLastRendered(const osg::FrameStamp* frameStamp); void updated(); static rfbBool resizeImage(rfbClient* client); static void updateImage(rfbClient* client,int x,int y,int w,int h); double _timeOfLastUpdate; double _timeOfLastRender; bool _active; osg::ref_ptr _inactiveBlock; protected: virtual ~LibVncImage(); class RfbThread : public osg::Referenced, public OpenThreads::Thread { public: RfbThread(rfbClient* client, LibVncImage* image): _client(client), _image(image), _done(false) {} virtual ~RfbThread() { _done = true; while(isRunning()) { OpenThreads::Thread::YieldCurrentThread(); } } virtual void run() { do { if (_image->_active) { int i=WaitForMessage(_client,5000); if(i<0) return; if(i) { OSG_NOTICE<<"Handling "<updated(); } } else { _image->_inactiveBlock->block(); } double deltaTime = _image->getTimeOfLastRender() - _image->getTimeOfLastUpdate(); if (deltaTime<-0.01) { //OSG_NOTICE<<"Inactive"<_active = false; } else { _image->_active = true; } } while (!_done && !testCancel()); } rfbClient* _client; osg::observer_ptr _image; bool _done; }; public: rfbClient* _client; osg::ref_ptr _rfbThread; }; LibVncImage::LibVncImage(): _client(0) { // setPixelBufferObject(new osg::PixelBufferObject(this); _inactiveBlock = new osg::RefBlock; } LibVncImage::~LibVncImage() { close(); } static rfbBool rfbInitConnection(rfbClient* client) { /* Unless we accepted an incoming connection, make a TCP connection to the given VNC server */ if (!client->listenSpecified) { if (!client->serverHost || !ConnectToRFBServer(client,client->serverHost,client->serverPort)) return FALSE; } /* Initialise the VNC connection, including reading the password */ if (!InitialiseRFBConnection(client)) return FALSE; if (!SetFormatAndEncodings(client)) return FALSE; client->width=client->si.framebufferWidth; client->height=client->si.framebufferHeight; client->MallocFrameBuffer(client); if (client->updateRect.x < 0) { client->updateRect.x = client->updateRect.y = 0; client->updateRect.w = client->width; client->updateRect.h = client->height; } if (client->appData.scaleSetting>1) { if (!SendScaleSetting(client, client->appData.scaleSetting)) return FALSE; if (!SendFramebufferUpdateRequest(client, client->updateRect.x / client->appData.scaleSetting, client->updateRect.y / client->appData.scaleSetting, client->updateRect.w / client->appData.scaleSetting, client->updateRect.h / client->appData.scaleSetting, FALSE)) return FALSE; } else { if (!SendFramebufferUpdateRequest(client, client->updateRect.x, client->updateRect.y, client->updateRect.w, client->updateRect.h, FALSE)) return FALSE; } return TRUE; } bool LibVncImage::connect(const std::string& hostname) { if (hostname.empty()) return false; if (_client) close(); _client = rfbGetClient(8,3,4); _client->canHandleNewFBSize = TRUE; _client->MallocFrameBuffer = resizeImage; _client->GotFrameBufferUpdate = updateImage; _client->HandleKeyboardLedState = 0; _client->HandleTextChat = 0; rfbClientSetClientData(_client, 0, this); _client->serverHost = strdup(hostname.c_str()); // _client->serverPort = ; // _client->appData.qualityLevel = ; // _client->appData.encodings = ; // _client->appData.compressLevel = ; // _client->appData.scaleSetting = ; if(rfbInitConnection(_client)) { _rfbThread = new RfbThread(_client, this); _rfbThread->startThread(); return true; } else { close(); return false; } } void LibVncImage::close() { if (_rfbThread.valid()) { _inactiveBlock->release(); // stop the client thread _rfbThread = 0; } if (_client) { // close the client rfbClientCleanup(_client); _client = 0; } } rfbBool LibVncImage::resizeImage(rfbClient* client) { osg::Image* image = (osg::Image*)(rfbClientGetClientData(client, 0)); int width=client->width; int height=client->height; int depth=client->format.bitsPerPixel; OSG_NOTICE<<"resize "< vncClient = new osgWidget::VncClient(); if (vncClient->assign(dynamic_cast(result.getImage()))) { return vncClient.release(); } else { return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; } } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(vnc, ReaderWriterVNC)