cleanup
[presencevnc] / src / vncview.cpp
index 8152bec..ccbae25 100644 (file)
@@ -53,9 +53,13 @@ critical(parent, caption, message)
 #define KMOD_Shift_L   0x10
 
 //local cursor width/height in px, should be an odd number
-const int cursor_size = 7;
+const int CURSOR_SIZE = 7;
 
-VncView::VncView(QWidget *parent, const KUrl &url, RemoteView::Quality quality)
+const int TAP_PRESS_TIME = 180;
+const int DOUBLE_TAP_UP_TIME = 500;
+
+
+VncView::VncView(QWidget *parent, const KUrl &url, RemoteView::Quality quality, int listen_port)
         : RemoteView(parent),
         m_initDone(false),
         m_buttonMask(0),
@@ -69,12 +73,14 @@ VncView::VncView(QWidget *parent, const KUrl &url, RemoteView::Quality quality)
         m_verticalFactor(1.0),
         m_forceLocalCursor(false),
        force_full_repaint(false),
-       quality(quality)
+       quality(quality),
+       listen_port(listen_port)
 {
     m_url = url;
     m_host = url.host();
     m_port = url.port();
 
+       //BlockingQueuedConnection can cause deadlocks when exiting, handled in startQuitting()
     connect(&vncThread, SIGNAL(imageUpdated(int, int, int, int)), this, SLOT(updateImage(int, int, int, int)), Qt::BlockingQueuedConnection);
     connect(&vncThread, SIGNAL(gotCut(const QString&)), this, SLOT(setCut(const QString&)), Qt::BlockingQueuedConnection);
     connect(&vncThread, SIGNAL(passwordRequest()), this, SLOT(requestPassword()), Qt::BlockingQueuedConnection);
@@ -133,48 +139,28 @@ QSize VncView::minimumSizeHint() const
     return size();
 }
 
-void VncView::scaleResize(int w, int h)
-{
-    RemoteView::scaleResize(w, h);
-    
-    kDebug(5011) << "scaleResize(): " <<w << h;
-    if (m_scale) {
-        m_verticalFactor = (qreal) h / m_frame.height();
-        m_horizontalFactor = (qreal) w / m_frame.width();
-
-        m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor);
-
-        const qreal newW = m_frame.width() * m_horizontalFactor;
-        const qreal newH = m_frame.height() * m_verticalFactor;
-       /*
-        setMaximumSize(newW, newH); //This is a hack to force Qt to center the view in the scroll area
-       //also causes the widget's size to flicker
-       */
-        resize(newW, newH);
-    } 
-}
-
-
 void VncView::startQuitting()
 {
     kDebug(5011) << "about to quit";
 
-    const bool connected = status() == RemoteView::Connected;
+    //const bool connected = status() == RemoteView::Connected;
 
     setStatus(Disconnecting);
 
     m_quitFlag = true;
 
-    if (connected) {
-        vncThread.stop();
-    }
-
-    vncThread.quit();
-
-    const bool quitSuccess = vncThread.wait(500);
-
-    kDebug(5011) << "startQuitting(): Quit VNC thread success:" << quitSuccess;
-
+       //if(connected) //remove if things work without it
+       vncThread.stop();
+
+    const bool quitSuccess = vncThread.wait(700);
+       if(!quitSuccess) {
+               //happens when vncThread wants to call a slot via BlockingQueuedConnection,
+               //needs an event loop in this thread so execution continues after 'emit'
+               QEventLoop loop;
+               if(!loop.processEvents())
+                       kDebug(5011) << "BUG: deadlocked, but no events to deliver?";
+               vncThread.wait(700);
+       }
     setStatus(Disconnected);
 }
 
@@ -187,7 +173,7 @@ bool VncView::start()
 {
     vncThread.setHost(m_host);
     vncThread.setPort(m_port);
-
+       vncThread.setListenPort(listen_port); //if port is != 0, thread will listen for connections
     vncThread.setQuality(quality);
 
     // set local cursor on by default because low quality mostly means slow internet connection
@@ -251,7 +237,8 @@ void VncView::requestPassword()
        QHBoxLayout layout1;
        QVBoxLayout layout2;
        layout2.addWidget(&passwordbox);
-       layout2.addWidget(&save_password);
+       if(!m_host.isEmpty()) //don't save incomming connections
+               layout2.addWidget(&save_password);
        layout1.addLayout(&layout2);
        layout1.addWidget(&ok_button);
        dialog.setLayout(&layout1);
@@ -259,7 +246,7 @@ void VncView::requestPassword()
        if(dialog.exec()) { //dialog accepted
                password = passwordbox.text();
 
-               if(save_password.isChecked()) {
+               if(!m_host.isEmpty() and save_password.isChecked()) {
                        kDebug(5011) << "Saving password for host '" << m_host << "'";
 
                        settings.setValue(QString("%1/password").arg(m_host), password);
@@ -274,8 +261,6 @@ void VncView::requestPassword()
 
 void VncView::outputErrorMessage(const QString &message)
 {
-    kDebug(5011) << message;
-
     if (message == "INTERNAL:APPLE_VNC_COMPATIBILTY") {
         setCursor(localDotCursor());
         m_forceLocalCursor = true;
@@ -292,46 +277,14 @@ void VncView::updateImage(int x, int y, int w, int h)
        if(!QApplication::focusWidget()) { //no focus, we're probably minimized
                return;
        }
-     //kDebug(5011) << "got update" << width() << height();
 
-     /*
-     static unsigned int frames = 0;
-     static unsigned int updates = 0;
-     static QTime time = QTime::currentTime();
-     updates++;
-     if(updates % 100 == 0)
-            kDebug(5011) << "u/s: " << updates/double(time.elapsed()) * 1000.0;
-if(x == 0 and y == 0) {
-       frames++;
-     if(frames % 100 == 0)
-            kDebug(5011) << "f/s: " << frames/double(time.elapsed()) * 1000.0;
-}
-*/
+     //kDebug(5011) << "got update" << width() << height();
 
     m_x = x;
     m_y = y;
     m_w = w;
     m_h = h;
 
-
-       //with scaled view, artefacts occur because of rounding errors
-       //we'll try to only update chunks of screen space that correspond to integer pixel sizes in m_frame
-       //put this into paintEvent
-       /*
-       int frame_x = x/m_horizontalFactor;
-       int frame_w = w/m_horizontalFactor;
-       int frame_y = y/m_verticalFactor;
-       int frame_h = h/m_verticalFactor;
-       
-       m_x = frame_x*m_horizontalFactor;
-       m_y = frame_y*m_verticalFactor;
-
-       m_w = (frame_w+2)*m_horizontalFactor;
-       m_h = (frame_h+2)*m_verticalFactor;
-       kDebug(5011)<< "update);
-       */
-
-
     if (m_horizontalFactor != 1.0 || m_verticalFactor != 1.0) {
         // If the view is scaled, grow the update rectangle to avoid artifacts
         int x_extrapixels = 1.0/m_horizontalFactor + 1;
@@ -358,12 +311,7 @@ if(x == 0 and y == 0) {
 //         emit framebufferSizeChanged(m_frame.width(), m_frame.height());
         emit connected();
         
-        if (m_scale) {
-            if (parentWidget())
-                scaleResize(parentWidget()->width(), parentWidget()->height());
-           else
-                scaleResize(width(), height());
-        } 
+               resize(width(), height());
         
         m_initDone = true;
 
@@ -373,16 +321,7 @@ if(x == 0 and y == 0) {
     if ((y == 0 && x == 0) && (m_frame.size() != old_frame_size)) {
            old_frame_size = m_frame.size();
         kDebug(5011) << "Updating framebuffer size";
-        if (m_scale) {
-            //setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
-            if (parentWidget())
-                scaleResize(parentWidget()->width(), parentWidget()->height());
-        } else {
-            kDebug(5011) << "Resizing: " << m_frame.width() << m_frame.height();
-            resize(m_frame.width(), m_frame.height());
-            //setMaximumSize(m_frame.width(), m_frame.height()); //This is a hack to force Qt to center the view in the scroll area
-            //setMinimumSize(m_frame.width(), m_frame.height());
-        }
+               setZoomLevel();
         emit framebufferSizeChanged(m_frame.width(), m_frame.height());
     }
 
@@ -410,39 +349,36 @@ void VncView::showDotCursor(DotCursorState state)
     setCursor(state == CursorOn ? localDotCursor() : Qt::BlankCursor);
 }
 
-void VncView::enableScaling(bool scale)
-{
-    RemoteView::enableScaling(scale);
-}
-
 //level should be in [0, 100]
 void VncView::setZoomLevel(int level)
 {
        Q_ASSERT(parentWidget() != 0);
 
+       if(level == -1) { //handle resize
+               resize(m_frame.width()*m_horizontalFactor, m_frame.height()*m_verticalFactor);
+               return;
+       }
 
-       double factor; //actual magnification
-       if(level > 95) {
-               factor = 2.0;
-       } else if(level > 90) {
-               factor = 1.0;
+       double magnification;
+       if(level == 100) {
+               magnification = 2.0;
+       } else if(level >= 90) {
+               magnification = 1.0;
        } else {
-               const double min_horiz_factor = double(parentWidget()->width())/m_frame.width();
-               const double min_vert_factor = double(parentWidget()->height())/m_frame.height();
-               const double fit_screen_factor = qMin(min_horiz_factor, min_vert_factor);
+               const double min_horiz_magnification = double(parentWidget()->width())/m_frame.width();
+               const double min_vert_magnification = double(parentWidget()->height())/m_frame.height();
+               const double fit_screen_magnification = qMin(min_horiz_magnification, min_vert_magnification);
 
-               //level=900 => factor=1.0, level=0 => factor=fit_screen_factor
-               factor = (level)/90.0*(1.0 - fit_screen_factor) + fit_screen_factor;
+               //level=90 => magnification=1.0, level=0 => magnification=fit_screen_magnification
+               magnification = (level)/90.0*(1.0 - fit_screen_magnification) + fit_screen_magnification;
        }
 
-       if(factor < 0) {
-               //remote display smaller than local?
-               kDebug(5011) << "remote display smaller than local?";
-               factor = 1.0;
-       }
-
-       m_verticalFactor = m_horizontalFactor = factor;
-       resize(m_frame.width()*factor, m_frame.height()*factor);
+       if(magnification < 0                    //remote display smaller than local?
+       or magnification != magnification)      //nan
+               magnification = 1.0;
+       
+       m_verticalFactor = m_horizontalFactor = magnification;
+       resize(m_frame.width()*magnification, m_frame.height()*magnification);
 }
 
 void VncView::setCut(const QString &text)
@@ -504,7 +440,7 @@ void VncView::paintEvent(QPaintEvent *event)
                painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
 #endif
                //rectangle size includes 1px pen width
-               painter.drawRect(cursor_x*m_horizontalFactor - cursor_size/2, cursor_y*m_verticalFactor - cursor_size/2, cursor_size-1, cursor_size-1);
+               painter.drawRect(cursor_x*m_horizontalFactor - CURSOR_SIZE/2, cursor_y*m_verticalFactor - CURSOR_SIZE/2, CURSOR_SIZE-1, CURSOR_SIZE-1);
        }
 
     RemoteView::paintEvent(event);
@@ -513,10 +449,7 @@ void VncView::paintEvent(QPaintEvent *event)
 void VncView::resizeEvent(QResizeEvent *event)
 {
     RemoteView::resizeEvent(event);
-       /*
-    scaleResize(event->size().width(), event->size().height());
-    forceFullRepaint();
-       */
+    update();
 }
 
 bool VncView::event(QEvent *event)
@@ -558,9 +491,6 @@ void VncView::mouseEventHandler(QMouseEvent *e)
        static QTime press_time;
        static QTime up_time; //used for double clicks/tap&drag, for time after first tap
 
-       const int TAP_PRESS_TIME = 180;
-       const int DOUBLE_TAP_UP_TIME = 500;
-
        if(!e) { //flush held taps
                if(tap_detected) {
                        m_buttonMask |= 0x01;
@@ -640,9 +570,9 @@ void VncView::mouseEventHandler(QMouseEvent *e)
        if(((m_dotCursorState == CursorOn) || m_forceLocalCursor)
        and (cursor_x != old_cursor_x or cursor_y != old_cursor_y)) {
                //clear last position
-               repaint(old_cursor_x*m_horizontalFactor - cursor_size/2, old_cursor_y*m_verticalFactor - cursor_size/2, cursor_size, cursor_size);
+               repaint(old_cursor_x*m_horizontalFactor - CURSOR_SIZE/2, old_cursor_y*m_verticalFactor - CURSOR_SIZE/2, CURSOR_SIZE, CURSOR_SIZE);
                //and refresh new one
-               repaint(cursor_x*m_horizontalFactor - cursor_size/2, cursor_y*m_verticalFactor - cursor_size/2, cursor_size, cursor_size);
+               repaint(cursor_x*m_horizontalFactor - CURSOR_SIZE/2, cursor_y*m_verticalFactor - CURSOR_SIZE/2, CURSOR_SIZE, CURSOR_SIZE);
 
                old_cursor_x = cursor_x; old_cursor_y = cursor_y;
        }
@@ -886,10 +816,12 @@ void VncView::sendKeySequence(QKeySequence keys)
 
        //to get at individual key presses, we split 'keys' into its components
        QList<int> key_list;
-       for(int i = 0; ; i++) {
-               QString k = keys.toString().section('+', i, i);
+       int pos = 0;
+       while(true) {
+               QString k = keys.toString().section('+', pos, pos);
                if(k.isEmpty())
                        break;
+
                //kDebug(5011) << "found key: " << k;
                if(k == "Alt") {
                        key_list.append(Qt::Key_Alt);
@@ -900,6 +832,8 @@ void VncView::sendKeySequence(QKeySequence keys)
                } else {
                        key_list.append(QKeySequence(k)[0]);
                }
+               
+               pos++;
        }
        
        for(int i = 0; i < key_list.count(); i++)