Initial import of VNCFlinger
diff --git a/src/VNCFlinger.cpp b/src/VNCFlinger.cpp
new file mode 100644
index 0000000..a55b868
--- /dev/null
+++ b/src/VNCFlinger.cpp
@@ -0,0 +1,165 @@
+#define LOG_TAG "VNCFlinger"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/IGraphicBufferProducer.h>
+
+#include "VNCFlinger.h"
+
+using namespace android;
+
+EventQueue *VNCFlinger::sQueue = new EventQueue();
+
+status_t VNCFlinger::start() {
+    Mutex::Autolock _l(mMutex);
+
+    status_t err = setup_l();
+    if (err != NO_ERROR) {
+        ALOGE("Failed to start VNCFlinger: err=%d", err);
+        return err;
+    }
+
+    ALOGD("VNCFlinger is running!");
+
+    rfbRunEventLoop(mVNCScreen, -1, true);
+    sQueue->await();
+
+    release_l();
+    return NO_ERROR;
+}
+
+status_t VNCFlinger::setup_l() {
+
+    status_t err = NO_ERROR;
+
+    mMainDpy = SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain);
+    err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &mMainDpyInfo);
+    if (err != NO_ERROR) {
+        ALOGE("Unable to get display characteristics\n");
+        return err;
+    }
+
+    bool rotated = VirtualDisplay::isDeviceRotated(mMainDpyInfo.orientation);
+    if (mWidth == 0) {
+        mWidth = rotated ? mMainDpyInfo.h : mMainDpyInfo.w;
+    }
+    if (mHeight == 0) {
+        mHeight = rotated ? mMainDpyInfo.w : mMainDpyInfo.h;
+    }
+
+    ALOGD("Display dimensions: %dx%d rotated=%d", mWidth, mHeight, rotated);
+
+    sQueue->addListener(this);
+
+    mVirtualDisplay = new VirtualDisplay();
+
+    mVNCBuf = new uint8_t[mWidth * mHeight * 4];
+
+    rfbLog = VNCFlinger::rfbLogger;
+    rfbErr = VNCFlinger::rfbLogger;
+
+    // 32-bit color
+    mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
+    if (mVNCScreen == NULL) {
+        ALOGE("Unable to create VNCScreen");
+        return NO_INIT;
+    }
+
+    mVNCScreen->desktopName = "VNCFlinger";
+    mVNCScreen->frameBuffer = (char *)mVNCBuf;
+    mVNCScreen->alwaysShared = TRUE;
+    mVNCScreen->httpDir = NULL;
+    mVNCScreen->port = VNC_PORT;
+    mVNCScreen->newClientHook = (rfbNewClientHookPtr) VNCFlinger::onNewClient;
+    mVNCScreen->serverFormat.trueColour = true;
+    mVNCScreen->serverFormat.bitsPerPixel = 32;
+    mVNCScreen->handleEventsEagerly = true;
+    mVNCScreen->deferUpdateTime = 5;
+
+    rfbInitServer(mVNCScreen);
+
+    /* Mark as dirty since we haven't sent any updates at all yet. */
+    rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
+
+    return err;
+}
+
+void VNCFlinger::release_l() {
+    sQueue->removeListener(this);
+    mVirtualDisplay.clear();
+
+    ALOGD("VNCFlinger released");
+}
+
+status_t VNCFlinger::stop() {
+    Mutex::Autolock _l(mMutex);
+    sQueue->shutdown();
+
+    return NO_ERROR;
+}
+
+void VNCFlinger::onEvent(const Event& event) {
+
+    ALOGV("onEvent: mId=%d mData=%p", event.mId, event.mData);
+
+    switch(event.mId) {
+        case EVENT_CLIENT_CONNECT:
+            if (mClientCount == 0) {
+                mVirtualDisplay->start(mMainDpyInfo, sQueue);
+            }
+            mClientCount++;
+
+            ALOGI("Client connected (%zu)", mClientCount);
+            break;
+
+        case EVENT_CLIENT_GONE:
+            if (mClientCount > 0) {
+                mClientCount--;
+                if (mClientCount == 0) {
+                    mVirtualDisplay->stop();
+                }
+            }
+
+            ALOGI("Client disconnected (%zu)", mClientCount);
+            break;
+
+        case EVENT_BUFFER_READY:
+            //mVNCScreen->frameBuffer = (char *) event.mData;
+            memcpy(mVNCBuf, (uint8_t *) event.mData, mWidth * mHeight * 4);
+            rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
+            break;
+
+        default:
+            ALOGE("Unhandled event: %d", event.mId);
+            break;
+    }
+}
+
+ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr /* cl */) {
+    ALOGV("onClientGone");
+    sQueue->enqueue(Event(EVENT_CLIENT_GONE));
+    return 0;
+}
+
+enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
+    ALOGV("onNewClient");
+    cl->clientGoneHook = (ClientGoneHookPtr) VNCFlinger::onClientGone;
+    sQueue->enqueue(Event(EVENT_CLIENT_CONNECT));
+    return RFB_CLIENT_ACCEPT;
+}
+
+void VNCFlinger::rfbLogger(const char *format, ...) {
+    va_list args;
+    char buf[256];
+
+    va_start(args, format);
+    vsprintf(buf, format, args);
+    ALOGI("%s", buf);
+    va_end(args);
+}