vmstate: port fw_cfg device
[qemu] / vnc.c
diff --git a/vnc.c b/vnc.c
index cfaf7ba..5eaef6a 100644 (file)
--- a/vnc.c
+++ b/vnc.c
@@ -30,7 +30,9 @@
 #include "qemu-timer.h"
 #include "acl.h"
 
-#define VNC_REFRESH_INTERVAL (1000 / 30)
+#define VNC_REFRESH_INTERVAL_BASE 30
+#define VNC_REFRESH_INTERVAL_INC  50
+#define VNC_REFRESH_INTERVAL_MAX  2000
 
 #include "vnc_keysym.h"
 #include "d3des.h"
@@ -215,7 +217,7 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
    3) resolutions > 1024
 */
 
-static void vnc_update_client(VncState *vs, int has_dirty);
+static int vnc_update_client(VncState *vs, int has_dirty);
 static void vnc_disconnect_start(VncState *vs);
 static void vnc_disconnect_finish(VncState *vs);
 static void vnc_init_timer(VncDisplay *vd);
@@ -751,7 +753,7 @@ static int find_and_clear_dirty_height(struct VncState *vs,
     return h;
 }
 
-static void vnc_update_client(VncState *vs, int has_dirty)
+static int vnc_update_client(VncState *vs, int has_dirty)
 {
     if (vs->need_update && vs->csock != -1) {
         VncDisplay *vd = vs->vd;
@@ -761,10 +763,10 @@ static void vnc_update_client(VncState *vs, int has_dirty)
 
         if (vs->output.offset && !vs->audio_cap && !vs->force_update)
             /* kernel send buffers are full -> drop frames to throttle */
-            return;
+            return 0;
 
         if (!has_dirty && !vs->audio_cap && !vs->force_update)
-            return;
+            return 0;
 
         /*
          * Send screen updates to the vnc client using the server
@@ -806,11 +808,13 @@ static void vnc_update_client(VncState *vs, int has_dirty)
         vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
         vnc_flush(vs);
         vs->force_update = 0;
-
+        return n_rectangles;
     }
 
     if (vs->csock == -1)
         vnc_disconnect_finish(vs);
+
+    return 0;
 }
 
 /* audio */
@@ -1701,6 +1705,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 {
     int i;
     uint16_t limit;
+    VncDisplay *vd = vs->vd;
+
+    if (data[0] > 3) {
+        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+        if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
+            qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
+    }
 
     switch (data[0]) {
     case 0:
@@ -2104,7 +2115,7 @@ static void vnc_refresh(void *opaque)
 {
     VncDisplay *vd = opaque;
     VncState *vs = NULL;
-    int has_dirty = 0;
+    int has_dirty = 0, rects = 0;
 
     vga_hw_update();
 
@@ -2112,15 +2123,25 @@ static void vnc_refresh(void *opaque)
 
     vs = vd->clients;
     while (vs != NULL) {
-        vnc_update_client(vs, has_dirty);
+        rects += vnc_update_client(vs, has_dirty);
         vs = vs->next;
     }
 
-    qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+    if (has_dirty && rects) {
+        vd->timer_interval /= 2;
+        if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+    } else {
+        vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
+        if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
+    }
+    qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
 }
 
 static void vnc_init_timer(VncDisplay *vd)
 {
+    vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
     if (vd->timer == NULL && vd->clients != NULL) {
         vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
         vnc_refresh(vd);
@@ -2242,6 +2263,10 @@ int vnc_display_password(DisplayState *ds, const char *password)
 {
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
+    if (!vs) {
+        return -1;
+    }
+
     if (vs->password) {
         qemu_free(vs->password);
         vs->password = NULL;
@@ -2249,6 +2274,11 @@ int vnc_display_password(DisplayState *ds, const char *password)
     if (password && password[0]) {
         if (!(vs->password = qemu_strdup(password)))
             return -1;
+        if (vs->auth == VNC_AUTH_NONE) {
+            vs->auth = VNC_AUTH_VNC;
+        }
+    } else {
+        vs->auth = VNC_AUTH_NONE;
     }
 
     return 0;