Fix interrupt controller address masking
[qemu] / vnc.c
diff --git a/vnc.c b/vnc.c
index 92e48c5..70d30d9 100644 (file)
--- a/vnc.c
+++ b/vnc.c
@@ -68,6 +68,13 @@ struct VncState
     int depth; /* internal VNC frame buffer byte per pixel */
     int has_resize;
     int has_hextile;
+    int has_pointer_type_change;
+    int absolute;
+    int last_x;
+    int last_y;
+
+    const char *display;
+
     Buffer output;
     Buffer input;
     kbd_layout_t *kbd_layout;
@@ -85,6 +92,24 @@ struct VncState
     uint8_t modifiers_state[256];
 };
 
+static VncState *vnc_state; /* needed for info vnc */
+
+void do_info_vnc(void)
+{
+    if (vnc_state == NULL)
+       term_printf("VNC server disabled\n");
+    else {
+       term_printf("VNC server active on: ");
+       term_print_filename(vnc_state->display);
+       term_printf("\n");
+
+       if (vnc_state->csock == -1)
+           term_printf("No client connected\n");
+       else
+           term_printf("Client connected\n");
+    }
+}
+
 /* TODO
    1) Get the queue working for IO.
    2) there is some weirdness when using the -S option (the screen is grey
@@ -671,6 +696,19 @@ static void client_cut_text(VncState *vs, size_t len, char *text)
 {
 }
 
+static void check_pointer_type_change(VncState *vs, int absolute)
+{
+    if (vs->has_pointer_type_change && vs->absolute != absolute) {
+       vnc_write_u8(vs, 0);
+       vnc_write_u8(vs, 0);
+       vnc_write_u16(vs, 1);
+       vnc_framebuffer_update(vs, absolute, 0,
+                              vs->ds->width, vs->ds->height, -257);
+       vnc_flush(vs);
+    }
+    vs->absolute = absolute;
+}
+
 static void pointer_event(VncState *vs, int button_mask, int x, int y)
 {
     int buttons = 0;
@@ -686,21 +724,26 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
        dz = -1;
     if (button_mask & 0x10)
        dz = 1;
-           
-    if (kbd_mouse_is_absolute()) {
+
+    if (vs->absolute) {
        kbd_mouse_event(x * 0x7FFF / vs->ds->width,
                        y * 0x7FFF / vs->ds->height,
                        dz, buttons);
-    } else {
-       static int last_x = -1;
-       static int last_y = -1;
-
-       if (last_x != -1)
-           kbd_mouse_event(x - last_x, y - last_y, dz, buttons);
+    } else if (vs->has_pointer_type_change) {
+       x -= 0x7FFF;
+       y -= 0x7FFF;
 
-       last_x = x;
-       last_y = y;
+       kbd_mouse_event(x, y, dz, buttons);
+    } else {
+       if (vs->last_x != -1)
+           kbd_mouse_event(x - vs->last_x,
+                           y - vs->last_y,
+                           dz, buttons);
+       vs->last_x = x;
+       vs->last_y = y;
     }
+
+    check_pointer_type_change(vs, kbd_mouse_is_absolute());
 }
 
 static void reset_keys(VncState *vs)
@@ -809,6 +852,15 @@ static void framebuffer_update_request(VncState *vs, int incremental,
                                       int x_position, int y_position,
                                       int w, int h)
 {
+    if (x_position > vs->ds->width)
+        x_position = vs->ds->width;
+    if (y_position > vs->ds->height)
+        y_position = vs->ds->height;
+    if (x_position + w >= vs->ds->width)
+        w = vs->ds->width  - x_position;
+    if (y_position + h >= vs->ds->height)
+        h = vs->ds->height - y_position;
+
     int i;
     vs->need_update = 1;
     if (!incremental) {
@@ -829,6 +881,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 
     vs->has_hextile = 0;
     vs->has_resize = 0;
+    vs->has_pointer_type_change = 0;
+    vs->absolute = -1;
     vs->ds->dpy_copy = NULL;
 
     for (i = n_encodings - 1; i >= 0; i--) {
@@ -845,10 +899,15 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
        case -223: /* DesktopResize */
            vs->has_resize = 1;
            break;
+       case -257:
+           vs->has_pointer_type_change = 1;
+           break;
        default:
            break;
        }
     }
+
+    check_pointer_type_change(vs, kbd_mouse_is_absolute());
 }
 
 static int compute_nbits(unsigned int val)
@@ -1006,6 +1065,8 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len)
 static int protocol_client_init(VncState *vs, char *data, size_t len)
 {
     char pad[3] = { 0, 0, 0 };
+    char buf[1024];
+    int size;
 
     vs->width = vs->ds->width;
     vs->height = vs->ds->height;
@@ -1050,8 +1111,13 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
        
     vnc_write(vs, pad, 3);           /* padding */
 
-    vnc_write_u32(vs, 4);        
-    vnc_write(vs, "QEMU", 4);
+    if (qemu_name)
+        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
+    else
+        size = snprintf(buf, sizeof(buf), "QEMU");
+
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
     vnc_flush(vs);
 
     vnc_read_when(vs, protocol_client_msg, 1);
@@ -1101,10 +1167,18 @@ static void vnc_listen_read(void *opaque)
     }
 }
 
-void vnc_display_init(DisplayState *ds, int display)
+extern int parse_host_port(struct sockaddr_in *saddr, const char *str);
+
+void vnc_display_init(DisplayState *ds, const char *arg)
 {
-    struct sockaddr_in addr;
+    struct sockaddr *addr;
+    struct sockaddr_in iaddr;
+#ifndef _WIN32
+    struct sockaddr_un uaddr;
+#endif
     int reuse_addr, ret;
+    socklen_t addrlen;
+    const char *p;
     VncState *vs;
 
     vs = qemu_mallocz(sizeof(VncState));
@@ -1112,10 +1186,14 @@ void vnc_display_init(DisplayState *ds, int display)
        exit(1);
 
     ds->opaque = vs;
+    vnc_state = vs;
+    vs->display = arg;
 
     vs->lsock = -1;
     vs->csock = -1;
     vs->depth = 4;
+    vs->last_x = -1;
+    vs->last_y = -1;
 
     vs->ds = ds;
 
@@ -1126,25 +1204,60 @@ void vnc_display_init(DisplayState *ds, int display)
     if (!vs->kbd_layout)
        exit(1);
 
-    vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
-    if (vs->lsock == -1) {
-       fprintf(stderr, "Could not create socket\n");
-       exit(1);
-    }
+    vs->ds->data = NULL;
+    vs->ds->dpy_update = vnc_dpy_update;
+    vs->ds->dpy_resize = vnc_dpy_resize;
+    vs->ds->dpy_refresh = vnc_dpy_refresh;
 
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(5900 + display);
-    memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
+    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
 
-    reuse_addr = 1;
-    ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
-                    (const char *)&reuse_addr, sizeof(reuse_addr));
-    if (ret == -1) {
-       fprintf(stderr, "setsockopt() failed\n");
-       exit(1);
+    vnc_dpy_resize(vs->ds, 640, 400);
+
+#ifndef _WIN32
+    if (strstart(arg, "unix:", &p)) {
+       addr = (struct sockaddr *)&uaddr;
+       addrlen = sizeof(uaddr);
+
+       vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (vs->lsock == -1) {
+           fprintf(stderr, "Could not create socket\n");
+           exit(1);
+       }
+
+       uaddr.sun_family = AF_UNIX;
+       memset(uaddr.sun_path, 0, 108);
+       snprintf(uaddr.sun_path, 108, "%s", p);
+
+       unlink(uaddr.sun_path);
+    } else
+#endif
+    {
+       addr = (struct sockaddr *)&iaddr;
+       addrlen = sizeof(iaddr);
+
+       vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
+       if (vs->lsock == -1) {
+           fprintf(stderr, "Could not create socket\n");
+           exit(1);
+       }
+
+       if (parse_host_port(&iaddr, arg) < 0) {
+           fprintf(stderr, "Could not parse VNC address\n");
+           exit(1);
+       }
+           
+       iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
+
+       reuse_addr = 1;
+       ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
+                        (const char *)&reuse_addr, sizeof(reuse_addr));
+       if (ret == -1) {
+           fprintf(stderr, "setsockopt() failed\n");
+           exit(1);
+       }
     }
 
-    if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+    if (bind(vs->lsock, addr, addrlen) == -1) {
        fprintf(stderr, "bind() failed\n");
        exit(1);
     }
@@ -1158,13 +1271,4 @@ void vnc_display_init(DisplayState *ds, int display)
     if (ret == -1) {
        exit(1);
     }
-
-    vs->ds->data = NULL;
-    vs->ds->dpy_update = vnc_dpy_update;
-    vs->ds->dpy_resize = vnc_dpy_resize;
-    vs->ds->dpy_refresh = vnc_dpy_refresh;
-
-    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
-
-    vnc_dpy_resize(vs->ds, 640, 400);
 }