]> git.proxmox.com Git - qemu.git/commitdiff
ui: move all ui components in ui/
authorCorentin Chary <corentincj@iksaif.net>
Wed, 7 Jul 2010 18:57:52 +0000 (20:57 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 26 Jul 2010 22:35:54 +0000 (17:35 -0500)
Move sdl, vnc, curses and cocoa UI into ui/ to cleanup
the root directory. Also remove some unnecessary explicit
targets from Makefile.

aliguori: fix build when srcdir != objdir

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
59 files changed:
Makefile
Makefile.objs
cocoa.m [deleted file]
configure
curses.c [deleted file]
curses_keys.h [deleted file]
d3des.c [deleted file]
d3des.h [deleted file]
keymaps.c [deleted file]
keymaps.h [deleted file]
sdl.c [deleted file]
sdl_keysym.h [deleted file]
sdl_zoom.c [deleted file]
sdl_zoom.h [deleted file]
sdl_zoom_template.h [deleted file]
ui/cocoa.m [new file with mode: 0644]
ui/curses.c [new file with mode: 0644]
ui/curses_keys.h [new file with mode: 0644]
ui/d3des.c [new file with mode: 0644]
ui/d3des.h [new file with mode: 0644]
ui/keymaps.c [new file with mode: 0644]
ui/keymaps.h [new file with mode: 0644]
ui/sdl.c [new file with mode: 0644]
ui/sdl_keysym.h [new file with mode: 0644]
ui/sdl_zoom.c [new file with mode: 0644]
ui/sdl_zoom.h [new file with mode: 0644]
ui/sdl_zoom_template.h [new file with mode: 0644]
ui/vnc-auth-sasl.c [new file with mode: 0644]
ui/vnc-auth-sasl.h [new file with mode: 0644]
ui/vnc-auth-vencrypt.c [new file with mode: 0644]
ui/vnc-auth-vencrypt.h [new file with mode: 0644]
ui/vnc-encoding-hextile.c [new file with mode: 0644]
ui/vnc-encoding-tight.c [new file with mode: 0644]
ui/vnc-encoding-tight.h [new file with mode: 0644]
ui/vnc-encoding-zlib.c [new file with mode: 0644]
ui/vnc-tls.c [new file with mode: 0644]
ui/vnc-tls.h [new file with mode: 0644]
ui/vnc.c [new file with mode: 0644]
ui/vnc.h [new file with mode: 0644]
ui/vnc_keysym.h [new file with mode: 0644]
ui/vnchextile.h [new file with mode: 0644]
ui/x_keymap.c [new file with mode: 0644]
ui/x_keymap.h [new file with mode: 0644]
vnc-auth-sasl.c [deleted file]
vnc-auth-sasl.h [deleted file]
vnc-auth-vencrypt.c [deleted file]
vnc-auth-vencrypt.h [deleted file]
vnc-encoding-hextile.c [deleted file]
vnc-encoding-tight.c [deleted file]
vnc-encoding-tight.h [deleted file]
vnc-encoding-zlib.c [deleted file]
vnc-tls.c [deleted file]
vnc-tls.h [deleted file]
vnc.c [deleted file]
vnc.h [deleted file]
vnc_keysym.h [deleted file]
vnchextile.h [deleted file]
x_keymap.c [deleted file]
x_keymap.h [deleted file]

index 6fc1b2c89bb30a580af23c682e47279c7cbb4c89..f95cc2fd01f253d1970cb78a429ec543607d0691 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -96,42 +96,14 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
-cocoa.o: cocoa.m
+ui/cocoa.o: ui/cocoa.m
 
-keymaps.o: keymaps.c keymaps.h
+ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 
-sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
-
-sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
-
-sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
-
-acl.o: acl.h acl.c
-
-vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
-
-vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
-
-vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
-
-vnc-tls.o: vnc-tls.c vnc.h
-
-vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
-
-vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
-
-vnc-encoding-zlib.o: vnc-encoding-zlib.c vnc.h
-
-vnc-encoding-hextile.o: vnc-encoding-hextile.c vnc.h
-
-vnc-encoding-tight.o: vnc-encoding-tight.c vnc.h vnc-encoding-tight.h
-
-curses.o: curses.c keymaps.h curses_keys.h
+ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
-iov.o: iov.c iov.h
-
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
@@ -159,7 +131,7 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
        rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
-       rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d
+       rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
        rm -f qemu-img-cmds.h
        $(MAKE) -C tests clean
        for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
@@ -345,4 +317,4 @@ tarbin:
        $(mandir)/man8/qemu-nbd.8
 
 # Include automatically generated dependency files
--include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
+-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
index 67f1b215b146bf9f2b6f35ab04a8f4c5f9c5b8ee..43b4e169e333be6a83f34952c3cccb9f563ca3fe 100644 (file)
@@ -102,16 +102,18 @@ audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 audio-obj-y += wavcapture.o
 common-obj-y += $(addprefix audio/, $(audio-obj-y))
 
-common-obj-y += keymaps.o
-common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
-common-obj-$(CONFIG_CURSES) += curses.o
-common-obj-y += vnc.o acl.o d3des.o
-common-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o
-common-obj-y += vnc-encoding-tight.o
-common-obj-y += iov.o
-common-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
-common-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
-common-obj-$(CONFIG_COCOA) += cocoa.o
+ui-obj-y += keymaps.o
+ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+ui-obj-$(CONFIG_CURSES) += curses.o
+ui-obj-y += vnc.o d3des.o
+ui-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o
+ui-obj-y += vnc-encoding-tight.o
+ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
+ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
+ui-obj-$(CONFIG_COCOA) += cocoa.o
+common-obj-y += $(addprefix ui/, $(ui-obj-y))
+
+common-obj-y += iov.o acl.o
 common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
 common-obj-y += notify.o event_notifier.o
 common-obj-y += qemu-timer.o
diff --git a/cocoa.m b/cocoa.m
deleted file mode 100644 (file)
index 56c789a..0000000
--- a/cocoa.m
+++ /dev/null
@@ -1,1014 +0,0 @@
-/*
- * QEMU Cocoa CG display driver
- *
- * Copyright (c) 2008 Mike Kronenberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#include "qemu-common.h"
-#include "console.h"
-#include "sysemu.h"
-
-#ifndef MAC_OS_X_VERSION_10_4
-#define MAC_OS_X_VERSION_10_4 1040
-#endif
-#ifndef MAC_OS_X_VERSION_10_5
-#define MAC_OS_X_VERSION_10_5 1050
-#endif
-
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define COCOA_DEBUG(...)  { (void) fprintf (stdout, __VA_ARGS__); }
-#else
-#define COCOA_DEBUG(...)  ((void) 0)
-#endif
-
-#define cgrect(nsrect) (*(CGRect *)&(nsrect))
-#define COCOA_MOUSE_EVENT \
-        if (isTabletEnabled) { \
-            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
-        } else if (isMouseGrabed) { \
-            kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
-        } else { \
-            [NSApp sendEvent:event]; \
-        }
-
-typedef struct {
-    int width;
-    int height;
-    int bitsPerComponent;
-    int bitsPerPixel;
-} QEMUScreen;
-
-int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
-NSWindow *normalWindow;
-id cocoaView;
-static DisplayChangeListener *dcl;
-
-int gArgc;
-char **gArgv;
-
-// keymap conversion
-int keymap[] =
-{
-//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
-    30, //  0       0x00    0x1e            A       QZ_a
-    31, //  1       0x01    0x1f            S       QZ_s
-    32, //  2       0x02    0x20            D       QZ_d
-    33, //  3       0x03    0x21            F       QZ_f
-    35, //  4       0x04    0x23            H       QZ_h
-    34, //  5       0x05    0x22            G       QZ_g
-    44, //  6       0x06    0x2c            Z       QZ_z
-    45, //  7       0x07    0x2d            X       QZ_x
-    46, //  8       0x08    0x2e            C       QZ_c
-    47, //  9       0x09    0x2f            V       QZ_v
-    0,  //  10      0x0A    Undefined
-    48, //  11      0x0B    0x30            B       QZ_b
-    16, //  12      0x0C    0x10            Q       QZ_q
-    17, //  13      0x0D    0x11            W       QZ_w
-    18, //  14      0x0E    0x12            E       QZ_e
-    19, //  15      0x0F    0x13            R       QZ_r
-    21, //  16      0x10    0x15            Y       QZ_y
-    20, //  17      0x11    0x14            T       QZ_t
-    2,  //  18      0x12    0x02            1       QZ_1
-    3,  //  19      0x13    0x03            2       QZ_2
-    4,  //  20      0x14    0x04            3       QZ_3
-    5,  //  21      0x15    0x05            4       QZ_4
-    7,  //  22      0x16    0x07            6       QZ_6
-    6,  //  23      0x17    0x06            5       QZ_5
-    13, //  24      0x18    0x0d            =       QZ_EQUALS
-    10, //  25      0x19    0x0a            9       QZ_9
-    8,  //  26      0x1A    0x08            7       QZ_7
-    12, //  27      0x1B    0x0c            -       QZ_MINUS
-    9,  //  28      0x1C    0x09            8       QZ_8
-    11, //  29      0x1D    0x0b            0       QZ_0
-    27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
-    24, //  31      0x1F    0x18            O       QZ_o
-    22, //  32      0x20    0x16            U       QZ_u
-    26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
-    23, //  34      0x22    0x17            I       QZ_i
-    25, //  35      0x23    0x19            P       QZ_p
-    28, //  36      0x24    0x1c            ENTER   QZ_RETURN
-    38, //  37      0x25    0x26            L       QZ_l
-    36, //  38      0x26    0x24            J       QZ_j
-    40, //  39      0x27    0x28            '       QZ_QUOTE
-    37, //  40      0x28    0x25            K       QZ_k
-    39, //  41      0x29    0x27            ;       QZ_SEMICOLON
-    43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
-    51, //  43      0x2B    0x33            ,       QZ_COMMA
-    53, //  44      0x2C    0x35            /       QZ_SLASH
-    49, //  45      0x2D    0x31            N       QZ_n
-    50, //  46      0x2E    0x32            M       QZ_m
-    52, //  47      0x2F    0x34            .       QZ_PERIOD
-    15, //  48      0x30    0x0f            TAB     QZ_TAB
-    57, //  49      0x31    0x39            SPACE   QZ_SPACE
-    41, //  50      0x32    0x29            `       QZ_BACKQUOTE
-    14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
-    0,  //  52      0x34    Undefined
-    1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
-    0,  //  54      0x36                            QZ_RMETA
-    0,  //  55      0x37                            QZ_LMETA
-    42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
-    58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
-    56, //  58      0x3A    0x38            L ALT   QZ_LALT
-    29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
-    54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
-    184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
-    157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
-    0,  //  63      0x3F    Undefined
-    0,  //  64      0x40    Undefined
-    0,  //  65      0x41    Undefined
-    0,  //  66      0x42    Undefined
-    55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
-    0,  //  68      0x44    Undefined
-    78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
-    0,  //  70      0x46    Undefined
-    69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
-    0,  //  72      0x48    Undefined
-    0,  //  73      0x49    Undefined
-    0,  //  74      0x4A    Undefined
-    181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
-    152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
-    0,  //  77      0x4D    undefined
-    74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
-    0,  //  79      0x4F    Undefined
-    0,  //  80      0x50    Undefined
-    0,  //  81      0x51                            QZ_KP_EQUALS
-    82, //  82      0x52    0x52            KP 0    QZ_KP0
-    79, //  83      0x53    0x4f            KP 1    QZ_KP1
-    80, //  84      0x54    0x50            KP 2    QZ_KP2
-    81, //  85      0x55    0x51            KP 3    QZ_KP3
-    75, //  86      0x56    0x4b            KP 4    QZ_KP4
-    76, //  87      0x57    0x4c            KP 5    QZ_KP5
-    77, //  88      0x58    0x4d            KP 6    QZ_KP6
-    71, //  89      0x59    0x47            KP 7    QZ_KP7
-    0,  //  90      0x5A    Undefined
-    72, //  91      0x5B    0x48            KP 8    QZ_KP8
-    73, //  92      0x5C    0x49            KP 9    QZ_KP9
-    0,  //  93      0x5D    Undefined
-    0,  //  94      0x5E    Undefined
-    0,  //  95      0x5F    Undefined
-    63, //  96      0x60    0x3f            F5      QZ_F5
-    64, //  97      0x61    0x40            F6      QZ_F6
-    65, //  98      0x62    0x41            F7      QZ_F7
-    61, //  99      0x63    0x3d            F3      QZ_F3
-    66, //  100     0x64    0x42            F8      QZ_F8
-    67, //  101     0x65    0x43            F9      QZ_F9
-    0,  //  102     0x66    Undefined
-    87, //  103     0x67    0x57            F11     QZ_F11
-    0,  //  104     0x68    Undefined
-    183,//  105     0x69    0xb7                    QZ_PRINT
-    0,  //  106     0x6A    Undefined
-    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
-    0,  //  108     0x6C    Undefined
-    68, //  109     0x6D    0x44            F10     QZ_F10
-    0,  //  110     0x6E    Undefined
-    88, //  111     0x6F    0x58            F12     QZ_F12
-    0,  //  112     0x70    Undefined
-    110,//  113     0x71    0x0                     QZ_PAUSE
-    210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
-    199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
-    201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
-    211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
-    62, //  118     0x76    0x3e            F4      QZ_F4
-    207,//  119     0x77    0xcf    E0,4f   END     QZ_END
-    60, //  120     0x78    0x3c            F2      QZ_F2
-    209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
-    59, //  122     0x7A    0x3b            F1      QZ_F1
-    203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
-    205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
-    208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
-    200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
-/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
-
-/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
-/*
-    219 //          0xdb            e0,5b   L GUI
-    220 //          0xdc            e0,5c   R GUI
-    221 //          0xdd            e0,5d   APPS
-        //              E0,2A,E0,37         PRNT SCRN
-        //              E1,1D,45,E1,9D,C5   PAUSE
-    83  //          0x53    0x53            KP .
-// ACPI Scan Codes
-    222 //          0xde            E0, 5E  Power
-    223 //          0xdf            E0, 5F  Sleep
-    227 //          0xe3            E0, 63  Wake
-// Windows Multimedia Scan Codes
-    153 //          0x99            E0, 19  Next Track
-    144 //          0x90            E0, 10  Previous Track
-    164 //          0xa4            E0, 24  Stop
-    162 //          0xa2            E0, 22  Play/Pause
-    160 //          0xa0            E0, 20  Mute
-    176 //          0xb0            E0, 30  Volume Up
-    174 //          0xae            E0, 2E  Volume Down
-    237 //          0xed            E0, 6D  Media Select
-    236 //          0xec            E0, 6C  E-Mail
-    161 //          0xa1            E0, 21  Calculator
-    235 //          0xeb            E0, 6B  My Computer
-    229 //          0xe5            E0, 65  WWW Search
-    178 //          0xb2            E0, 32  WWW Home
-    234 //          0xea            E0, 6A  WWW Back
-    233 //          0xe9            E0, 69  WWW Forward
-    232 //          0xe8            E0, 68  WWW Stop
-    231 //          0xe7            E0, 67  WWW Refresh
-    230 //          0xe6            E0, 66  WWW Favorites
-*/
-};
-
-static int cocoa_keycode_to_qemu(int keycode)
-{
-    if((sizeof(keymap)/sizeof(int)) <= keycode)
-    {
-        printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
-        return 0;
-    }
-    return keymap[keycode];
-}
-
-
-
-/*
- ------------------------------------------------------
-    QemuCocoaView
- ------------------------------------------------------
-*/
-@interface QemuCocoaView : NSView
-{
-    QEMUScreen screen;
-    NSWindow *fullScreenWindow;
-    float cx,cy,cw,ch,cdx,cdy;
-    CGDataProviderRef dataProviderRef;
-    int modifiers_state[256];
-    BOOL isMouseGrabed;
-    BOOL isFullscreen;
-    BOOL isAbsoluteEnabled;
-    BOOL isTabletEnabled;
-}
-- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
-- (void) grabMouse;
-- (void) ungrabMouse;
-- (void) toggleFullScreen:(id)sender;
-- (void) handleEvent:(NSEvent *)event;
-- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
-- (BOOL) isMouseGrabed;
-- (BOOL) isAbsoluteEnabled;
-- (float) cdx;
-- (float) cdy;
-- (QEMUScreen) gscreen;
-@end
-
-@implementation QemuCocoaView
-- (id)initWithFrame:(NSRect)frameRect
-{
-    COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
-
-    self = [super initWithFrame:frameRect];
-    if (self) {
-
-        screen.bitsPerComponent = 8;
-        screen.bitsPerPixel = 32;
-        screen.width = frameRect.size.width;
-        screen.height = frameRect.size.height;
-
-    }
-    return self;
-}
-
-- (void) dealloc
-{
-    COCOA_DEBUG("QemuCocoaView: dealloc\n");
-
-    if (dataProviderRef)
-        CGDataProviderRelease(dataProviderRef);
-
-    [super dealloc];
-}
-
-- (BOOL) isOpaque
-{
-    return YES;
-}
-
-- (void) drawRect:(NSRect) rect
-{
-    COCOA_DEBUG("QemuCocoaView: drawRect\n");
-
-    // get CoreGraphic context
-    CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
-    CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
-    CGContextSetShouldAntialias (viewContextRef, NO);
-
-    // draw screen bitmap directly to Core Graphics context
-    if (dataProviderRef) {
-        CGImageRef imageRef = CGImageCreate(
-            screen.width, //width
-            screen.height, //height
-            screen.bitsPerComponent, //bitsPerComponent
-            screen.bitsPerPixel, //bitsPerPixel
-            (screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
-#ifdef __LITTLE_ENDIAN__
-            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
-            kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
-#else
-            CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
-            kCGImageAlphaNoneSkipFirst, //bitmapInfo
-#endif
-            dataProviderRef, //provider
-            NULL, //decode
-            0, //interpolate
-            kCGRenderingIntentDefault //intent
-        );
-// test if host supports "CGImageCreateWithImageInRect" at compile time
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
-        if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
-#endif
-            // compatibility drawing code (draws everything) (OS X < 10.4)
-            CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
-        } else {
-            // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
-            const NSRect *rectList;
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
-            NSInteger rectCount;
-#else
-            int rectCount;
-#endif
-            int i;
-            CGImageRef clipImageRef;
-            CGRect clipRect;
-
-            [self getRectsBeingDrawn:&rectList count:&rectCount];
-            for (i = 0; i < rectCount; i++) {
-                clipRect.origin.x = rectList[i].origin.x / cdx;
-                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
-                clipRect.size.width = rectList[i].size.width / cdx;
-                clipRect.size.height = rectList[i].size.height / cdy;
-                clipImageRef = CGImageCreateWithImageInRect(
-                    imageRef,
-                    clipRect
-                );
-                CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
-                CGImageRelease (clipImageRef);
-            }
-        }
-#endif
-        CGImageRelease (imageRef);
-    }
-}
-
-- (void) setContentDimensions
-{
-    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
-
-    if (isFullscreen) {
-        cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
-        cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
-        cw = screen.width * cdx;
-        ch = screen.height * cdy;
-        cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
-        cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
-    } else {
-        cx = 0;
-        cy = 0;
-        cw = screen.width;
-        ch = screen.height;
-        cdx = 1.0;
-        cdy = 1.0;
-    }
-}
-
-- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
-{
-    COCOA_DEBUG("QemuCocoaView: resizeContent\n");
-
-    // update screenBuffer
-    if (dataProviderRef)
-        CGDataProviderRelease(dataProviderRef);
-
-    //sync host window color space with guests
-       screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
-       screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
-
-    dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
-
-    // update windows
-    if (isFullscreen) {
-        [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
-        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
-    } else {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
-        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
-    }
-    screen.width = w;
-    screen.height = h;
-       [normalWindow center];
-    [self setContentDimensions];
-    [self setFrame:NSMakeRect(cx, cy, cw, ch)];
-}
-
-- (void) toggleFullScreen:(id)sender
-{
-    COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
-
-    if (isFullscreen) { // switch from fullscreen to desktop
-        isFullscreen = FALSE;
-        [self ungrabMouse];
-        [self setContentDimensions];
-// test if host supports "exitFullScreenModeWithOptions" at compile time
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
-        if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
-            [self exitFullScreenModeWithOptions:nil];
-        } else {
-#endif
-            [fullScreenWindow close];
-            [normalWindow setContentView: self];
-            [normalWindow makeKeyAndOrderFront: self];
-            [NSMenu setMenuBarVisible:YES];
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
-        }
-#endif
-    } else { // switch from desktop to fullscreen
-        isFullscreen = TRUE;
-        [self grabMouse];
-        [self setContentDimensions];
-// test if host supports "enterFullScreenMode:withOptions" at compile time
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
-        if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
-            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
-                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
-                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
-                 nil]];
-        } else {
-#endif
-            [NSMenu setMenuBarVisible:NO];
-            fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
-                styleMask:NSBorderlessWindowMask
-                backing:NSBackingStoreBuffered
-                defer:NO];
-            [fullScreenWindow setHasShadow:NO];
-            [fullScreenWindow setContentView:self];
-            [fullScreenWindow makeKeyAndOrderFront:self];
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
-        }
-#endif
-    }
-}
-
-- (void) handleEvent:(NSEvent *)event
-{
-    COCOA_DEBUG("QemuCocoaView: handleEvent\n");
-
-    int buttons = 0;
-    int keycode;
-    NSPoint p = [event locationInWindow];
-
-    switch ([event type]) {
-        case NSFlagsChanged:
-            keycode = cocoa_keycode_to_qemu([event keyCode]);
-            if (keycode) {
-                if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
-                    kbd_put_keycode(keycode);
-                    kbd_put_keycode(keycode | 0x80);
-                } else if (is_graphic_console()) {
-                    if (keycode & 0x80)
-                        kbd_put_keycode(0xe0);
-                    if (modifiers_state[keycode] == 0) { // keydown
-                        kbd_put_keycode(keycode & 0x7f);
-                        modifiers_state[keycode] = 1;
-                    } else { // keyup
-                        kbd_put_keycode(keycode | 0x80);
-                        modifiers_state[keycode] = 0;
-                    }
-                }
-            }
-
-            // release Mouse grab when pressing ctrl+alt
-            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
-                [self ungrabMouse];
-            }
-            break;
-        case NSKeyDown:
-
-            // forward command Key Combos
-            if ([event modifierFlags] & NSCommandKeyMask) {
-                [NSApp sendEvent:event];
-                return;
-            }
-
-            // default
-            keycode = cocoa_keycode_to_qemu([event keyCode]);
-
-            // handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
-            if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
-                switch (keycode) {
-
-                    // enable graphic console
-                    case 0x02 ... 0x0a: // '1' to '9' keys
-                        console_select(keycode - 0x02);
-                        break;
-                }
-
-            // handle keys for graphic console
-            } else if (is_graphic_console()) {
-                if (keycode & 0x80) //check bit for e0 in front
-                    kbd_put_keycode(0xe0);
-                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
-
-            // handlekeys for Monitor
-            } else {
-                int keysym = 0;
-                switch([event keyCode]) {
-                case 115:
-                    keysym = QEMU_KEY_HOME;
-                    break;
-                case 117:
-                    keysym = QEMU_KEY_DELETE;
-                    break;
-                case 119:
-                    keysym = QEMU_KEY_END;
-                    break;
-                case 123:
-                    keysym = QEMU_KEY_LEFT;
-                    break;
-                case 124:
-                    keysym = QEMU_KEY_RIGHT;
-                    break;
-                case 125:
-                    keysym = QEMU_KEY_DOWN;
-                    break;
-                case 126:
-                    keysym = QEMU_KEY_UP;
-                    break;
-                default:
-                    {
-                        NSString *ks = [event characters];
-                        if ([ks length] > 0)
-                            keysym = [ks characterAtIndex:0];
-                    }
-                }
-                if (keysym)
-                    kbd_put_keysym(keysym);
-            }
-            break;
-        case NSKeyUp:
-            keycode = cocoa_keycode_to_qemu([event keyCode]);
-            if (is_graphic_console()) {
-                if (keycode & 0x80)
-                    kbd_put_keycode(0xe0);
-                kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
-            }
-            break;
-        case NSMouseMoved:
-            if (isAbsoluteEnabled) {
-                if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
-                    if (isTabletEnabled) { // if we leave the window, deactivate the tablet
-                        [NSCursor unhide];
-                        isTabletEnabled = FALSE;
-                    }
-                } else {
-                    if (!isTabletEnabled) { // if we enter the window, activate the tablet
-                        [NSCursor hide];
-                        isTabletEnabled = TRUE;
-                    }
-                }
-            }
-            COCOA_MOUSE_EVENT
-            break;
-        case NSLeftMouseDown:
-            if ([event modifierFlags] & NSCommandKeyMask) {
-                buttons |= MOUSE_EVENT_RBUTTON;
-            } else {
-                buttons |= MOUSE_EVENT_LBUTTON;
-            }
-            COCOA_MOUSE_EVENT
-            break;
-        case NSRightMouseDown:
-            buttons |= MOUSE_EVENT_RBUTTON;
-            COCOA_MOUSE_EVENT
-            break;
-        case NSOtherMouseDown:
-            buttons |= MOUSE_EVENT_MBUTTON;
-            COCOA_MOUSE_EVENT
-            break;
-        case NSLeftMouseDragged:
-            if ([event modifierFlags] & NSCommandKeyMask) {
-                buttons |= MOUSE_EVENT_RBUTTON;
-            } else {
-                buttons |= MOUSE_EVENT_LBUTTON;
-            }
-            COCOA_MOUSE_EVENT
-            break;
-        case NSRightMouseDragged:
-            buttons |= MOUSE_EVENT_RBUTTON;
-            COCOA_MOUSE_EVENT
-            break;
-        case NSOtherMouseDragged:
-            buttons |= MOUSE_EVENT_MBUTTON;
-            COCOA_MOUSE_EVENT
-            break;
-        case NSLeftMouseUp:
-            if (isTabletEnabled) {
-                    COCOA_MOUSE_EVENT
-            } else if (!isMouseGrabed) {
-                if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
-                    [self grabMouse];
-                } else {
-                    [NSApp sendEvent:event];
-                }
-            } else {
-                COCOA_MOUSE_EVENT
-            }
-            break;
-        case NSRightMouseUp:
-            COCOA_MOUSE_EVENT
-            break;
-        case NSOtherMouseUp:
-            COCOA_MOUSE_EVENT
-            break;
-        case NSScrollWheel:
-            if (isTabletEnabled || isMouseGrabed) {
-                kbd_mouse_event(0, 0, -[event deltaY], 0);
-            } else {
-                [NSApp sendEvent:event];
-            }
-            break;
-        default:
-            [NSApp sendEvent:event];
-    }
-}
-
-- (void) grabMouse
-{
-    COCOA_DEBUG("QemuCocoaView: grabMouse\n");
-
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
-    }
-    [NSCursor hide];
-    CGAssociateMouseAndMouseCursorPosition(FALSE);
-    isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
-}
-
-- (void) ungrabMouse
-{
-    COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
-
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU"];
-    }
-    [NSCursor unhide];
-    CGAssociateMouseAndMouseCursorPosition(TRUE);
-    isMouseGrabed = FALSE;
-}
-
-- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
-- (BOOL) isMouseGrabed {return isMouseGrabed;}
-- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
-- (float) cdx {return cdx;}
-- (float) cdy {return cdy;}
-- (QEMUScreen) gscreen {return screen;}
-@end
-
-
-
-/*
- ------------------------------------------------------
-    QemuCocoaAppController
- ------------------------------------------------------
-*/
-@interface QemuCocoaAppController : NSObject
-{
-}
-- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
-- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-- (void)toggleFullScreen:(id)sender;
-- (void)showQEMUDoc:(id)sender;
-- (void)showQEMUTec:(id)sender;
-@end
-
-@implementation QemuCocoaAppController
-- (id) init
-{
-    COCOA_DEBUG("QemuCocoaAppController: init\n");
-
-    self = [super init];
-    if (self) {
-
-        // create a view and add it to the window
-        cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
-        if(!cocoaView) {
-            fprintf(stderr, "(cocoa) can't create a view\n");
-            exit(1);
-        }
-
-        // create a window
-        normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
-            styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
-            backing:NSBackingStoreBuffered defer:NO];
-        if(!normalWindow) {
-            fprintf(stderr, "(cocoa) can't create window\n");
-            exit(1);
-        }
-        [normalWindow setAcceptsMouseMovedEvents:YES];
-        [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
-        [normalWindow setContentView:cocoaView];
-        [normalWindow useOptimizedDrawing:YES];
-        [normalWindow makeKeyAndOrderFront:self];
-               [normalWindow center];
-
-    }
-    return self;
-}
-
-- (void) dealloc
-{
-    COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
-
-    if (cocoaView)
-        [cocoaView release];
-    [super dealloc];
-}
-
-- (void)applicationDidFinishLaunching: (NSNotification *) note
-{
-    COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
-
-    // Display an open dialog box if no argument were passed or
-    // if qemu was launched from the finder ( the Finder passes "-psn" )
-    if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
-        NSOpenPanel *op = [[NSOpenPanel alloc] init];
-        [op setPrompt:@"Boot image"];
-        [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
-        [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
-              modalForWindow:normalWindow modalDelegate:self
-              didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
-    } else {
-        // or Launch Qemu, with the global args
-        [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
-    }
-}
-
-- (void)applicationWillTerminate:(NSNotification *)aNotification
-{
-    COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
-
-    qemu_system_shutdown_request();
-    exit(0);
-}
-
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
-{
-    return YES;
-}
-
-- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
-{
-    COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
-
-    int status;
-    status = qemu_main(argc, argv);
-    exit(status);
-}
-
-- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
-    COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
-
-    if(returnCode == NSCancelButton) {
-        exit(0);
-    } else if(returnCode == NSOKButton) {
-        const char *bin = "qemu";
-        char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
-
-        char **argv = (char**)malloc( sizeof(char*)*3 );
-
-        asprintf(&argv[0], "%s", bin);
-        asprintf(&argv[1], "-hda");
-        asprintf(&argv[2], "%s", img);
-
-        printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
-
-        [self startEmulationWithArgc:3 argv:(char**)argv];
-    }
-}
-- (void)toggleFullScreen:(id)sender
-{
-    COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
-
-    [cocoaView toggleFullScreen:sender];
-}
-
-- (void)showQEMUDoc:(id)sender
-{
-    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
-
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
-}
-
-- (void)showQEMUTec:(id)sender
-{
-    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
-
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
-}
-@end
-
-
-
-// Dock Connection
-typedef struct CPSProcessSerNum
-{
-        UInt32                lo;
-        UInt32                hi;
-} CPSProcessSerNum;
-
-extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
-extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
-
-int main (int argc, const char * argv[]) {
-
-    gArgc = argc;
-    gArgv = (char **)argv;
-    CPSProcessSerNum PSN;
-    int i;
-
-    /* In case we don't need to display a window, let's not do that */
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-vnc") ||
-            !strcmp(argv[i], "-nographic") ||
-            !strcmp(argv[i], "-curses")) {
-                return qemu_main(gArgc, gArgv);
-        }
-    }
-
-    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-    [NSApplication sharedApplication];
-
-    if (!CPSGetCurrentProcess(&PSN))
-        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
-            if (!CPSSetFrontProcess(&PSN))
-                [NSApplication sharedApplication];
-
-    // Add menus
-    NSMenu      *menu;
-    NSMenuItem  *menuItem;
-
-    [NSApp setMainMenu:[[NSMenu alloc] init]];
-
-    // Application menu
-    menu = [[NSMenu alloc] initWithTitle:@""];
-    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
-    [menu addItem:[NSMenuItem separatorItem]]; //Separator
-    [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
-    menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
-    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
-    [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
-    [menu addItem:[NSMenuItem separatorItem]]; //Separator
-    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
-    menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
-    [menuItem setSubmenu:menu];
-    [[NSApp mainMenu] addItem:menuItem];
-    [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
-
-    // View menu
-    menu = [[NSMenu alloc] initWithTitle:@"View"];
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
-    menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
-    [menuItem setSubmenu:menu];
-    [[NSApp mainMenu] addItem:menuItem];
-
-    // Window menu
-    menu = [[NSMenu alloc] initWithTitle:@"Window"];
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
-    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
-    [menuItem setSubmenu:menu];
-    [[NSApp mainMenu] addItem:menuItem];
-    [NSApp setWindowsMenu:menu];
-
-    // Help menu
-    menu = [[NSMenu alloc] initWithTitle:@"Help"];
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
-    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
-    [menuItem setSubmenu:menu];
-    [[NSApp mainMenu] addItem:menuItem];
-
-    // Create an Application controller
-    QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
-    [NSApp setDelegate:appController];
-
-    // Start the main event loop
-    [NSApp run];
-
-    [appController release];
-    [pool release];
-
-    return 0;
-}
-
-
-
-#pragma mark qemu
-static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
-
-    NSRect rect;
-    if ([cocoaView cdx] == 1.0) {
-        rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
-    } else {
-        rect = NSMakeRect(
-            x * [cocoaView cdx],
-            ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
-            w * [cocoaView cdx],
-            h * [cocoaView cdy]);
-    }
-    [cocoaView setNeedsDisplayInRect:rect];
-}
-
-static void cocoa_resize(DisplayState *ds)
-{
-    COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
-
-    [cocoaView resizeContentToWidth:(int)(ds_get_width(ds)) height:(int)(ds_get_height(ds)) displayState:ds];
-}
-
-static void cocoa_refresh(DisplayState *ds)
-{
-    COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
-
-    if (kbd_mouse_is_absolute()) {
-        if (![cocoaView isAbsoluteEnabled]) {
-            if ([cocoaView isMouseGrabed]) {
-                [cocoaView ungrabMouse];
-            }
-        }
-        [cocoaView setAbsoluteEnabled:YES];
-    }
-
-    NSDate *distantPast;
-    NSEvent *event;
-    distantPast = [NSDate distantPast];
-    do {
-        event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
-                        inMode: NSDefaultRunLoopMode dequeue:YES];
-        if (event != nil) {
-            [cocoaView handleEvent:event];
-        }
-    } while(event != nil);
-    vga_hw_update();
-}
-
-static void cocoa_cleanup(void)
-{
-    COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
-       qemu_free(dcl);
-}
-
-void cocoa_display_init(DisplayState *ds, int full_screen)
-{
-    COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
-
-       dcl = qemu_mallocz(sizeof(DisplayChangeListener));
-       
-    // register vga output callbacks
-    dcl->dpy_update = cocoa_update;
-    dcl->dpy_resize = cocoa_resize;
-    dcl->dpy_refresh = cocoa_refresh;
-
-       register_displaychangelistener(ds, dcl);
-
-    // register cleanup function
-    atexit(cocoa_cleanup);
-}
index 27791b530e4ff97c80fcf0d693b7bc45f0d0fae7..33e98a499367753985b05ebd660529d59399ff7c 100755 (executable)
--- a/configure
+++ b/configure
@@ -2864,7 +2864,7 @@ done # for target in $targets
 if test "$source_path_used" = "yes" ; then
     DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
     DIRS="$DIRS roms/seabios roms/vgabios"
-    DIRS="$DIRS fsdev"
+    DIRS="$DIRS fsdev ui"
     FILES="Makefile tests/Makefile"
     FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
     FILES="$FILES tests/test-mmap.c"
diff --git a/curses.c b/curses.c
deleted file mode 100644 (file)
index ed3165e..0000000
--- a/curses.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * QEMU curses/ncurses display driver
- * 
- * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <curses.h>
-
-#ifndef _WIN32
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#endif
-
-#ifdef __OpenBSD__
-#define resize_term resizeterm
-#endif
-
-#include "qemu-common.h"
-#include "console.h"
-#include "sysemu.h"
-
-#define FONT_HEIGHT 16
-#define FONT_WIDTH 8
-
-static console_ch_t screen[160 * 100];
-static WINDOW *screenpad = NULL;
-static int width, height, gwidth, gheight, invalidate;
-static int px, py, sminx, sminy, smaxx, smaxy;
-
-static void curses_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    chtype *line;
-
-    line = ((chtype *) screen) + y * width;
-    for (h += y; y < h; y ++, line += width)
-        mvwaddchnstr(screenpad, y, 0, line, width);
-
-    pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
-    refresh();
-}
-
-static void curses_calc_pad(void)
-{
-    if (is_fixedsize_console()) {
-        width = gwidth;
-        height = gheight;
-    } else {
-        width = COLS;
-        height = LINES;
-    }
-
-    if (screenpad)
-        delwin(screenpad);
-
-    clear();
-    refresh();
-
-    screenpad = newpad(height, width);
-
-    if (width > COLS) {
-        px = (width - COLS) / 2;
-        sminx = 0;
-        smaxx = COLS;
-    } else {
-        px = 0;
-        sminx = (COLS - width) / 2;
-        smaxx = sminx + width;
-    }
-
-    if (height > LINES) {
-        py = (height - LINES) / 2;
-        sminy = 0;
-        smaxy = LINES;
-    } else {
-        py = 0;
-        sminy = (LINES - height) / 2;
-        smaxy = sminy + height;
-    }
-}
-
-static void curses_resize(DisplayState *ds)
-{
-    if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
-        return;
-
-    gwidth = ds_get_width(ds);
-    gheight = ds_get_height(ds);
-
-    curses_calc_pad();
-    ds->surface->width = width * FONT_WIDTH;
-    ds->surface->height = height * FONT_HEIGHT;
-}
-
-#ifndef _WIN32
-#if defined(SIGWINCH) && defined(KEY_RESIZE)
-static void curses_winch_handler(int signum)
-{
-    struct winsize {
-        unsigned short ws_row;
-        unsigned short ws_col;
-        unsigned short ws_xpixel;   /* unused */
-        unsigned short ws_ypixel;   /* unused */
-    } ws;
-
-    /* terminal size changed */
-    if (ioctl(1, TIOCGWINSZ, &ws) == -1)
-        return;
-
-    resize_term(ws.ws_row, ws.ws_col);
-    curses_calc_pad();
-    invalidate = 1;
-
-    /* some systems require this */
-    signal(SIGWINCH, curses_winch_handler);
-}
-#endif
-#endif
-
-static void curses_cursor_position(DisplayState *ds, int x, int y)
-{
-    if (x >= 0) {
-        x = sminx + x - px;
-        y = sminy + y - py;
-
-        if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
-            move(y, x);
-            curs_set(1);
-            /* it seems that curs_set(1) must always be called before
-             * curs_set(2) for the latter to have effect */
-            if (!is_graphic_console())
-                curs_set(2);
-            return;
-        }
-    }
-
-    curs_set(0);
-}
-
-/* generic keyboard conversion */
-
-#include "curses_keys.h"
-
-static kbd_layout_t *kbd_layout = NULL;
-
-static void curses_refresh(DisplayState *ds)
-{
-    int chr, nextchr, keysym, keycode, keycode_alt;
-
-    if (invalidate) {
-        clear();
-        refresh();
-        curses_calc_pad();
-        ds->surface->width = FONT_WIDTH * width;
-        ds->surface->height = FONT_HEIGHT * height;
-        vga_hw_invalidate();
-        invalidate = 0;
-    }
-
-    vga_hw_text_update(screen);
-
-    nextchr = ERR;
-    while (1) {
-        /* while there are any pending key strokes to process */
-        if (nextchr == ERR)
-            chr = getch();
-        else {
-            chr = nextchr;
-            nextchr = ERR;
-        }
-
-        if (chr == ERR)
-            break;
-
-#ifdef KEY_RESIZE
-        /* this shouldn't occur when we use a custom SIGWINCH handler */
-        if (chr == KEY_RESIZE) {
-            clear();
-            refresh();
-            curses_calc_pad();
-            curses_update(ds, 0, 0, width, height);
-            ds->surface->width = FONT_WIDTH * width;
-            ds->surface->height = FONT_HEIGHT * height;
-            continue;
-        }
-#endif
-
-        keycode = curses2keycode[chr];
-        keycode_alt = 0;
-
-        /* alt key */
-        if (keycode == 1) {
-            nextchr = getch();
-
-            if (nextchr != ERR) {
-                chr = nextchr;
-                keycode_alt = ALT;
-                keycode = curses2keycode[nextchr];
-                nextchr = ERR;
-
-                if (keycode != -1) {
-                    keycode |= ALT;
-
-                    /* process keys reserved for qemu */
-                    if (keycode >= QEMU_KEY_CONSOLE0 &&
-                            keycode < QEMU_KEY_CONSOLE0 + 9) {
-                        erase();
-                        wnoutrefresh(stdscr);
-                        console_select(keycode - QEMU_KEY_CONSOLE0);
-
-                        invalidate = 1;
-                        continue;
-                    }
-                }
-            }
-        }
-
-        if (kbd_layout) {
-            keysym = -1;
-            if (chr < CURSES_KEYS)
-                keysym = curses2keysym[chr];
-
-            if (keysym == -1) {
-                if (chr < ' ')
-                    keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
-                else
-                    keysym = chr;
-            }
-
-            keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
-            if (keycode == 0)
-                continue;
-
-            keycode |= (keysym & ~KEYSYM_MASK) >> 16;
-            keycode |= keycode_alt;
-        }
-
-        if (keycode == -1)
-            continue;
-
-        if (is_graphic_console()) {
-            /* since terminals don't know about key press and release
-             * events, we need to emit both for each key received */
-            if (keycode & SHIFT)
-                kbd_put_keycode(SHIFT_CODE);
-            if (keycode & CNTRL)
-                kbd_put_keycode(CNTRL_CODE);
-            if (keycode & ALT)
-                kbd_put_keycode(ALT_CODE);
-            if (keycode & ALTGR) {
-                kbd_put_keycode(SCANCODE_EMUL0);
-                kbd_put_keycode(ALT_CODE);
-            }
-            if (keycode & GREY)
-                kbd_put_keycode(GREY_CODE);
-            kbd_put_keycode(keycode & KEY_MASK);
-            if (keycode & GREY)
-                kbd_put_keycode(GREY_CODE);
-            kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
-            if (keycode & ALTGR) {
-                kbd_put_keycode(SCANCODE_EMUL0);
-                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
-            }
-            if (keycode & ALT)
-                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
-            if (keycode & CNTRL)
-                kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
-            if (keycode & SHIFT)
-                kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
-        } else {
-            keysym = curses2qemu[chr];
-            if (keysym == -1)
-                keysym = chr;
-
-            kbd_put_keysym(keysym);
-        }
-    }
-}
-
-static void curses_atexit(void)
-{
-    endwin();
-}
-
-static void curses_setup(void)
-{
-    int i, colour_default[8] = {
-        COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
-        COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
-    };
-
-    /* input as raw as possible, let everything be interpreted
-     * by the guest system */
-    initscr(); noecho(); intrflush(stdscr, FALSE);
-    nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
-    start_color(); raw(); scrollok(stdscr, FALSE);
-
-    for (i = 0; i < 64; i ++)
-        init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
-}
-
-static void curses_keyboard_setup(void)
-{
-#if defined(__APPLE__)
-    /* always use generic keymaps */
-    if (!keyboard_layout)
-        keyboard_layout = "en-us";
-#endif
-    if(keyboard_layout) {
-        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
-        if (!kbd_layout)
-            exit(1);
-    }
-}
-
-void curses_display_init(DisplayState *ds, int full_screen)
-{
-    DisplayChangeListener *dcl;
-#ifndef _WIN32
-    if (!isatty(1)) {
-        fprintf(stderr, "We need a terminal output\n");
-        exit(1);
-    }
-#endif
-
-    curses_setup();
-    curses_keyboard_setup();
-    atexit(curses_atexit);
-
-#ifndef _WIN32
-#if defined(SIGWINCH) && defined(KEY_RESIZE)
-    /* some curses implementations provide a handler, but we
-     * want to be sure this is handled regardless of the library */
-    signal(SIGWINCH, curses_winch_handler);
-#endif
-#endif
-
-    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
-    dcl->dpy_update = curses_update;
-    dcl->dpy_resize = curses_resize;
-    dcl->dpy_refresh = curses_refresh;
-    dcl->dpy_text_cursor = curses_cursor_position;
-    register_displaychangelistener(ds, dcl);
-    qemu_free_displaysurface(ds);
-    ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
-
-    invalidate = 1;
-}
diff --git a/curses_keys.h b/curses_keys.h
deleted file mode 100644 (file)
index 1decd11..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Keycode and keysyms conversion tables for curses
- * 
- * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <curses.h>
-#include "keymaps.h"
-
-
-#define KEY_RELEASE         0x80
-#define KEY_MASK            0x7f
-#define GREY_CODE           0xe0
-#define GREY                SCANCODE_GREY
-#define SHIFT_CODE          0x2a
-#define SHIFT               SCANCODE_SHIFT
-#define CNTRL_CODE          0x1d
-#define CNTRL               SCANCODE_CTRL
-#define ALT_CODE            0x38
-#define ALT                 SCANCODE_ALT
-#define ALTGR               SCANCODE_ALTGR
-
-#define KEYSYM_MASK         0x0ffffff
-#define KEYSYM_SHIFT        (SCANCODE_SHIFT << 16)
-#define KEYSYM_CNTRL        (SCANCODE_CTRL  << 16)
-#define KEYSYM_ALT          (SCANCODE_ALT   << 16)
-#define KEYSYM_ALTGR        (SCANCODE_ALTGR << 16)
-
-/* curses won't detect a Control + Alt + 1, so use Alt + 1 */
-#define QEMU_KEY_CONSOLE0   (2 | ALT)   /* (curses2keycode['1'] | ALT) */
-
-#define CURSES_KEYS         KEY_MAX     /* KEY_MAX defined in <curses.h> */
-
-static const int curses2keysym[CURSES_KEYS] = {
-    [0 ... (CURSES_KEYS - 1)] = -1,
-
-    [0x7f] = KEY_BACKSPACE,
-    ['\r'] = KEY_ENTER,
-    ['\n'] = KEY_ENTER,
-    [KEY_BTAB] = '\t' | KEYSYM_SHIFT,
-};
-
-static const int curses2keycode[CURSES_KEYS] = {
-    [0 ... (CURSES_KEYS - 1)] = -1,
-
-    [0x01b] = 1, /* Escape */
-    ['1'] = 2,
-    ['2'] = 3,
-    ['3'] = 4,
-    ['4'] = 5,
-    ['5'] = 6,
-    ['6'] = 7,
-    ['7'] = 8,
-    ['8'] = 9,
-    ['9'] = 10,
-    ['0'] = 11,
-    ['-'] = 12,
-    ['='] = 13,
-    [0x07f] = 14, /* Backspace */
-    [KEY_BACKSPACE] = 14, /* Backspace */
-
-    ['\t'] = 15, /* Tab */
-    ['q'] = 16,
-    ['w'] = 17,
-    ['e'] = 18,
-    ['r'] = 19,
-    ['t'] = 20,
-    ['y'] = 21,
-    ['u'] = 22,
-    ['i'] = 23,
-    ['o'] = 24,
-    ['p'] = 25,
-    ['['] = 26,
-    [']'] = 27,
-    ['\n'] = 28, /* Return */
-    ['\r'] = 28, /* Return */
-    [KEY_ENTER] = 28, /* Return */
-
-    ['a'] = 30,
-    ['s'] = 31,
-    ['d'] = 32,
-    ['f'] = 33,
-    ['g'] = 34,
-    ['h'] = 35,
-    ['j'] = 36,
-    ['k'] = 37,
-    ['l'] = 38,
-    [';'] = 39,
-    ['\''] = 40, /* Single quote */
-    ['`'] = 41,
-    ['\\'] = 43, /* Backslash */
-
-    ['z'] = 44,
-    ['x'] = 45,
-    ['c'] = 46,
-    ['v'] = 47,
-    ['b'] = 48,
-    ['n'] = 49,
-    ['m'] = 50,
-    [','] = 51,
-    ['.'] = 52,
-    ['/'] = 53,
-
-    [' '] = 57,
-
-    [KEY_F(1)] = 59, /* Function Key 1 */
-    [KEY_F(2)] = 60, /* Function Key 2 */
-    [KEY_F(3)] = 61, /* Function Key 3 */
-    [KEY_F(4)] = 62, /* Function Key 4 */
-    [KEY_F(5)] = 63, /* Function Key 5 */
-    [KEY_F(6)] = 64, /* Function Key 6 */
-    [KEY_F(7)] = 65, /* Function Key 7 */
-    [KEY_F(8)] = 66, /* Function Key 8 */
-    [KEY_F(9)] = 67, /* Function Key 9 */
-    [KEY_F(10)] = 68, /* Function Key 10 */
-    [KEY_F(11)] = 87, /* Function Key 11 */
-    [KEY_F(12)] = 88, /* Function Key 12 */
-
-    [KEY_HOME] = 71 | GREY, /* Home */
-    [KEY_UP] = 72 | GREY, /* Up Arrow */
-    [KEY_PPAGE] = 73 | GREY, /* Page Up */
-    [KEY_LEFT] = 75 | GREY, /* Left Arrow */
-    [KEY_RIGHT] = 77 | GREY, /* Right Arrow */
-    [KEY_END] = 79 | GREY, /* End */
-    [KEY_DOWN] = 80 | GREY, /* Down Arrow */
-    [KEY_NPAGE] = 81 | GREY, /* Page Down */
-    [KEY_IC] = 82 | GREY, /* Insert */
-    [KEY_DC] = 83 | GREY, /* Delete */
-
-    ['!'] = 2 | SHIFT,
-    ['@'] = 3 | SHIFT,
-    ['#'] = 4 | SHIFT,
-    ['$'] = 5 | SHIFT,
-    ['%'] = 6 | SHIFT,
-    ['^'] = 7 | SHIFT,
-    ['&'] = 8 | SHIFT,
-    ['*'] = 9 | SHIFT,
-    ['('] = 10 | SHIFT,
-    [')'] = 11 | SHIFT,
-    ['_'] = 12 | SHIFT,
-    ['+'] = 13 | SHIFT,
-
-    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
-    ['Q'] = 16 | SHIFT,
-    ['W'] = 17 | SHIFT,
-    ['E'] = 18 | SHIFT,
-    ['R'] = 19 | SHIFT,
-    ['T'] = 20 | SHIFT,
-    ['Y'] = 21 | SHIFT,
-    ['U'] = 22 | SHIFT,
-    ['I'] = 23 | SHIFT,
-    ['O'] = 24 | SHIFT,
-    ['P'] = 25 | SHIFT,
-    ['{'] = 26 | SHIFT,
-    ['}'] = 27 | SHIFT,
-
-    ['A'] = 30 | SHIFT,
-    ['S'] = 31 | SHIFT,
-    ['D'] = 32 | SHIFT,
-    ['F'] = 33 | SHIFT,
-    ['G'] = 34 | SHIFT,
-    ['H'] = 35 | SHIFT,
-    ['J'] = 36 | SHIFT,
-    ['K'] = 37 | SHIFT,
-    ['L'] = 38 | SHIFT,
-    [':'] = 39 | SHIFT,
-    ['"'] = 40 | SHIFT,
-    ['~'] = 41 | SHIFT,
-    ['|'] = 43 | SHIFT,
-
-    ['Z'] = 44 | SHIFT,
-    ['X'] = 45 | SHIFT,
-    ['C'] = 46 | SHIFT,
-    ['V'] = 47 | SHIFT,
-    ['B'] = 48 | SHIFT,
-    ['N'] = 49 | SHIFT,
-    ['M'] = 50 | SHIFT,
-    ['<'] = 51 | SHIFT,
-    ['>'] = 52 | SHIFT,
-    ['?'] = 53 | SHIFT,
-
-    [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
-    [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
-    [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
-    [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
-    [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
-    [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
-    [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
-    [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
-    [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
-    [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
-    [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
-    [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
-
-    ['Q' - '@'] = 16 | CNTRL, /* Control + q */
-    ['W' - '@'] = 17 | CNTRL, /* Control + w */
-    ['E' - '@'] = 18 | CNTRL, /* Control + e */
-    ['R' - '@'] = 19 | CNTRL, /* Control + r */
-    ['T' - '@'] = 20 | CNTRL, /* Control + t */
-    ['Y' - '@'] = 21 | CNTRL, /* Control + y */
-    ['U' - '@'] = 22 | CNTRL, /* Control + u */
-    /* Control + i collides with Tab */
-    ['O' - '@'] = 24 | CNTRL, /* Control + o */
-    ['P' - '@'] = 25 | CNTRL, /* Control + p */
-
-    ['A' - '@'] = 30 | CNTRL, /* Control + a */
-    ['S' - '@'] = 31 | CNTRL, /* Control + s */
-    ['D' - '@'] = 32 | CNTRL, /* Control + d */
-    ['F' - '@'] = 33 | CNTRL, /* Control + f */
-    ['G' - '@'] = 34 | CNTRL, /* Control + g */
-    ['H' - '@'] = 35 | CNTRL, /* Control + h */
-    /* Control + j collides with Return */
-    ['K' - '@'] = 37 | CNTRL, /* Control + k */
-    ['L' - '@'] = 38 | CNTRL, /* Control + l */
-
-    ['Z' - '@'] = 44 | CNTRL, /* Control + z */
-    ['X' - '@'] = 45 | CNTRL, /* Control + x */
-    ['C' - '@'] = 46 | CNTRL, /* Control + c */
-    ['V' - '@'] = 47 | CNTRL, /* Control + v */
-    ['B' - '@'] = 48 | CNTRL, /* Control + b */
-    ['N' - '@'] = 49 | CNTRL, /* Control + n */
-    /* Control + m collides with the keycode for Enter */
-
-};
-
-static const int curses2qemu[CURSES_KEYS] = {
-    [0 ... (CURSES_KEYS - 1)] = -1,
-
-    ['\n'] = '\n',
-    ['\r'] = '\n',
-
-    [0x07f] = QEMU_KEY_BACKSPACE,
-
-    [KEY_DOWN] = QEMU_KEY_DOWN,
-    [KEY_UP] = QEMU_KEY_UP,
-    [KEY_LEFT] = QEMU_KEY_LEFT,
-    [KEY_RIGHT] = QEMU_KEY_RIGHT,
-    [KEY_HOME] = QEMU_KEY_HOME,
-    [KEY_BACKSPACE] = QEMU_KEY_BACKSPACE,
-
-    [KEY_DC] = QEMU_KEY_DELETE,
-    [KEY_NPAGE] = QEMU_KEY_PAGEDOWN,
-    [KEY_PPAGE] = QEMU_KEY_PAGEUP,
-    [KEY_ENTER] = '\n',
-    [KEY_END] = QEMU_KEY_END,
-
-};
-
-static const name2keysym_t name2keysym[] = {
-    /* Plain ASCII */
-    { "space", 0x020 },
-    { "exclam", 0x021 },
-    { "quotedbl", 0x022 },
-    { "numbersign", 0x023 },
-    { "dollar", 0x024 },
-    { "percent", 0x025 },
-    { "ampersand", 0x026 },
-    { "apostrophe", 0x027 },
-    { "parenleft", 0x028 },
-    { "parenright", 0x029 },
-    { "asterisk", 0x02a },
-    { "plus", 0x02b },
-    { "comma", 0x02c },
-    { "minus", 0x02d },
-    { "period", 0x02e },
-    { "slash", 0x02f },
-    { "0", 0x030 },
-    { "1", 0x031 },
-    { "2", 0x032 },
-    { "3", 0x033 },
-    { "4", 0x034 },
-    { "5", 0x035 },
-    { "6", 0x036 },
-    { "7", 0x037 },
-    { "8", 0x038 },
-    { "9", 0x039 },
-    { "colon", 0x03a },
-    { "semicolon", 0x03b },
-    { "less", 0x03c },
-    { "equal", 0x03d },
-    { "greater", 0x03e },
-    { "question", 0x03f },
-    { "at", 0x040 },
-    { "A", 0x041 },
-    { "B", 0x042 },
-    { "C", 0x043 },
-    { "D", 0x044 },
-    { "E", 0x045 },
-    { "F", 0x046 },
-    { "G", 0x047 },
-    { "H", 0x048 },
-    { "I", 0x049 },
-    { "J", 0x04a },
-    { "K", 0x04b },
-    { "L", 0x04c },
-    { "M", 0x04d },
-    { "N", 0x04e },
-    { "O", 0x04f },
-    { "P", 0x050 },
-    { "Q", 0x051 },
-    { "R", 0x052 },
-    { "S", 0x053 },
-    { "T", 0x054 },
-    { "U", 0x055 },
-    { "V", 0x056 },
-    { "W", 0x057 },
-    { "X", 0x058 },
-    { "Y", 0x059 },
-    { "Z", 0x05a },
-    { "bracketleft", 0x05b },
-    { "backslash", 0x05c },
-    { "bracketright", 0x05d },
-    { "asciicircum", 0x05e },
-    { "underscore", 0x05f },
-    { "grave", 0x060 },
-    { "a", 0x061 },
-    { "b", 0x062 },
-    { "c", 0x063 },
-    { "d", 0x064 },
-    { "e", 0x065 },
-    { "f", 0x066 },
-    { "g", 0x067 },
-    { "h", 0x068 },
-    { "i", 0x069 },
-    { "j", 0x06a },
-    { "k", 0x06b },
-    { "l", 0x06c },
-    { "m", 0x06d },
-    { "n", 0x06e },
-    { "o", 0x06f },
-    { "p", 0x070 },
-    { "q", 0x071 },
-    { "r", 0x072 },
-    { "s", 0x073 },
-    { "t", 0x074 },
-    { "u", 0x075 },
-    { "v", 0x076 },
-    { "w", 0x077 },
-    { "x", 0x078 },
-    { "y", 0x079 },
-    { "z", 0x07a },
-    { "braceleft", 0x07b },
-    { "bar", 0x07c },
-    { "braceright", 0x07d },
-    { "asciitilde", 0x07e },
-
-    /* Latin-1 extensions */
-    { "nobreakspace", 0x0a0 },
-    { "exclamdown", 0x0a1 },
-    { "cent", 0x0a2 },
-    { "sterling", 0x0a3 },
-    { "currency", 0x0a4 },
-    { "yen", 0x0a5 },
-    { "brokenbar", 0x0a6 },
-    { "section", 0x0a7 },
-    { "diaeresis", 0x0a8 },
-    { "copyright", 0x0a9 },
-    { "ordfeminine", 0x0aa },
-    { "guillemotleft", 0x0ab },
-    { "notsign", 0x0ac },
-    { "hyphen", 0x0ad },
-    { "registered", 0x0ae },
-    { "macron", 0x0af },
-    { "degree", 0x0b0 },
-    { "plusminus", 0x0b1 },
-    { "twosuperior", 0x0b2 },
-    { "threesuperior", 0x0b3 },
-    { "acute", 0x0b4 },
-    { "mu", 0x0b5 },
-    { "paragraph", 0x0b6 },
-    { "periodcentered", 0x0b7 },
-    { "cedilla", 0x0b8 },
-    { "onesuperior", 0x0b9 },
-    { "masculine", 0x0ba },
-    { "guillemotright", 0x0bb },
-    { "onequarter", 0x0bc },
-    { "onehalf", 0x0bd },
-    { "threequarters", 0x0be },
-    { "questiondown", 0x0bf },
-    { "Agrave", 0x0c0 },
-    { "Aacute", 0x0c1 },
-    { "Acircumflex", 0x0c2 },
-    { "Atilde", 0x0c3 },
-    { "Adiaeresis", 0x0c4 },
-    { "Aring", 0x0c5 },
-    { "AE", 0x0c6 },
-    { "Ccedilla", 0x0c7 },
-    { "Egrave", 0x0c8 },
-    { "Eacute", 0x0c9 },
-    { "Ecircumflex", 0x0ca },
-    { "Ediaeresis", 0x0cb },
-    { "Igrave", 0x0cc },
-    { "Iacute", 0x0cd },
-    { "Icircumflex", 0x0ce },
-    { "Idiaeresis", 0x0cf },
-    { "ETH", 0x0d0 },
-    { "Eth", 0x0d0 },
-    { "Ntilde", 0x0d1 },
-    { "Ograve", 0x0d2 },
-    { "Oacute", 0x0d3 },
-    { "Ocircumflex", 0x0d4 },
-    { "Otilde", 0x0d5 },
-    { "Odiaeresis", 0x0d6 },
-    { "multiply", 0x0d7 },
-    { "Ooblique", 0x0d8 },
-    { "Oslash", 0x0d8 },
-    { "Ugrave", 0x0d9 },
-    { "Uacute", 0x0da },
-    { "Ucircumflex", 0x0db },
-    { "Udiaeresis", 0x0dc },
-    { "Yacute", 0x0dd },
-    { "THORN", 0x0de },
-    { "Thorn", 0x0de },
-    { "ssharp", 0x0df },
-    { "agrave", 0x0e0 },
-    { "aacute", 0x0e1 },
-    { "acircumflex", 0x0e2 },
-    { "atilde", 0x0e3 },
-    { "adiaeresis", 0x0e4 },
-    { "aring", 0x0e5 },
-    { "ae", 0x0e6 },
-    { "ccedilla", 0x0e7 },
-    { "egrave", 0x0e8 },
-    { "eacute", 0x0e9 },
-    { "ecircumflex", 0x0ea },
-    { "ediaeresis", 0x0eb },
-    { "igrave", 0x0ec },
-    { "iacute", 0x0ed },
-    { "icircumflex", 0x0ee },
-    { "idiaeresis", 0x0ef },
-    { "eth", 0x0f0 },
-    { "ntilde", 0x0f1 },
-    { "ograve", 0x0f2 },
-    { "oacute", 0x0f3 },
-    { "ocircumflex", 0x0f4 },
-    { "otilde", 0x0f5 },
-    { "odiaeresis", 0x0f6 },
-    { "division", 0x0f7 },
-    { "oslash", 0x0f8 },
-    { "ooblique", 0x0f8 },
-    { "ugrave", 0x0f9 },
-    { "uacute", 0x0fa },
-    { "ucircumflex", 0x0fb },
-    { "udiaeresis", 0x0fc },
-    { "yacute", 0x0fd },
-    { "thorn", 0x0fe },
-    { "ydiaeresis", 0x0ff },
-
-    /* Special keys */
-    { "BackSpace", KEY_BACKSPACE },
-    { "Tab", '\t' },
-    { "Return", KEY_ENTER },
-    { "Right", KEY_RIGHT },
-    { "Left", KEY_LEFT },
-    { "Up", KEY_UP },
-    { "Down", KEY_DOWN },
-    { "Page_Down", KEY_NPAGE },
-    { "Page_Up", KEY_PPAGE },
-    { "Insert", KEY_IC },
-    { "Delete", KEY_DC },
-    { "Home", KEY_HOME },
-    { "End", KEY_END },
-    { "F1", KEY_F(1) },
-    { "F2", KEY_F(2) },
-    { "F3", KEY_F(3) },
-    { "F4", KEY_F(4) },
-    { "F5", KEY_F(5) },
-    { "F6", KEY_F(6) },
-    { "F7", KEY_F(7) },
-    { "F8", KEY_F(8) },
-    { "F9", KEY_F(9) },
-    { "F10", KEY_F(10) },
-    { "F11", KEY_F(11) },
-    { "F12", KEY_F(12) },
-    { "F13", KEY_F(13) },
-    { "F14", KEY_F(14) },
-    { "F15", KEY_F(15) },
-    { "F16", KEY_F(16) },
-    { "F17", KEY_F(17) },
-    { "F18", KEY_F(18) },
-    { "F19", KEY_F(19) },
-    { "F20", KEY_F(20) },
-    { "F21", KEY_F(21) },
-    { "F22", KEY_F(22) },
-    { "F23", KEY_F(23) },
-    { "F24", KEY_F(24) },
-    { "Escape", 27 },
-
-    { NULL, 0 },
-};
diff --git a/d3des.c b/d3des.c
deleted file mode 100644 (file)
index 60c840e..0000000
--- a/d3des.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * This is D3DES (V5.09) by Richard Outerbridge with the double and
- * triple-length support removed for use in VNC.  Also the bytebit[] array
- * has been reversed so that the most significant bit in each byte of the
- * key is ignored, not the least significant.
- *
- * These changes are:
- *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * 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.
- */
-
-/* D3DES (V5.09) -
- *
- * A portable, public domain, version of the Data Encryption Standard.
- *
- * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
- * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
- * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
- * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
- * for humouring me on.
- *
- * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
- * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
- */
-
-#include "d3des.h"
-
-static void scrunch(unsigned char *, unsigned long *);
-static void unscrun(unsigned long *, unsigned char *);
-static void desfunc(unsigned long *, unsigned long *);
-static void cookey(unsigned long *);
-
-static unsigned long KnL[32] = { 0L };
-
-static const unsigned short bytebit[8] = {
-       01, 02, 04, 010, 020, 040, 0100, 0200 };
-
-static const unsigned long bigbyte[24] = {
-       0x800000L,      0x400000L,      0x200000L,      0x100000L,
-       0x80000L,       0x40000L,       0x20000L,       0x10000L,
-       0x8000L,        0x4000L,        0x2000L,        0x1000L,
-       0x800L,         0x400L,         0x200L,         0x100L,
-       0x80L,          0x40L,          0x20L,          0x10L,
-       0x8L,           0x4L,           0x2L,           0x1L    };
-
-/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
-
-static const unsigned char pc1[56] = {
-       56, 48, 40, 32, 24, 16,  8,      0, 57, 49, 41, 33, 25, 17,
-        9,  1, 58, 50, 42, 34, 26,     18, 10,  2, 59, 51, 43, 35,
-       62, 54, 46, 38, 30, 22, 14,      6, 61, 53, 45, 37, 29, 21,
-       13,  5, 60, 52, 44, 36, 28,     20, 12,  4, 27, 19, 11,  3 };
-
-static const unsigned char totrot[16] = {
-       1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
-
-static const unsigned char pc2[48] = {
-       13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
-       22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
-       40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
-       43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
-
-/* Thanks to James Gillogly & Phil Karn! */
-void deskey(unsigned char *key, int edf)
-{
-       register int i, j, l, m, n;
-       unsigned char pc1m[56], pcr[56];
-       unsigned long kn[32];
-
-       for ( j = 0; j < 56; j++ ) {
-               l = pc1[j];
-               m = l & 07;
-               pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
-               }
-       for( i = 0; i < 16; i++ ) {
-               if( edf == DE1 ) m = (15 - i) << 1;
-               else m = i << 1;
-               n = m + 1;
-               kn[m] = kn[n] = 0L;
-               for( j = 0; j < 28; j++ ) {
-                       l = j + totrot[i];
-                       if( l < 28 ) pcr[j] = pc1m[l];
-                       else pcr[j] = pc1m[l - 28];
-                       }
-               for( j = 28; j < 56; j++ ) {
-                   l = j + totrot[i];
-                   if( l < 56 ) pcr[j] = pc1m[l];
-                   else pcr[j] = pc1m[l - 28];
-                   }
-               for( j = 0; j < 24; j++ ) {
-                       if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
-                       if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
-                       }
-               }
-       cookey(kn);
-       return;
-       }
-
-static void cookey(register unsigned long *raw1)
-{
-       register unsigned long *cook, *raw0;
-       unsigned long dough[32];
-       register int i;
-
-       cook = dough;
-       for( i = 0; i < 16; i++, raw1++ ) {
-               raw0 = raw1++;
-               *cook    = (*raw0 & 0x00fc0000L) << 6;
-               *cook   |= (*raw0 & 0x00000fc0L) << 10;
-               *cook   |= (*raw1 & 0x00fc0000L) >> 10;
-               *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
-               *cook    = (*raw0 & 0x0003f000L) << 12;
-               *cook   |= (*raw0 & 0x0000003fL) << 16;
-               *cook   |= (*raw1 & 0x0003f000L) >> 4;
-               *cook++ |= (*raw1 & 0x0000003fL);
-               }
-       usekey(dough);
-       return;
-       }
-
-void cpkey(register unsigned long *into)
-{
-       register unsigned long *from, *endp;
-
-       from = KnL, endp = &KnL[32];
-       while( from < endp ) *into++ = *from++;
-       return;
-       }
-
-void usekey(register unsigned long *from)
-{
-       register unsigned long *to, *endp;
-
-       to = KnL, endp = &KnL[32];
-       while( to < endp ) *to++ = *from++;
-       return;
-       }
-
-void des(unsigned char *inblock, unsigned char *outblock)
-{
-       unsigned long work[2];
-
-       scrunch(inblock, work);
-       desfunc(work, KnL);
-       unscrun(work, outblock);
-       return;
-       }
-
-static void scrunch(register unsigned char *outof, register unsigned long *into)
-{
-       *into    = (*outof++ & 0xffL) << 24;
-       *into   |= (*outof++ & 0xffL) << 16;
-       *into   |= (*outof++ & 0xffL) << 8;
-       *into++ |= (*outof++ & 0xffL);
-       *into    = (*outof++ & 0xffL) << 24;
-       *into   |= (*outof++ & 0xffL) << 16;
-       *into   |= (*outof++ & 0xffL) << 8;
-       *into   |= (*outof   & 0xffL);
-       return;
-       }
-
-static void unscrun(register unsigned long *outof, register unsigned char *into)
-{
-       *into++ = (unsigned char)((*outof >> 24) & 0xffL);
-       *into++ = (unsigned char)((*outof >> 16) & 0xffL);
-       *into++ = (unsigned char)((*outof >>  8) & 0xffL);
-       *into++ = (unsigned char)(*outof++       & 0xffL);
-       *into++ = (unsigned char)((*outof >> 24) & 0xffL);
-       *into++ = (unsigned char)((*outof >> 16) & 0xffL);
-       *into++ = (unsigned char)((*outof >>  8) & 0xffL);
-       *into   =  (unsigned char)(*outof        & 0xffL);
-       return;
-       }
-
-static const unsigned long SP1[64] = {
-       0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
-       0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
-       0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
-       0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
-       0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
-       0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
-       0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
-       0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
-       0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
-       0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
-       0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
-       0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
-       0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
-       0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
-       0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
-       0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
-
-static const unsigned long SP2[64] = {
-       0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
-       0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
-       0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
-       0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
-       0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
-       0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
-       0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
-       0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
-       0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
-       0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
-       0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
-       0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
-       0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
-       0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
-       0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
-       0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
-
-static const unsigned long SP3[64] = {
-       0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
-       0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
-       0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
-       0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
-       0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
-       0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
-       0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
-       0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
-       0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
-       0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
-       0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
-       0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
-       0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
-       0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
-       0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
-       0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
-
-static const unsigned long SP4[64] = {
-       0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
-       0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
-       0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
-       0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
-       0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
-       0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
-       0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
-       0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
-       0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
-       0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
-       0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
-       0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
-       0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
-       0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
-       0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
-       0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
-
-static const unsigned long SP5[64] = {
-       0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
-       0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
-       0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
-       0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
-       0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
-       0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
-       0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
-       0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
-       0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
-       0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
-       0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
-       0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
-       0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
-       0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
-       0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
-       0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
-
-static const unsigned long SP6[64] = {
-       0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
-       0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
-       0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
-       0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
-       0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
-       0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
-       0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
-       0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
-       0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
-       0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
-       0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
-       0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
-       0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
-       0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
-       0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
-       0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
-
-static const unsigned long SP7[64] = {
-       0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
-       0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
-       0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
-       0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
-       0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
-       0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
-       0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
-       0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
-       0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
-       0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
-       0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
-       0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
-       0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
-       0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
-       0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
-       0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
-
-static const unsigned long SP8[64] = {
-       0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
-       0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
-       0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
-       0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
-       0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
-       0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
-       0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
-       0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
-       0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
-       0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
-       0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
-       0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
-       0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
-       0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
-       0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
-       0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
-
-static void desfunc(register unsigned long *block, register unsigned long *keys)
-{
-       register unsigned long fval, work, right, leftt;
-       register int round;
-
-       leftt = block[0];
-       right = block[1];
-       work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
-       right ^= work;
-       leftt ^= (work << 4);
-       work = ((leftt >> 16) ^ right) & 0x0000ffffL;
-       right ^= work;
-       leftt ^= (work << 16);
-       work = ((right >> 2) ^ leftt) & 0x33333333L;
-       leftt ^= work;
-       right ^= (work << 2);
-       work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
-       leftt ^= work;
-       right ^= (work << 8);
-       right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
-       work = (leftt ^ right) & 0xaaaaaaaaL;
-       leftt ^= work;
-       right ^= work;
-       leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
-
-       for( round = 0; round < 8; round++ ) {
-               work  = (right << 28) | (right >> 4);
-               work ^= *keys++;
-               fval  = SP7[ work                & 0x3fL];
-               fval |= SP5[(work >>  8) & 0x3fL];
-               fval |= SP3[(work >> 16) & 0x3fL];
-               fval |= SP1[(work >> 24) & 0x3fL];
-               work  = right ^ *keys++;
-               fval |= SP8[ work                & 0x3fL];
-               fval |= SP6[(work >>  8) & 0x3fL];
-               fval |= SP4[(work >> 16) & 0x3fL];
-               fval |= SP2[(work >> 24) & 0x3fL];
-               leftt ^= fval;
-               work  = (leftt << 28) | (leftt >> 4);
-               work ^= *keys++;
-               fval  = SP7[ work                & 0x3fL];
-               fval |= SP5[(work >>  8) & 0x3fL];
-               fval |= SP3[(work >> 16) & 0x3fL];
-               fval |= SP1[(work >> 24) & 0x3fL];
-               work  = leftt ^ *keys++;
-               fval |= SP8[ work                & 0x3fL];
-               fval |= SP6[(work >>  8) & 0x3fL];
-               fval |= SP4[(work >> 16) & 0x3fL];
-               fval |= SP2[(work >> 24) & 0x3fL];
-               right ^= fval;
-               }
-
-       right = (right << 31) | (right >> 1);
-       work = (leftt ^ right) & 0xaaaaaaaaL;
-       leftt ^= work;
-       right ^= work;
-       leftt = (leftt << 31) | (leftt >> 1);
-       work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
-       right ^= work;
-       leftt ^= (work << 8);
-       work = ((leftt >> 2) ^ right) & 0x33333333L;
-       right ^= work;
-       leftt ^= (work << 2);
-       work = ((right >> 16) ^ leftt) & 0x0000ffffL;
-       leftt ^= work;
-       right ^= (work << 16);
-       work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
-       leftt ^= work;
-       right ^= (work << 4);
-       *block++ = right;
-       *block = leftt;
-       return;
-       }
-
-/* Validation sets:
- *
- * Single-length key, single-length plaintext -
- * Key   : 0123 4567 89ab cdef
- * Plain  : 0123 4567 89ab cde7
- * Cipher : c957 4425 6a5e d31d
- *
- * Double-length key, single-length plaintext -
- * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210
- * Plain  : 0123 4567 89ab cde7
- * Cipher : 7f1d 0a77 826b 8aff
- *
- * Double-length key, double-length plaintext -
- * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210
- * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
- * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
- *
- * Triple-length key, single-length plaintext -
- * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
- * Plain  : 0123 4567 89ab cde7
- * Cipher : de0b 7c06 ae5e 0ed5
- *
- * Triple-length key, double-length plaintext -
- * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
- * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
- * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
- *
- * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
- **********************************************************************/
diff --git a/d3des.h b/d3des.h
deleted file mode 100644 (file)
index ea3da44..0000000
--- a/d3des.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This is D3DES (V5.09) by Richard Outerbridge with the double and
- * triple-length support removed for use in VNC.
- *
- * These changes are:
- *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * 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.
- */
-
-/* d3des.h -
- *
- *     Headers and defines for d3des.c
- *     Graven Imagery, 1992.
- *
- * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
- *     (GEnie : OUTER; CIS : [71755,204])
- */
-
-#define EN0    0       /* MODE == encrypt */
-#define DE1    1       /* MODE == decrypt */
-
-extern void deskey(unsigned char *, int);
-/*                   hexkey[8]     MODE
- * Sets the internal key register according to the hexadecimal
- * key contained in the 8 bytes of hexkey, according to the DES,
- * for encryption or decryption according to MODE.
- */
-
-extern void usekey(unsigned long *);
-/*                 cookedkey[32]
- * Loads the internal key register with the data in cookedkey.
- */
-
-extern void cpkey(unsigned long *);
-/*                cookedkey[32]
- * Copies the contents of the internal key register into the storage
- * located at &cookedkey[0].
- */
-
-extern void des(unsigned char *, unsigned char *);
-/*                 from[8]           to[8]
- * Encrypts/Decrypts (according to the key currently loaded in the
- * internal key register) one block of eight bytes at address 'from'
- * into the block at address 'to'.  They can be the same.
- */
-
-/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
- ********************************************************************/
diff --git a/keymaps.c b/keymaps.c
deleted file mode 100644 (file)
index 78c7ea3..0000000
--- a/keymaps.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * QEMU keysym to keycode conversion using rdesktop keymaps
- *
- * Copyright (c) 2004 Johannes Schindelin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "keymaps.h"
-#include "sysemu.h"
-
-static int get_keysym(const name2keysym_t *table,
-                     const char *name)
-{
-    const name2keysym_t *p;
-    for(p = table; p->name != NULL; p++) {
-        if (!strcmp(p->name, name))
-            return p->keysym;
-    }
-    return 0;
-}
-
-
-static void add_to_key_range(struct key_range **krp, int code) {
-    struct key_range *kr;
-    for (kr = *krp; kr; kr = kr->next) {
-       if (code >= kr->start && code <= kr->end)
-           break;
-       if (code == kr->start - 1) {
-           kr->start--;
-           break;
-       }
-       if (code == kr->end + 1) {
-           kr->end++;
-           break;
-       }
-    }
-    if (kr == NULL) {
-       kr = qemu_mallocz(sizeof(*kr));
-        kr->start = kr->end = code;
-        kr->next = *krp;
-        *krp = kr;
-    }
-}
-
-static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) {
-    if (keysym < MAX_NORMAL_KEYCODE) {
-       //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
-       k->keysym2keycode[keysym] = keycode;
-    } else {
-       if (k->extra_count >= MAX_EXTRA_COUNT) {
-           fprintf(stderr,
-                   "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n",
-                   line, keysym);
-       } else {
-#if 0
-           fprintf(stderr, "Setting %d: %d,%d\n",
-                   k->extra_count, keysym, keycode);
-#endif
-           k->keysym2keycode_extra[k->extra_count].
-               keysym = keysym;
-           k->keysym2keycode_extra[k->extra_count].
-               keycode = keycode;
-           k->extra_count++;
-       }
-    }
-}
-
-static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
-                                          const char *language,
-                                          kbd_layout_t * k)
-{
-    FILE *f;
-    char * filename;
-    char line[1024];
-    int len;
-
-    filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
-
-    if (!k)
-       k = qemu_mallocz(sizeof(kbd_layout_t));
-    if (!(filename && (f = fopen(filename, "r")))) {
-       fprintf(stderr,
-               "Could not read keymap file: '%s'\n", language);
-       return NULL;
-    }
-    qemu_free(filename);
-    for(;;) {
-       if (fgets(line, 1024, f) == NULL)
-            break;
-        len = strlen(line);
-        if (len > 0 && line[len - 1] == '\n')
-            line[len - 1] = '\0';
-        if (line[0] == '#')
-           continue;
-       if (!strncmp(line, "map ", 4))
-           continue;
-       if (!strncmp(line, "include ", 8)) {
-           parse_keyboard_layout(table, line + 8, k);
-        } else {
-           char *end_of_keysym = line;
-           while (*end_of_keysym != 0 && *end_of_keysym != ' ')
-               end_of_keysym++;
-           if (*end_of_keysym) {
-               int keysym;
-               *end_of_keysym = 0;
-               keysym = get_keysym(table, line);
-               if (keysym == 0) {
-                    //             fprintf(stderr, "Warning: unknown keysym %s\n", line);
-               } else {
-                   const char *rest = end_of_keysym + 1;
-                   char *rest2;
-                   int keycode = strtol(rest, &rest2, 0);
-
-                   if (rest && strstr(rest, "numlock")) {
-                       add_to_key_range(&k->keypad_range, keycode);
-                       add_to_key_range(&k->numlock_range, keysym);
-                       //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode);
-                   }
-
-                   if (rest && strstr(rest, "shift"))
-                       keycode |= SCANCODE_SHIFT;
-                   if (rest && strstr(rest, "altgr"))
-                       keycode |= SCANCODE_ALTGR;
-                   if (rest && strstr(rest, "ctrl"))
-                       keycode |= SCANCODE_CTRL;
-
-                   add_keysym(line, keysym, keycode, k);
-
-                   if (rest && strstr(rest, "addupper")) {
-                       char *c;
-                       for (c = line; *c; c++)
-                           *c = toupper(*c);
-                       keysym = get_keysym(table, line);
-                       if (keysym)
-                           add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k);
-                   }
-               }
-           }
-       }
-    }
-    fclose(f);
-    return k;
-}
-
-
-void *init_keyboard_layout(const name2keysym_t *table, const char *language)
-{
-    return parse_keyboard_layout(table, language, NULL);
-}
-
-
-int keysym2scancode(void *kbd_layout, int keysym)
-{
-    kbd_layout_t *k = kbd_layout;
-    if (keysym < MAX_NORMAL_KEYCODE) {
-       if (k->keysym2keycode[keysym] == 0)
-           fprintf(stderr, "Warning: no scancode found for keysym %d\n",
-                   keysym);
-       return k->keysym2keycode[keysym];
-    } else {
-       int i;
-#ifdef XK_ISO_Left_Tab
-       if (keysym == XK_ISO_Left_Tab)
-           keysym = XK_Tab;
-#endif
-       for (i = 0; i < k->extra_count; i++)
-           if (k->keysym2keycode_extra[i].keysym == keysym)
-               return k->keysym2keycode_extra[i].keycode;
-    }
-    return 0;
-}
-
-int keycode_is_keypad(void *kbd_layout, int keycode)
-{
-    kbd_layout_t *k = kbd_layout;
-    struct key_range *kr;
-
-    for (kr = k->keypad_range; kr; kr = kr->next)
-        if (keycode >= kr->start && keycode <= kr->end)
-            return 1;
-    return 0;
-}
-
-int keysym_is_numlock(void *kbd_layout, int keysym)
-{
-    kbd_layout_t *k = kbd_layout;
-    struct key_range *kr;
-
-    for (kr = k->numlock_range; kr; kr = kr->next)
-        if (keysym >= kr->start && keysym <= kr->end)
-            return 1;
-    return 0;
-}
diff --git a/keymaps.h b/keymaps.h
deleted file mode 100644 (file)
index a7600d5..0000000
--- a/keymaps.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * QEMU keysym to keycode conversion using rdesktop keymaps
- *
- * Copyright (c) 2004 Johannes Schindelin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef __QEMU_KEYMAPS_H__
-#define __QEMU_KEYMAPS_H__
-
-#include "qemu-common.h"
-
-typedef struct {
-       const char* name;
-       int keysym;
-} name2keysym_t;
-
-struct key_range {
-    int start;
-    int end;
-    struct key_range *next;
-};
-
-#define MAX_NORMAL_KEYCODE 512
-#define MAX_EXTRA_COUNT 256
-typedef struct {
-    uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
-    struct {
-       int keysym;
-       uint16_t keycode;
-    } keysym2keycode_extra[MAX_EXTRA_COUNT];
-    int extra_count;
-    struct key_range *keypad_range;
-    struct key_range *numlock_range;
-} kbd_layout_t;
-
-/* scancode without modifiers */
-#define SCANCODE_KEYMASK 0xff
-/* scancode without grey or up bit */
-#define SCANCODE_KEYCODEMASK 0x7f
-
-/* "grey" keys will usually need a 0xe0 prefix */
-#define SCANCODE_GREY   0x80
-#define SCANCODE_EMUL0  0xE0
-/* "up" flag */
-#define SCANCODE_UP     0x80
-
-/* Additional modifiers to use if not catched another way. */
-#define SCANCODE_SHIFT  0x100
-#define SCANCODE_CTRL   0x200
-#define SCANCODE_ALT    0x400
-#define SCANCODE_ALTGR  0x800
-
-
-void *init_keyboard_layout(const name2keysym_t *table, const char *language);
-int keysym2scancode(void *kbd_layout, int keysym);
-int keycode_is_keypad(void *kbd_layout, int keycode);
-int keysym_is_numlock(void *kbd_layout, int keysym);
-
-#endif /* __QEMU_KEYMAPS_H__ */
diff --git a/sdl.c b/sdl.c
deleted file mode 100644 (file)
index 0072680..0000000
--- a/sdl.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * QEMU SDL display driver
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <SDL.h>
-#include <SDL_syswm.h>
-
-#ifndef _WIN32
-#include <signal.h>
-#endif
-
-#include "qemu-common.h"
-#include "console.h"
-#include "sysemu.h"
-#include "x_keymap.h"
-#include "sdl_zoom.h"
-
-static DisplayChangeListener *dcl;
-static SDL_Surface *real_screen;
-static SDL_Surface *guest_screen = NULL;
-static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
-static int last_vm_running;
-static int gui_saved_grab;
-static int gui_fullscreen;
-static int gui_noframe;
-static int gui_key_modifier_pressed;
-static int gui_keysym;
-static int gui_fullscreen_initial_grab;
-static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
-static uint8_t modifiers_state[256];
-static int width, height;
-static SDL_Cursor *sdl_cursor_normal;
-static SDL_Cursor *sdl_cursor_hidden;
-static int absolute_enabled = 0;
-static int guest_cursor = 0;
-static int guest_x, guest_y;
-static SDL_Cursor *guest_sprite = NULL;
-static uint8_t allocator;
-static SDL_PixelFormat host_format;
-static int scaling_active = 0;
-static Notifier mouse_mode_notifier;
-
-static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-    SDL_Rect rec;
-    rec.x = x;
-    rec.y = y;
-    rec.w = w;
-    rec.h = h;
-
-    if (guest_screen) {
-        if (!scaling_active) {
-            SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
-        } else {
-            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
-                fprintf(stderr, "Zoom blit failed\n");
-                exit(1);
-            }
-        }
-    } 
-    SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
-}
-
-static void sdl_setdata(DisplayState *ds)
-{
-    SDL_Rect rec;
-    rec.x = 0;
-    rec.y = 0;
-    rec.w = real_screen->w;
-    rec.h = real_screen->h;
-
-    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
-
-    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
-                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
-                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
-                                            ds->surface->pf.bmask, ds->surface->pf.amask);
-}
-
-static void do_sdl_resize(int new_width, int new_height, int bpp)
-{
-    int flags;
-
-    //    printf("resizing to %d %d\n", w, h);
-
-    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
-    if (gui_fullscreen)
-        flags |= SDL_FULLSCREEN;
-    if (gui_noframe)
-        flags |= SDL_NOFRAME;
-
-    width = new_width;
-    height = new_height;
-    real_screen = SDL_SetVideoMode(width, height, bpp, flags);
-    if (!real_screen) {
-       fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
-               height, bpp, SDL_GetError());
-        exit(1);
-    }
-}
-
-static void sdl_resize(DisplayState *ds)
-{
-    if  (!allocator) {
-        if (!scaling_active)
-            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
-        else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
-            do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
-        sdl_setdata(ds);
-    } else {
-        if (guest_screen != NULL) {
-            SDL_FreeSurface(guest_screen);
-            guest_screen = NULL;
-        }
-    }
-}
-
-static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
-{
-    PixelFormat qemu_pf;
-
-    memset(&qemu_pf, 0x00, sizeof(PixelFormat));
-
-    qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
-    qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
-    qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
-
-    qemu_pf.rmask = sdl_pf->Rmask;
-    qemu_pf.gmask = sdl_pf->Gmask;
-    qemu_pf.bmask = sdl_pf->Bmask;
-    qemu_pf.amask = sdl_pf->Amask;
-
-    qemu_pf.rshift = sdl_pf->Rshift;
-    qemu_pf.gshift = sdl_pf->Gshift;
-    qemu_pf.bshift = sdl_pf->Bshift;
-    qemu_pf.ashift = sdl_pf->Ashift;
-
-    qemu_pf.rbits = 8 - sdl_pf->Rloss;
-    qemu_pf.gbits = 8 - sdl_pf->Gloss;
-    qemu_pf.bbits = 8 - sdl_pf->Bloss;
-    qemu_pf.abits = 8 - sdl_pf->Aloss;
-
-    qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
-    qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
-    qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
-    qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
-
-    return qemu_pf;
-}
-
-static DisplaySurface* sdl_create_displaysurface(int width, int height)
-{
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-    if (surface == NULL) {
-        fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
-        exit(1);
-    }
-
-    surface->width = width;
-    surface->height = height;
-    
-    if (scaling_active) {
-        if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
-            surface->linesize = width * 4;
-            surface->pf = qemu_default_pixelformat(32);
-        } else {
-            surface->linesize = width * host_format.BytesPerPixel;
-            surface->pf = sdl_to_qemu_pixelformat(&host_format);
-        }
-#ifdef HOST_WORDS_BIGENDIAN
-        surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-        surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-        surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
-
-        return surface;
-    }
-
-    if (host_format.BitsPerPixel == 16)
-        do_sdl_resize(width, height, 16);
-    else
-        do_sdl_resize(width, height, 32);
-
-    surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
-    surface->linesize = real_screen->pitch;
-    surface->data = real_screen->pixels;
-
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_REALPIXELS_FLAG;
-#endif
-    allocator = 1;
-
-    return surface;
-}
-
-static void sdl_free_displaysurface(DisplaySurface *surface)
-{
-    allocator = 0;
-    if (surface == NULL)
-        return;
-
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        qemu_free(surface->data);
-    qemu_free(surface);
-}
-
-static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
-{
-    sdl_free_displaysurface(surface);
-    return sdl_create_displaysurface(width, height);
-}
-
-/* generic keyboard conversion */
-
-#include "sdl_keysym.h"
-
-static kbd_layout_t *kbd_layout = NULL;
-
-static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
-{
-    int keysym;
-    /* workaround for X11+SDL bug with AltGR */
-    keysym = ev->keysym.sym;
-    if (keysym == 0 && ev->keysym.scancode == 113)
-        keysym = SDLK_MODE;
-    /* For Japanese key '\' and '|' */
-    if (keysym == 92 && ev->keysym.scancode == 133) {
-        keysym = 0xa5;
-    }
-    return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
-}
-
-/* specific keyboard conversions from scan codes */
-
-#if defined(_WIN32)
-
-static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
-{
-    return ev->keysym.scancode;
-}
-
-#else
-
-#if defined(SDL_VIDEO_DRIVER_X11)
-#include <X11/XKBlib.h>
-
-static int check_for_evdev(void)
-{
-    SDL_SysWMinfo info;
-    XkbDescPtr desc = NULL;
-    int has_evdev = 0;
-    char *keycodes = NULL;
-
-    SDL_VERSION(&info.version);
-    if (!SDL_GetWMInfo(&info)) {
-        return 0;
-    }
-    desc = XkbGetKeyboard(info.info.x11.display,
-                          XkbGBN_AllComponentsMask,
-                          XkbUseCoreKbd);
-    if (desc && desc->names) {
-        keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
-        if (keycodes == NULL) {
-            fprintf(stderr, "could not lookup keycode name\n");
-        } else if (strstart(keycodes, "evdev", NULL)) {
-            has_evdev = 1;
-        } else if (!strstart(keycodes, "xfree86", NULL)) {
-            fprintf(stderr, "unknown keycodes `%s', please report to "
-                    "qemu-devel@nongnu.org\n", keycodes);
-        }
-    }
-
-    if (desc) {
-        XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
-    }
-    if (keycodes) {
-        XFree(keycodes);
-    }
-    return has_evdev;
-}
-#else
-static int check_for_evdev(void)
-{
-       return 0;
-}
-#endif
-
-static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
-{
-    int keycode;
-    static int has_evdev = -1;
-
-    if (has_evdev == -1)
-        has_evdev = check_for_evdev();
-
-    keycode = ev->keysym.scancode;
-
-    if (keycode < 9) {
-        keycode = 0;
-    } else if (keycode < 97) {
-        keycode -= 8; /* just an offset */
-    } else if (keycode < 158) {
-        /* use conversion table */
-        if (has_evdev)
-            keycode = translate_evdev_keycode(keycode - 97);
-        else
-            keycode = translate_xfree86_keycode(keycode - 97);
-    } else if (keycode == 208) { /* Hiragana_Katakana */
-        keycode = 0x70;
-    } else if (keycode == 211) { /* backslash */
-        keycode = 0x73;
-    } else {
-        keycode = 0;
-    }
-    return keycode;
-}
-
-#endif
-
-static void reset_keys(void)
-{
-    int i;
-    for(i = 0; i < 256; i++) {
-        if (modifiers_state[i]) {
-            if (i & SCANCODE_GREY)
-                kbd_put_keycode(SCANCODE_EMUL0);
-            kbd_put_keycode(i | SCANCODE_UP);
-            modifiers_state[i] = 0;
-        }
-    }
-}
-
-static void sdl_process_key(SDL_KeyboardEvent *ev)
-{
-    int keycode, v;
-
-    if (ev->keysym.sym == SDLK_PAUSE) {
-        /* specific case */
-        v = 0;
-        if (ev->type == SDL_KEYUP)
-            v |= SCANCODE_UP;
-        kbd_put_keycode(0xe1);
-        kbd_put_keycode(0x1d | v);
-        kbd_put_keycode(0x45 | v);
-        return;
-    }
-
-    if (kbd_layout) {
-        keycode = sdl_keyevent_to_keycode_generic(ev);
-    } else {
-        keycode = sdl_keyevent_to_keycode(ev);
-    }
-
-    switch(keycode) {
-    case 0x00:
-        /* sent when leaving window: reset the modifiers state */
-        reset_keys();
-        return;
-    case 0x2a:                          /* Left Shift */
-    case 0x36:                          /* Right Shift */
-    case 0x1d:                          /* Left CTRL */
-    case 0x9d:                          /* Right CTRL */
-    case 0x38:                          /* Left ALT */
-    case 0xb8:                         /* Right ALT */
-        if (ev->type == SDL_KEYUP)
-            modifiers_state[keycode] = 0;
-        else
-            modifiers_state[keycode] = 1;
-        break;
-    case 0x45: /* num lock */
-    case 0x3a: /* caps lock */
-        /* SDL does not send the key up event, so we generate it */
-        kbd_put_keycode(keycode);
-        kbd_put_keycode(keycode | SCANCODE_UP);
-        return;
-    }
-
-    /* now send the key code */
-    if (keycode & SCANCODE_GREY)
-        kbd_put_keycode(SCANCODE_EMUL0);
-    if (ev->type == SDL_KEYUP)
-        kbd_put_keycode(keycode | SCANCODE_UP);
-    else
-        kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
-}
-
-static void sdl_update_caption(void)
-{
-    char win_title[1024];
-    char icon_title[1024];
-    const char *status = "";
-
-    if (!vm_running)
-        status = " [Stopped]";
-    else if (gui_grab) {
-        if (alt_grab)
-            status = " - Press Ctrl-Alt-Shift to exit mouse grab";
-        else if (ctrl_grab)
-            status = " - Press Right-Ctrl to exit mouse grab";
-        else
-            status = " - Press Ctrl-Alt to exit mouse grab";
-    }
-
-    if (qemu_name) {
-        snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
-        snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
-    } else {
-        snprintf(win_title, sizeof(win_title), "QEMU%s", status);
-        snprintf(icon_title, sizeof(icon_title), "QEMU");
-    }
-
-    SDL_WM_SetCaption(win_title, icon_title);
-}
-
-static void sdl_hide_cursor(void)
-{
-    if (!cursor_hide)
-        return;
-
-    if (kbd_mouse_is_absolute()) {
-        SDL_ShowCursor(1);
-        SDL_SetCursor(sdl_cursor_hidden);
-    } else {
-        SDL_ShowCursor(0);
-    }
-}
-
-static void sdl_show_cursor(void)
-{
-    if (!cursor_hide)
-        return;
-
-    if (!kbd_mouse_is_absolute()) {
-        SDL_ShowCursor(1);
-        if (guest_cursor &&
-                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
-            SDL_SetCursor(guest_sprite);
-        else
-            SDL_SetCursor(sdl_cursor_normal);
-    }
-}
-
-static void sdl_grab_start(void)
-{
-    if (guest_cursor) {
-        SDL_SetCursor(guest_sprite);
-        if (!kbd_mouse_is_absolute() && !absolute_enabled)
-            SDL_WarpMouse(guest_x, guest_y);
-    } else
-        sdl_hide_cursor();
-
-    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
-        gui_grab = 1;
-        sdl_update_caption();
-    } else
-        sdl_show_cursor();
-}
-
-static void sdl_grab_end(void)
-{
-    SDL_WM_GrabInput(SDL_GRAB_OFF);
-    gui_grab = 0;
-    sdl_show_cursor();
-    sdl_update_caption();
-}
-
-static void sdl_mouse_mode_change(Notifier *notify)
-{
-    if (kbd_mouse_is_absolute()) {
-        if (!absolute_enabled) {
-            sdl_hide_cursor();
-            if (gui_grab) {
-                sdl_grab_end();
-            }
-            absolute_enabled = 1;
-        }
-    } else if (absolute_enabled) {
-       sdl_show_cursor();
-       absolute_enabled = 0;
-    }
-}
-
-static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
-{
-    int buttons;
-    buttons = 0;
-    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
-        buttons |= MOUSE_EVENT_LBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
-        buttons |= MOUSE_EVENT_RBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
-        buttons |= MOUSE_EVENT_MBUTTON;
-
-    if (kbd_mouse_is_absolute()) {
-       dx = x * 0x7FFF / (width - 1);
-       dy = y * 0x7FFF / (height - 1);
-    } else if (guest_cursor) {
-        x -= guest_x;
-        y -= guest_y;
-        guest_x += x;
-        guest_y += y;
-        dx = x;
-        dy = y;
-    }
-
-    kbd_mouse_event(dx, dy, dz, buttons);
-}
-
-static void toggle_full_screen(DisplayState *ds)
-{
-    gui_fullscreen = !gui_fullscreen;
-    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
-    if (gui_fullscreen) {
-        scaling_active = 0;
-        gui_saved_grab = gui_grab;
-        sdl_grab_start();
-    } else {
-        if (!gui_saved_grab)
-            sdl_grab_end();
-    }
-    vga_hw_invalidate();
-    vga_hw_update();
-}
-
-static void sdl_refresh(DisplayState *ds)
-{
-    SDL_Event ev1, *ev = &ev1;
-    int mod_state;
-    int buttonstate = SDL_GetMouseState(NULL, NULL);
-
-    if (last_vm_running != vm_running) {
-        last_vm_running = vm_running;
-        sdl_update_caption();
-    }
-
-    vga_hw_update();
-    SDL_EnableUNICODE(!is_graphic_console());
-
-    while (SDL_PollEvent(ev)) {
-        switch (ev->type) {
-        case SDL_VIDEOEXPOSE:
-            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
-            break;
-        case SDL_KEYDOWN:
-        case SDL_KEYUP:
-            if (ev->type == SDL_KEYDOWN) {
-                if (alt_grab) {
-                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
-                                (gui_grab_code | KMOD_LSHIFT);
-                } else if (ctrl_grab) {
-                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
-                } else {
-                    mod_state = (SDL_GetModState() & gui_grab_code) ==
-                                gui_grab_code;
-                }
-                gui_key_modifier_pressed = mod_state;
-                if (gui_key_modifier_pressed) {
-                    int keycode;
-                    keycode = sdl_keyevent_to_keycode(&ev->key);
-                    switch(keycode) {
-                    case 0x21: /* 'f' key on US keyboard */
-                        toggle_full_screen(ds);
-                        gui_keysym = 1;
-                        break;
-                    case 0x16: /* 'u' key on US keyboard */
-                        scaling_active = 0;
-                        sdl_resize(ds);
-                        vga_hw_invalidate();
-                        vga_hw_update();
-                        break;
-                    case 0x02 ... 0x0a: /* '1' to '9' keys */
-                        /* Reset the modifiers sent to the current console */
-                        reset_keys();
-                        console_select(keycode - 0x02);
-                        if (!is_graphic_console()) {
-                            /* display grab if going to a text console */
-                            if (gui_grab)
-                                sdl_grab_end();
-                        }
-                        gui_keysym = 1;
-                        break;
-                    default:
-                        break;
-                    }
-                } else if (!is_graphic_console()) {
-                    int keysym;
-                    keysym = 0;
-                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
-                        default: break;
-                        }
-                    } else {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
-                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
-                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
-                        default: break;
-                        }
-                    }
-                    if (keysym) {
-                        kbd_put_keysym(keysym);
-                    } else if (ev->key.keysym.unicode != 0) {
-                        kbd_put_keysym(ev->key.keysym.unicode);
-                    }
-                }
-            } else if (ev->type == SDL_KEYUP) {
-                if (!alt_grab) {
-                    mod_state = (ev->key.keysym.mod & gui_grab_code);
-                } else {
-                    mod_state = (ev->key.keysym.mod &
-                                 (gui_grab_code | KMOD_LSHIFT));
-                }
-                if (!mod_state) {
-                    if (gui_key_modifier_pressed) {
-                        gui_key_modifier_pressed = 0;
-                        if (gui_keysym == 0) {
-                            /* exit/enter grab if pressing Ctrl-Alt */
-                            if (!gui_grab) {
-                                /* if the application is not active,
-                                   do not try to enter grab state. It
-                                   prevents
-                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
-                                   from blocking all the application
-                                   (SDL bug). */
-                                if (SDL_GetAppState() & SDL_APPACTIVE)
-                                    sdl_grab_start();
-                            } else {
-                                sdl_grab_end();
-                            }
-                            /* SDL does not send back all the
-                               modifiers key, so we must correct it */
-                            reset_keys();
-                            break;
-                        }
-                        gui_keysym = 0;
-                    }
-                }
-            }
-            if (is_graphic_console() && !gui_keysym)
-                sdl_process_key(&ev->key);
-            break;
-        case SDL_QUIT:
-            if (!no_quit)
-                qemu_system_shutdown_request();
-            break;
-        case SDL_MOUSEMOTION:
-            if (gui_grab || kbd_mouse_is_absolute() ||
-                absolute_enabled) {
-                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
-                       ev->motion.x, ev->motion.y, ev->motion.state);
-            }
-            break;
-        case SDL_MOUSEBUTTONDOWN:
-        case SDL_MOUSEBUTTONUP:
-            {
-                SDL_MouseButtonEvent *bev = &ev->button;
-                if (!gui_grab && !kbd_mouse_is_absolute()) {
-                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
-                        (bev->button == SDL_BUTTON_LEFT)) {
-                        /* start grabbing all events */
-                        sdl_grab_start();
-                    }
-                } else {
-                    int dz;
-                    dz = 0;
-                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
-                        buttonstate |= SDL_BUTTON(bev->button);
-                    } else {
-                        buttonstate &= ~SDL_BUTTON(bev->button);
-                    }
-#ifdef SDL_BUTTON_WHEELUP
-                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = -1;
-                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = 1;
-                    }
-#endif
-                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
-                }
-            }
-            break;
-        case SDL_ACTIVEEVENT:
-            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
-                !ev->active.gain && !gui_fullscreen_initial_grab) {
-                sdl_grab_end();
-            }
-            if (ev->active.state & SDL_APPACTIVE) {
-                if (ev->active.gain) {
-                    /* Back to default interval */
-                    dcl->gui_timer_interval = 0;
-                    dcl->idle = 0;
-                } else {
-                    /* Sleeping interval */
-                    dcl->gui_timer_interval = 500;
-                    dcl->idle = 1;
-                }
-            }
-            break;
-       case SDL_VIDEORESIZE:
-        {
-           SDL_ResizeEvent *rev = &ev->resize;
-            int bpp = real_screen->format->BitsPerPixel;
-            if (bpp != 16 && bpp != 32)
-                bpp = 32;
-            do_sdl_resize(rev->w, rev->h, bpp);
-            scaling_active = 1;
-            if (!is_buffer_shared(ds->surface)) {
-                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
-                dpy_resize(ds);
-            }
-            vga_hw_invalidate();
-            vga_hw_update();
-            break;
-        }
-        default:
-            break;
-        }
-    }
-}
-
-static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
-{
-    SDL_Rect dst = { x, y, w, h };
-    SDL_FillRect(real_screen, &dst, c);
-}
-
-static void sdl_mouse_warp(int x, int y, int on)
-{
-    if (on) {
-        if (!guest_cursor)
-            sdl_show_cursor();
-        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
-            SDL_SetCursor(guest_sprite);
-            if (!kbd_mouse_is_absolute() && !absolute_enabled)
-                SDL_WarpMouse(x, y);
-        }
-    } else if (gui_grab)
-        sdl_hide_cursor();
-    guest_cursor = on;
-    guest_x = x, guest_y = y;
-}
-
-static void sdl_mouse_define(QEMUCursor *c)
-{
-    uint8_t *image, *mask;
-    int bpl;
-
-    if (guest_sprite)
-        SDL_FreeCursor(guest_sprite);
-
-    bpl = cursor_get_mono_bpl(c);
-    image = qemu_mallocz(bpl * c->height);
-    mask  = qemu_mallocz(bpl * c->height);
-    cursor_get_mono_image(c, 0x000000, image);
-    cursor_get_mono_mask(c, 0, mask);
-    guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
-                                    c->hot_x, c->hot_y);
-    qemu_free(image);
-    qemu_free(mask);
-
-    if (guest_cursor &&
-            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
-        SDL_SetCursor(guest_sprite);
-}
-
-static void sdl_cleanup(void)
-{
-    if (guest_sprite)
-        SDL_FreeCursor(guest_sprite);
-    SDL_QuitSubSystem(SDL_INIT_VIDEO);
-}
-
-void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
-{
-    int flags;
-    uint8_t data = 0;
-    DisplayAllocator *da;
-    const SDL_VideoInfo *vi;
-
-#if defined(__APPLE__)
-    /* always use generic keymaps */
-    if (!keyboard_layout)
-        keyboard_layout = "en-us";
-#endif
-    if(keyboard_layout) {
-        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
-        if (!kbd_layout)
-            exit(1);
-    }
-
-    if (no_frame)
-        gui_noframe = 1;
-
-    if (!full_screen) {
-        setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
-    }
-
-    flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
-    if (SDL_Init (flags)) {
-        fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
-                SDL_GetError());
-        exit(1);
-    }
-    vi = SDL_GetVideoInfo();
-    host_format = *(vi->vfmt);
-
-    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
-    dcl->dpy_update = sdl_update;
-    dcl->dpy_resize = sdl_resize;
-    dcl->dpy_refresh = sdl_refresh;
-    dcl->dpy_setdata = sdl_setdata;
-    dcl->dpy_fill = sdl_fill;
-    ds->mouse_set = sdl_mouse_warp;
-    ds->cursor_define = sdl_mouse_define;
-    register_displaychangelistener(ds, dcl);
-
-    da = qemu_mallocz(sizeof(DisplayAllocator));
-    da->create_displaysurface = sdl_create_displaysurface;
-    da->resize_displaysurface = sdl_resize_displaysurface;
-    da->free_displaysurface = sdl_free_displaysurface;
-    if (register_displayallocator(ds, da) == da) {
-        dpy_resize(ds);
-    }
-
-    mouse_mode_notifier.notify = sdl_mouse_mode_change;
-    qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
-
-    sdl_update_caption();
-    SDL_EnableKeyRepeat(250, 50);
-    gui_grab = 0;
-
-    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
-    sdl_cursor_normal = SDL_GetCursor();
-
-    atexit(sdl_cleanup);
-    if (full_screen) {
-        gui_fullscreen = 1;
-        gui_fullscreen_initial_grab = 1;
-        sdl_grab_start();
-    }
-}
diff --git a/sdl_keysym.h b/sdl_keysym.h
deleted file mode 100644 (file)
index ee90480..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-
-#include "keymaps.h"
-
-static const name2keysym_t name2keysym[]={
-/* ascii */
-    { "space",                0x020},
-    { "exclam",               0x021},
-    { "quotedbl",             0x022},
-    { "numbersign",           0x023},
-    { "dollar",               0x024},
-    { "percent",              0x025},
-    { "ampersand",            0x026},
-    { "apostrophe",           0x027},
-    { "parenleft",            0x028},
-    { "parenright",           0x029},
-    { "asterisk",             0x02a},
-    { "plus",                 0x02b},
-    { "comma",                0x02c},
-    { "minus",                0x02d},
-    { "period",               0x02e},
-    { "slash",                0x02f},
-    { "0",                    0x030},
-    { "1",                    0x031},
-    { "2",                    0x032},
-    { "3",                    0x033},
-    { "4",                    0x034},
-    { "5",                    0x035},
-    { "6",                    0x036},
-    { "7",                    0x037},
-    { "8",                    0x038},
-    { "9",                    0x039},
-    { "colon",                0x03a},
-    { "semicolon",            0x03b},
-    { "less",                 0x03c},
-    { "equal",                0x03d},
-    { "greater",              0x03e},
-    { "question",             0x03f},
-    { "at",                   0x040},
-    { "A",                    0x041},
-    { "B",                    0x042},
-    { "C",                    0x043},
-    { "D",                    0x044},
-    { "E",                    0x045},
-    { "F",                    0x046},
-    { "G",                    0x047},
-    { "H",                    0x048},
-    { "I",                    0x049},
-    { "J",                    0x04a},
-    { "K",                    0x04b},
-    { "L",                    0x04c},
-    { "M",                    0x04d},
-    { "N",                    0x04e},
-    { "O",                    0x04f},
-    { "P",                    0x050},
-    { "Q",                    0x051},
-    { "R",                    0x052},
-    { "S",                    0x053},
-    { "T",                    0x054},
-    { "U",                    0x055},
-    { "V",                    0x056},
-    { "W",                    0x057},
-    { "X",                    0x058},
-    { "Y",                    0x059},
-    { "Z",                    0x05a},
-    { "bracketleft",          0x05b},
-    { "backslash",            0x05c},
-    { "bracketright",         0x05d},
-    { "asciicircum",          0x05e},
-    { "underscore",           0x05f},
-    { "grave",                0x060},
-    { "a",                    0x061},
-    { "b",                    0x062},
-    { "c",                    0x063},
-    { "d",                    0x064},
-    { "e",                    0x065},
-    { "f",                    0x066},
-    { "g",                    0x067},
-    { "h",                    0x068},
-    { "i",                    0x069},
-    { "j",                    0x06a},
-    { "k",                    0x06b},
-    { "l",                    0x06c},
-    { "m",                    0x06d},
-    { "n",                    0x06e},
-    { "o",                    0x06f},
-    { "p",                    0x070},
-    { "q",                    0x071},
-    { "r",                    0x072},
-    { "s",                    0x073},
-    { "t",                    0x074},
-    { "u",                    0x075},
-    { "v",                    0x076},
-    { "w",                    0x077},
-    { "x",                    0x078},
-    { "y",                    0x079},
-    { "z",                    0x07a},
-    { "braceleft",            0x07b},
-    { "bar",                  0x07c},
-    { "braceright",           0x07d},
-    { "asciitilde",           0x07e},
-
-/* latin 1 extensions */
-{ "nobreakspace",         0x0a0},
-{ "exclamdown",           0x0a1},
-{ "cent",                0x0a2},
-{ "sterling",             0x0a3},
-{ "currency",             0x0a4},
-{ "yen",                  0x0a5},
-{ "brokenbar",            0x0a6},
-{ "section",              0x0a7},
-{ "diaeresis",            0x0a8},
-{ "copyright",            0x0a9},
-{ "ordfeminine",          0x0aa},
-{ "guillemotleft",        0x0ab},
-{ "notsign",              0x0ac},
-{ "hyphen",               0x0ad},
-{ "registered",           0x0ae},
-{ "macron",               0x0af},
-{ "degree",               0x0b0},
-{ "plusminus",            0x0b1},
-{ "twosuperior",          0x0b2},
-{ "threesuperior",        0x0b3},
-{ "acute",                0x0b4},
-{ "mu",                   0x0b5},
-{ "paragraph",            0x0b6},
-{ "periodcentered",       0x0b7},
-{ "cedilla",              0x0b8},
-{ "onesuperior",          0x0b9},
-{ "masculine",            0x0ba},
-{ "guillemotright",       0x0bb},
-{ "onequarter",           0x0bc},
-{ "onehalf",              0x0bd},
-{ "threequarters",        0x0be},
-{ "questiondown",         0x0bf},
-{ "Agrave",               0x0c0},
-{ "Aacute",               0x0c1},
-{ "Acircumflex",          0x0c2},
-{ "Atilde",               0x0c3},
-{ "Adiaeresis",           0x0c4},
-{ "Aring",                0x0c5},
-{ "AE",                   0x0c6},
-{ "Ccedilla",             0x0c7},
-{ "Egrave",               0x0c8},
-{ "Eacute",               0x0c9},
-{ "Ecircumflex",          0x0ca},
-{ "Ediaeresis",           0x0cb},
-{ "Igrave",               0x0cc},
-{ "Iacute",               0x0cd},
-{ "Icircumflex",          0x0ce},
-{ "Idiaeresis",           0x0cf},
-{ "ETH",                  0x0d0},
-{ "Eth",                  0x0d0},
-{ "Ntilde",               0x0d1},
-{ "Ograve",               0x0d2},
-{ "Oacute",               0x0d3},
-{ "Ocircumflex",          0x0d4},
-{ "Otilde",               0x0d5},
-{ "Odiaeresis",           0x0d6},
-{ "multiply",             0x0d7},
-{ "Ooblique",             0x0d8},
-{ "Oslash",               0x0d8},
-{ "Ugrave",               0x0d9},
-{ "Uacute",               0x0da},
-{ "Ucircumflex",          0x0db},
-{ "Udiaeresis",           0x0dc},
-{ "Yacute",               0x0dd},
-{ "THORN",                0x0de},
-{ "Thorn",                0x0de},
-{ "ssharp",               0x0df},
-{ "agrave",               0x0e0},
-{ "aacute",               0x0e1},
-{ "acircumflex",          0x0e2},
-{ "atilde",               0x0e3},
-{ "adiaeresis",           0x0e4},
-{ "aring",                0x0e5},
-{ "ae",                   0x0e6},
-{ "ccedilla",             0x0e7},
-{ "egrave",               0x0e8},
-{ "eacute",               0x0e9},
-{ "ecircumflex",          0x0ea},
-{ "ediaeresis",           0x0eb},
-{ "igrave",               0x0ec},
-{ "iacute",               0x0ed},
-{ "icircumflex",          0x0ee},
-{ "idiaeresis",           0x0ef},
-{ "eth",                  0x0f0},
-{ "ntilde",               0x0f1},
-{ "ograve",               0x0f2},
-{ "oacute",               0x0f3},
-{ "ocircumflex",          0x0f4},
-{ "otilde",               0x0f5},
-{ "odiaeresis",           0x0f6},
-{ "division",             0x0f7},
-{ "oslash",               0x0f8},
-{ "ooblique",             0x0f8},
-{ "ugrave",               0x0f9},
-{ "uacute",               0x0fa},
-{ "ucircumflex",          0x0fb},
-{ "udiaeresis",           0x0fc},
-{ "yacute",               0x0fd},
-{ "thorn",                0x0fe},
-{ "ydiaeresis",           0x0ff},
-{"EuroSign", SDLK_EURO},
-
-    /* modifiers */
-{"Control_L", SDLK_LCTRL},
-{"Control_R", SDLK_RCTRL},
-{"Alt_L", SDLK_LALT},
-{"Alt_R", SDLK_RALT},
-{"Caps_Lock", SDLK_CAPSLOCK},
-{"Meta_L", SDLK_LMETA},
-{"Meta_R", SDLK_RMETA},
-{"Shift_L", SDLK_LSHIFT},
-{"Shift_R", SDLK_RSHIFT},
-{"Super_L", SDLK_LSUPER},
-{"Super_R", SDLK_RSUPER},
-
-    /* special keys */
-{"BackSpace", SDLK_BACKSPACE},
-{"Tab", SDLK_TAB},
-{"Return", SDLK_RETURN},
-{"Right", SDLK_RIGHT},
-{"Left", SDLK_LEFT},
-{"Up", SDLK_UP},
-{"Down", SDLK_DOWN},
-{"Page_Down", SDLK_PAGEDOWN},
-{"Page_Up", SDLK_PAGEUP},
-{"Insert", SDLK_INSERT},
-{"Delete", SDLK_DELETE},
-{"Home", SDLK_HOME},
-{"End", SDLK_END},
-{"Scroll_Lock", SDLK_SCROLLOCK},
-{"F1", SDLK_F1},
-{"F2", SDLK_F2},
-{"F3", SDLK_F3},
-{"F4", SDLK_F4},
-{"F5", SDLK_F5},
-{"F6", SDLK_F6},
-{"F7", SDLK_F7},
-{"F8", SDLK_F8},
-{"F9", SDLK_F9},
-{"F10", SDLK_F10},
-{"F11", SDLK_F11},
-{"F12", SDLK_F12},
-{"F13", SDLK_F13},
-{"F14", SDLK_F14},
-{"F15", SDLK_F15},
-{"Sys_Req", SDLK_SYSREQ},
-{"KP_0", SDLK_KP0},
-{"KP_1", SDLK_KP1},
-{"KP_2", SDLK_KP2},
-{"KP_3", SDLK_KP3},
-{"KP_4", SDLK_KP4},
-{"KP_5", SDLK_KP5},
-{"KP_6", SDLK_KP6},
-{"KP_7", SDLK_KP7},
-{"KP_8", SDLK_KP8},
-{"KP_9", SDLK_KP9},
-{"KP_Add", SDLK_KP_PLUS},
-{"KP_Decimal", SDLK_KP_PERIOD},
-{"KP_Divide", SDLK_KP_DIVIDE},
-{"KP_Enter", SDLK_KP_ENTER},
-{"KP_Equal", SDLK_KP_EQUALS},
-{"KP_Multiply", SDLK_KP_MULTIPLY},
-{"KP_Subtract", SDLK_KP_MINUS},
-{"help", SDLK_HELP},
-{"Menu", SDLK_MENU},
-{"Power", SDLK_POWER},
-{"Print", SDLK_PRINT},
-{"Mode_switch", SDLK_MODE},
-{"Multi_Key", SDLK_COMPOSE},
-{"Num_Lock", SDLK_NUMLOCK},
-{"Pause", SDLK_PAUSE},
-{"Escape", SDLK_ESCAPE},
-
-{NULL, 0},
-};
diff --git a/sdl_zoom.c b/sdl_zoom.c
deleted file mode 100644 (file)
index a986c7c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SDL_zoom - surface scaling
- * 
- * Copyright (c) 2009 Citrix Systems, Inc.
- *
- * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
- * Modifications by Stefano Stabellini.
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "sdl_zoom.h"
-#include "osdep.h"
-#include <stdint.h>
-#include <stdio.h>
-
-static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth,
-                          SDL_Rect *dst_rect);
-static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth,
-                          SDL_Rect *dst_rect);
-
-#define BPP 32
-#include  "sdl_zoom_template.h"
-#undef BPP
-#define BPP 16
-#include  "sdl_zoom_template.h"
-#undef BPP
-
-int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth,
-                  SDL_Rect *in_rect)
-{
-    SDL_Rect zoom, src_rect;
-    int extra;
-
-    /* Grow the size of the modified rectangle to avoid edge artefacts */
-    src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0;
-    src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0;
-
-    src_rect.w = in_rect->w + 1;
-    if (src_rect.x + src_rect.w > src_sfc->w)
-        src_rect.w = src_sfc->w - src_rect.x;
-
-    src_rect.h = in_rect->h + 1;
-    if (src_rect.y + src_rect.h > src_sfc->h)
-        src_rect.h = src_sfc->h - src_rect.y;
-
-    /* (x,y) : round down */
-    zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w));
-    zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h));
-
-    /* (w,h) : round up */
-    zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) /
-                     (double)(src_sfc->w));
-
-    zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) /
-                     (double)(src_sfc->h));
-
-    /* Account for any (x,y) rounding by adding one-source-pixel's worth
-     * of destination pixels and then edge checking.
-     */
-
-    extra = ((dst_sfc->w-1) / src_sfc->w) + 1;
-
-    if ((zoom.x + zoom.w) < (dst_sfc->w - extra))
-        zoom.w += extra;
-    else
-        zoom.w = dst_sfc->w - zoom.x;
-
-    extra = ((dst_sfc->h-1) / src_sfc->h) + 1;
-
-    if ((zoom.y + zoom.h) < (dst_sfc->h - extra))
-        zoom.h += extra;
-    else
-        zoom.h = dst_sfc->h - zoom.y;
-
-    /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the
-     * destination surface that needs to be updated.
-     */
-    if (src_sfc->format->BitsPerPixel == 32)
-        sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom);
-    else if (src_sfc->format->BitsPerPixel == 16)
-        sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom);
-    else {
-        fprintf(stderr, "pixel format not supported\n");
-        return -1;
-    }
-
-    /* Return the rectangle of the update to the caller */
-    *in_rect = zoom;
-
-    return 0;
-}
-
diff --git a/sdl_zoom.h b/sdl_zoom.h
deleted file mode 100644 (file)
index 74955bc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SDL_zoom - surface scaling
- * 
- * Copyright (c) 2009 Citrix Systems, Inc.
- *
- * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
- * Modifications by Stefano Stabellini.
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef SDL_zoom_h
-#define SDL_zoom_h
-
-#include <SDL.h>
-
-#define SMOOTHING_OFF          0
-#define SMOOTHING_ON           1
-
-int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc,
-                  int smooth, SDL_Rect *src_rect);
-
-#endif /* SDL_zoom_h */
diff --git a/sdl_zoom_template.h b/sdl_zoom_template.h
deleted file mode 100644 (file)
index 64bbca8..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * SDL_zoom_template - surface scaling
- * 
- * Copyright (c) 2009 Citrix Systems, Inc.
- *
- * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
- * Modifications by Stefano Stabellini.
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#if BPP == 16
-#define SDL_TYPE Uint16
-#elif BPP == 32
-#define SDL_TYPE Uint32
-#else
-#error unsupport depth
-#endif
-
-/*  
- *  Simple helper functions to make the code looks nicer
- *
- *  Assume spf = source SDL_PixelFormat
- *         dpf = dest SDL_PixelFormat
- *
- */
-#define getRed(color)   (((color) & spf->Rmask) >> spf->Rshift)
-#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift)
-#define getBlue(color)  (((color) & spf->Bmask) >> spf->Bshift)
-#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift)
-
-#define setRed(r, pcolor) do { \
-    *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \
-              (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \
-} while (0);
-
-#define setGreen(g, pcolor) do { \
-    *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \
-              (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \
-} while (0);
-
-#define setBlue(b, pcolor) do { \
-    *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \
-              (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \
-} while (0);
-
-#define setAlpha(a, pcolor) do { \
-    *pcolor = ((*pcolor) & (~(dpf->Amask))) + \
-              (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \
-} while (0);
-
-static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth,
-                                   SDL_Rect *dst_rect)
-{
-    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump;
-    SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp;
-    int d_gap;
-    SDL_PixelFormat *spf = src->format;
-    SDL_PixelFormat *dpf = dst->format;
-
-    if (smooth) { 
-        /* For interpolation: assume source dimension is one pixel.
-         * Smaller here to avoid overflow on right and bottom edge.
-         */
-        sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
-        sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
-    } else {
-        sx = (int) (65536.0 * (float) src->w / (float) dst->w);
-        sy = (int) (65536.0 * (float) src->h / (float) dst->h);
-    }
-
-    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
-        return (-1);
-    }
-    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
-        free(sax);
-        return (-1);
-    }
-
-    sp = csp = (SDL_TYPE *) src->pixels;
-    dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch +
-                       dst_rect->x * dst->format->BytesPerPixel);
-
-    csx = 0;
-    csax = sax;
-    for (x = 0; x <= dst->w; x++) {
-        *csax = csx;
-        csax++;
-        csx &= 0xffff;
-        csx += sx;
-    }
-    csy = 0;
-    csay = say;
-    for (y = 0; y <= dst->h; y++) {
-        *csay = csy;
-        csay++;
-        csy &= 0xffff;
-        csy += sy;
-    }
-
-    d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel;
-
-    if (smooth) {
-        csay = say;
-        for (y = 0; y < dst_rect->y; y++) {
-            csay++;
-            sstep = (*csay >> 16) * src->pitch;
-            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
-        }
-
-        /* Calculate sstep_jump */
-        csax = sax; 
-        sstep_jump = 0;
-        for (x = 0; x < dst_rect->x; x++) {
-            csax++; 
-            sstep = (*csax >> 16);
-            sstep_jump += sstep;
-        }
-
-        for (y = 0; y < dst_rect->h ; y++) {
-            /* Setup colour source pointers */
-            c00 = csp + sstep_jump;
-            c01 = c00 + 1;
-            c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump;
-            c11 = c10 + 1;
-            csax = sax + dst_rect->x; 
-
-            for (x = 0; x < dst_rect->w; x++) {
-
-                /* Interpolate colours */
-                ex = (*csax & 0xffff);
-                ey = (*csay & 0xffff);
-                t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) +
-                     getRed(*c00)) & (dpf->Rmask >> dpf->Rshift);
-                t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) +
-                     getRed(*c10)) & (dpf->Rmask >> dpf->Rshift);
-                setRed((((t2 - t1) * ey) >> 16) + t1, dp);
-                t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) +
-                     getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift);
-                t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) +
-                     getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift);
-                setGreen((((t2 - t1) * ey) >> 16) + t1, dp);
-                t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) +
-                     getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift);
-                t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) +
-                     getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift);
-                setBlue((((t2 - t1) * ey) >> 16) + t1, dp);
-                t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) +
-                     getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift);
-                t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) +
-                     getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift);
-                setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); 
-
-                /* Advance source pointers */
-                csax++; 
-                sstep = (*csax >> 16);
-                c00 += sstep;
-                c01 += sstep;
-                c10 += sstep;
-                c11 += sstep;
-                /* Advance destination pointer */
-                dp++;
-            }
-            /* Advance source pointer */
-            csay++;
-            csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
-            /* Advance destination pointers */
-            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
-        }
-
-
-    } else {
-        csay = say;
-
-        for (y = 0; y < dst_rect->y; y++) {
-            csay++;
-            sstep = (*csay >> 16) * src->pitch;
-            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
-        }
-
-        /* Calculate sstep_jump */
-        csax = sax; 
-        sstep_jump = 0;
-        for (x = 0; x < dst_rect->x; x++) {
-            csax++; 
-            sstep = (*csax >> 16);
-            sstep_jump += sstep;
-        }
-
-        for (y = 0 ; y < dst_rect->h ; y++) {
-            sp = csp + sstep_jump;
-            csax = sax + dst_rect->x;
-
-            for (x = 0; x < dst_rect->w; x++) {
-
-                /* Draw */
-                *dp = *sp;
-
-                /* Advance source pointers */
-                csax++;
-                sstep = (*csax >> 16);
-                sp += sstep;
-
-                /* Advance destination pointer */
-                dp++;
-            }
-            /* Advance source pointers */
-            csay++;
-            sstep = (*csay >> 16) * src->pitch;
-            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
-
-            /* Advance destination pointer */
-            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
-        }
-    }
-
-    free(sax);
-    free(say);
-    return (0);
-}
-
-#undef SDL_TYPE
-
diff --git a/ui/cocoa.m b/ui/cocoa.m
new file mode 100644 (file)
index 0000000..56c789a
--- /dev/null
@@ -0,0 +1,1014 @@
+/*
+ * QEMU Cocoa CG display driver
+ *
+ * Copyright (c) 2008 Mike Kronenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+#ifndef MAC_OS_X_VERSION_10_4
+#define MAC_OS_X_VERSION_10_4 1040
+#endif
+#ifndef MAC_OS_X_VERSION_10_5
+#define MAC_OS_X_VERSION_10_5 1050
+#endif
+
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define COCOA_DEBUG(...)  { (void) fprintf (stdout, __VA_ARGS__); }
+#else
+#define COCOA_DEBUG(...)  ((void) 0)
+#endif
+
+#define cgrect(nsrect) (*(CGRect *)&(nsrect))
+#define COCOA_MOUSE_EVENT \
+        if (isTabletEnabled) { \
+            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
+        } else if (isMouseGrabed) { \
+            kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
+        } else { \
+            [NSApp sendEvent:event]; \
+        }
+
+typedef struct {
+    int width;
+    int height;
+    int bitsPerComponent;
+    int bitsPerPixel;
+} QEMUScreen;
+
+int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
+NSWindow *normalWindow;
+id cocoaView;
+static DisplayChangeListener *dcl;
+
+int gArgc;
+char **gArgv;
+
+// keymap conversion
+int keymap[] =
+{
+//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
+    30, //  0       0x00    0x1e            A       QZ_a
+    31, //  1       0x01    0x1f            S       QZ_s
+    32, //  2       0x02    0x20            D       QZ_d
+    33, //  3       0x03    0x21            F       QZ_f
+    35, //  4       0x04    0x23            H       QZ_h
+    34, //  5       0x05    0x22            G       QZ_g
+    44, //  6       0x06    0x2c            Z       QZ_z
+    45, //  7       0x07    0x2d            X       QZ_x
+    46, //  8       0x08    0x2e            C       QZ_c
+    47, //  9       0x09    0x2f            V       QZ_v
+    0,  //  10      0x0A    Undefined
+    48, //  11      0x0B    0x30            B       QZ_b
+    16, //  12      0x0C    0x10            Q       QZ_q
+    17, //  13      0x0D    0x11            W       QZ_w
+    18, //  14      0x0E    0x12            E       QZ_e
+    19, //  15      0x0F    0x13            R       QZ_r
+    21, //  16      0x10    0x15            Y       QZ_y
+    20, //  17      0x11    0x14            T       QZ_t
+    2,  //  18      0x12    0x02            1       QZ_1
+    3,  //  19      0x13    0x03            2       QZ_2
+    4,  //  20      0x14    0x04            3       QZ_3
+    5,  //  21      0x15    0x05            4       QZ_4
+    7,  //  22      0x16    0x07            6       QZ_6
+    6,  //  23      0x17    0x06            5       QZ_5
+    13, //  24      0x18    0x0d            =       QZ_EQUALS
+    10, //  25      0x19    0x0a            9       QZ_9
+    8,  //  26      0x1A    0x08            7       QZ_7
+    12, //  27      0x1B    0x0c            -       QZ_MINUS
+    9,  //  28      0x1C    0x09            8       QZ_8
+    11, //  29      0x1D    0x0b            0       QZ_0
+    27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
+    24, //  31      0x1F    0x18            O       QZ_o
+    22, //  32      0x20    0x16            U       QZ_u
+    26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
+    23, //  34      0x22    0x17            I       QZ_i
+    25, //  35      0x23    0x19            P       QZ_p
+    28, //  36      0x24    0x1c            ENTER   QZ_RETURN
+    38, //  37      0x25    0x26            L       QZ_l
+    36, //  38      0x26    0x24            J       QZ_j
+    40, //  39      0x27    0x28            '       QZ_QUOTE
+    37, //  40      0x28    0x25            K       QZ_k
+    39, //  41      0x29    0x27            ;       QZ_SEMICOLON
+    43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
+    51, //  43      0x2B    0x33            ,       QZ_COMMA
+    53, //  44      0x2C    0x35            /       QZ_SLASH
+    49, //  45      0x2D    0x31            N       QZ_n
+    50, //  46      0x2E    0x32            M       QZ_m
+    52, //  47      0x2F    0x34            .       QZ_PERIOD
+    15, //  48      0x30    0x0f            TAB     QZ_TAB
+    57, //  49      0x31    0x39            SPACE   QZ_SPACE
+    41, //  50      0x32    0x29            `       QZ_BACKQUOTE
+    14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
+    0,  //  52      0x34    Undefined
+    1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
+    0,  //  54      0x36                            QZ_RMETA
+    0,  //  55      0x37                            QZ_LMETA
+    42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
+    58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
+    56, //  58      0x3A    0x38            L ALT   QZ_LALT
+    29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
+    54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
+    184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
+    157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
+    0,  //  63      0x3F    Undefined
+    0,  //  64      0x40    Undefined
+    0,  //  65      0x41    Undefined
+    0,  //  66      0x42    Undefined
+    55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
+    0,  //  68      0x44    Undefined
+    78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
+    0,  //  70      0x46    Undefined
+    69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
+    0,  //  72      0x48    Undefined
+    0,  //  73      0x49    Undefined
+    0,  //  74      0x4A    Undefined
+    181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
+    152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
+    0,  //  77      0x4D    undefined
+    74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
+    0,  //  79      0x4F    Undefined
+    0,  //  80      0x50    Undefined
+    0,  //  81      0x51                            QZ_KP_EQUALS
+    82, //  82      0x52    0x52            KP 0    QZ_KP0
+    79, //  83      0x53    0x4f            KP 1    QZ_KP1
+    80, //  84      0x54    0x50            KP 2    QZ_KP2
+    81, //  85      0x55    0x51            KP 3    QZ_KP3
+    75, //  86      0x56    0x4b            KP 4    QZ_KP4
+    76, //  87      0x57    0x4c            KP 5    QZ_KP5
+    77, //  88      0x58    0x4d            KP 6    QZ_KP6
+    71, //  89      0x59    0x47            KP 7    QZ_KP7
+    0,  //  90      0x5A    Undefined
+    72, //  91      0x5B    0x48            KP 8    QZ_KP8
+    73, //  92      0x5C    0x49            KP 9    QZ_KP9
+    0,  //  93      0x5D    Undefined
+    0,  //  94      0x5E    Undefined
+    0,  //  95      0x5F    Undefined
+    63, //  96      0x60    0x3f            F5      QZ_F5
+    64, //  97      0x61    0x40            F6      QZ_F6
+    65, //  98      0x62    0x41            F7      QZ_F7
+    61, //  99      0x63    0x3d            F3      QZ_F3
+    66, //  100     0x64    0x42            F8      QZ_F8
+    67, //  101     0x65    0x43            F9      QZ_F9
+    0,  //  102     0x66    Undefined
+    87, //  103     0x67    0x57            F11     QZ_F11
+    0,  //  104     0x68    Undefined
+    183,//  105     0x69    0xb7                    QZ_PRINT
+    0,  //  106     0x6A    Undefined
+    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
+    0,  //  108     0x6C    Undefined
+    68, //  109     0x6D    0x44            F10     QZ_F10
+    0,  //  110     0x6E    Undefined
+    88, //  111     0x6F    0x58            F12     QZ_F12
+    0,  //  112     0x70    Undefined
+    110,//  113     0x71    0x0                     QZ_PAUSE
+    210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
+    199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
+    201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
+    211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
+    62, //  118     0x76    0x3e            F4      QZ_F4
+    207,//  119     0x77    0xcf    E0,4f   END     QZ_END
+    60, //  120     0x78    0x3c            F2      QZ_F2
+    209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
+    59, //  122     0x7A    0x3b            F1      QZ_F1
+    203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
+    205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
+    208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
+    200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
+/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
+
+/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
+/*
+    219 //          0xdb            e0,5b   L GUI
+    220 //          0xdc            e0,5c   R GUI
+    221 //          0xdd            e0,5d   APPS
+        //              E0,2A,E0,37         PRNT SCRN
+        //              E1,1D,45,E1,9D,C5   PAUSE
+    83  //          0x53    0x53            KP .
+// ACPI Scan Codes
+    222 //          0xde            E0, 5E  Power
+    223 //          0xdf            E0, 5F  Sleep
+    227 //          0xe3            E0, 63  Wake
+// Windows Multimedia Scan Codes
+    153 //          0x99            E0, 19  Next Track
+    144 //          0x90            E0, 10  Previous Track
+    164 //          0xa4            E0, 24  Stop
+    162 //          0xa2            E0, 22  Play/Pause
+    160 //          0xa0            E0, 20  Mute
+    176 //          0xb0            E0, 30  Volume Up
+    174 //          0xae            E0, 2E  Volume Down
+    237 //          0xed            E0, 6D  Media Select
+    236 //          0xec            E0, 6C  E-Mail
+    161 //          0xa1            E0, 21  Calculator
+    235 //          0xeb            E0, 6B  My Computer
+    229 //          0xe5            E0, 65  WWW Search
+    178 //          0xb2            E0, 32  WWW Home
+    234 //          0xea            E0, 6A  WWW Back
+    233 //          0xe9            E0, 69  WWW Forward
+    232 //          0xe8            E0, 68  WWW Stop
+    231 //          0xe7            E0, 67  WWW Refresh
+    230 //          0xe6            E0, 66  WWW Favorites
+*/
+};
+
+static int cocoa_keycode_to_qemu(int keycode)
+{
+    if((sizeof(keymap)/sizeof(int)) <= keycode)
+    {
+        printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
+        return 0;
+    }
+    return keymap[keycode];
+}
+
+
+
+/*
+ ------------------------------------------------------
+    QemuCocoaView
+ ------------------------------------------------------
+*/
+@interface QemuCocoaView : NSView
+{
+    QEMUScreen screen;
+    NSWindow *fullScreenWindow;
+    float cx,cy,cw,ch,cdx,cdy;
+    CGDataProviderRef dataProviderRef;
+    int modifiers_state[256];
+    BOOL isMouseGrabed;
+    BOOL isFullscreen;
+    BOOL isAbsoluteEnabled;
+    BOOL isTabletEnabled;
+}
+- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
+- (void) grabMouse;
+- (void) ungrabMouse;
+- (void) toggleFullScreen:(id)sender;
+- (void) handleEvent:(NSEvent *)event;
+- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
+- (BOOL) isMouseGrabed;
+- (BOOL) isAbsoluteEnabled;
+- (float) cdx;
+- (float) cdy;
+- (QEMUScreen) gscreen;
+@end
+
+@implementation QemuCocoaView
+- (id)initWithFrame:(NSRect)frameRect
+{
+    COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
+
+    self = [super initWithFrame:frameRect];
+    if (self) {
+
+        screen.bitsPerComponent = 8;
+        screen.bitsPerPixel = 32;
+        screen.width = frameRect.size.width;
+        screen.height = frameRect.size.height;
+
+    }
+    return self;
+}
+
+- (void) dealloc
+{
+    COCOA_DEBUG("QemuCocoaView: dealloc\n");
+
+    if (dataProviderRef)
+        CGDataProviderRelease(dataProviderRef);
+
+    [super dealloc];
+}
+
+- (BOOL) isOpaque
+{
+    return YES;
+}
+
+- (void) drawRect:(NSRect) rect
+{
+    COCOA_DEBUG("QemuCocoaView: drawRect\n");
+
+    // get CoreGraphic context
+    CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
+    CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
+    CGContextSetShouldAntialias (viewContextRef, NO);
+
+    // draw screen bitmap directly to Core Graphics context
+    if (dataProviderRef) {
+        CGImageRef imageRef = CGImageCreate(
+            screen.width, //width
+            screen.height, //height
+            screen.bitsPerComponent, //bitsPerComponent
+            screen.bitsPerPixel, //bitsPerPixel
+            (screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
+#ifdef __LITTLE_ENDIAN__
+            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
+            kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
+#else
+            CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
+            kCGImageAlphaNoneSkipFirst, //bitmapInfo
+#endif
+            dataProviderRef, //provider
+            NULL, //decode
+            0, //interpolate
+            kCGRenderingIntentDefault //intent
+        );
+// test if host supports "CGImageCreateWithImageInRect" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+        if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
+#endif
+            // compatibility drawing code (draws everything) (OS X < 10.4)
+            CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+        } else {
+            // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
+            const NSRect *rectList;
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+            NSInteger rectCount;
+#else
+            int rectCount;
+#endif
+            int i;
+            CGImageRef clipImageRef;
+            CGRect clipRect;
+
+            [self getRectsBeingDrawn:&rectList count:&rectCount];
+            for (i = 0; i < rectCount; i++) {
+                clipRect.origin.x = rectList[i].origin.x / cdx;
+                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
+                clipRect.size.width = rectList[i].size.width / cdx;
+                clipRect.size.height = rectList[i].size.height / cdy;
+                clipImageRef = CGImageCreateWithImageInRect(
+                    imageRef,
+                    clipRect
+                );
+                CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
+                CGImageRelease (clipImageRef);
+            }
+        }
+#endif
+        CGImageRelease (imageRef);
+    }
+}
+
+- (void) setContentDimensions
+{
+    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
+
+    if (isFullscreen) {
+        cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
+        cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
+        cw = screen.width * cdx;
+        ch = screen.height * cdy;
+        cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
+        cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
+    } else {
+        cx = 0;
+        cy = 0;
+        cw = screen.width;
+        ch = screen.height;
+        cdx = 1.0;
+        cdy = 1.0;
+    }
+}
+
+- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
+{
+    COCOA_DEBUG("QemuCocoaView: resizeContent\n");
+
+    // update screenBuffer
+    if (dataProviderRef)
+        CGDataProviderRelease(dataProviderRef);
+
+    //sync host window color space with guests
+       screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
+       screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
+
+    dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
+
+    // update windows
+    if (isFullscreen) {
+        [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
+        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
+    } else {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
+        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
+    }
+    screen.width = w;
+    screen.height = h;
+       [normalWindow center];
+    [self setContentDimensions];
+    [self setFrame:NSMakeRect(cx, cy, cw, ch)];
+}
+
+- (void) toggleFullScreen:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
+
+    if (isFullscreen) { // switch from fullscreen to desktop
+        isFullscreen = FALSE;
+        [self ungrabMouse];
+        [self setContentDimensions];
+// test if host supports "exitFullScreenModeWithOptions" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
+            [self exitFullScreenModeWithOptions:nil];
+        } else {
+#endif
+            [fullScreenWindow close];
+            [normalWindow setContentView: self];
+            [normalWindow makeKeyAndOrderFront: self];
+            [NSMenu setMenuBarVisible:YES];
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        }
+#endif
+    } else { // switch from desktop to fullscreen
+        isFullscreen = TRUE;
+        [self grabMouse];
+        [self setContentDimensions];
+// test if host supports "enterFullScreenMode:withOptions" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
+            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
+                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
+                 nil]];
+        } else {
+#endif
+            [NSMenu setMenuBarVisible:NO];
+            fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
+                styleMask:NSBorderlessWindowMask
+                backing:NSBackingStoreBuffered
+                defer:NO];
+            [fullScreenWindow setHasShadow:NO];
+            [fullScreenWindow setContentView:self];
+            [fullScreenWindow makeKeyAndOrderFront:self];
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        }
+#endif
+    }
+}
+
+- (void) handleEvent:(NSEvent *)event
+{
+    COCOA_DEBUG("QemuCocoaView: handleEvent\n");
+
+    int buttons = 0;
+    int keycode;
+    NSPoint p = [event locationInWindow];
+
+    switch ([event type]) {
+        case NSFlagsChanged:
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            if (keycode) {
+                if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
+                    kbd_put_keycode(keycode);
+                    kbd_put_keycode(keycode | 0x80);
+                } else if (is_graphic_console()) {
+                    if (keycode & 0x80)
+                        kbd_put_keycode(0xe0);
+                    if (modifiers_state[keycode] == 0) { // keydown
+                        kbd_put_keycode(keycode & 0x7f);
+                        modifiers_state[keycode] = 1;
+                    } else { // keyup
+                        kbd_put_keycode(keycode | 0x80);
+                        modifiers_state[keycode] = 0;
+                    }
+                }
+            }
+
+            // release Mouse grab when pressing ctrl+alt
+            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+                [self ungrabMouse];
+            }
+            break;
+        case NSKeyDown:
+
+            // forward command Key Combos
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                [NSApp sendEvent:event];
+                return;
+            }
+
+            // default
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+
+            // handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
+            if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+                switch (keycode) {
+
+                    // enable graphic console
+                    case 0x02 ... 0x0a: // '1' to '9' keys
+                        console_select(keycode - 0x02);
+                        break;
+                }
+
+            // handle keys for graphic console
+            } else if (is_graphic_console()) {
+                if (keycode & 0x80) //check bit for e0 in front
+                    kbd_put_keycode(0xe0);
+                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
+
+            // handlekeys for Monitor
+            } else {
+                int keysym = 0;
+                switch([event keyCode]) {
+                case 115:
+                    keysym = QEMU_KEY_HOME;
+                    break;
+                case 117:
+                    keysym = QEMU_KEY_DELETE;
+                    break;
+                case 119:
+                    keysym = QEMU_KEY_END;
+                    break;
+                case 123:
+                    keysym = QEMU_KEY_LEFT;
+                    break;
+                case 124:
+                    keysym = QEMU_KEY_RIGHT;
+                    break;
+                case 125:
+                    keysym = QEMU_KEY_DOWN;
+                    break;
+                case 126:
+                    keysym = QEMU_KEY_UP;
+                    break;
+                default:
+                    {
+                        NSString *ks = [event characters];
+                        if ([ks length] > 0)
+                            keysym = [ks characterAtIndex:0];
+                    }
+                }
+                if (keysym)
+                    kbd_put_keysym(keysym);
+            }
+            break;
+        case NSKeyUp:
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            if (is_graphic_console()) {
+                if (keycode & 0x80)
+                    kbd_put_keycode(0xe0);
+                kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
+            }
+            break;
+        case NSMouseMoved:
+            if (isAbsoluteEnabled) {
+                if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
+                    if (isTabletEnabled) { // if we leave the window, deactivate the tablet
+                        [NSCursor unhide];
+                        isTabletEnabled = FALSE;
+                    }
+                } else {
+                    if (!isTabletEnabled) { // if we enter the window, activate the tablet
+                        [NSCursor hide];
+                        isTabletEnabled = TRUE;
+                    }
+                }
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseDown:
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                buttons |= MOUSE_EVENT_RBUTTON;
+            } else {
+                buttons |= MOUSE_EVENT_LBUTTON;
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSRightMouseDown:
+            buttons |= MOUSE_EVENT_RBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseDown:
+            buttons |= MOUSE_EVENT_MBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseDragged:
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                buttons |= MOUSE_EVENT_RBUTTON;
+            } else {
+                buttons |= MOUSE_EVENT_LBUTTON;
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSRightMouseDragged:
+            buttons |= MOUSE_EVENT_RBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseDragged:
+            buttons |= MOUSE_EVENT_MBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseUp:
+            if (isTabletEnabled) {
+                    COCOA_MOUSE_EVENT
+            } else if (!isMouseGrabed) {
+                if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
+                    [self grabMouse];
+                } else {
+                    [NSApp sendEvent:event];
+                }
+            } else {
+                COCOA_MOUSE_EVENT
+            }
+            break;
+        case NSRightMouseUp:
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseUp:
+            COCOA_MOUSE_EVENT
+            break;
+        case NSScrollWheel:
+            if (isTabletEnabled || isMouseGrabed) {
+                kbd_mouse_event(0, 0, -[event deltaY], 0);
+            } else {
+                [NSApp sendEvent:event];
+            }
+            break;
+        default:
+            [NSApp sendEvent:event];
+    }
+}
+
+- (void) grabMouse
+{
+    COCOA_DEBUG("QemuCocoaView: grabMouse\n");
+
+    if (!isFullscreen) {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
+        else
+            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
+    }
+    [NSCursor hide];
+    CGAssociateMouseAndMouseCursorPosition(FALSE);
+    isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
+}
+
+- (void) ungrabMouse
+{
+    COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
+
+    if (!isFullscreen) {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
+        else
+            [normalWindow setTitle:@"QEMU"];
+    }
+    [NSCursor unhide];
+    CGAssociateMouseAndMouseCursorPosition(TRUE);
+    isMouseGrabed = FALSE;
+}
+
+- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
+- (BOOL) isMouseGrabed {return isMouseGrabed;}
+- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
+- (float) cdx {return cdx;}
+- (float) cdy {return cdy;}
+- (QEMUScreen) gscreen {return screen;}
+@end
+
+
+
+/*
+ ------------------------------------------------------
+    QemuCocoaAppController
+ ------------------------------------------------------
+*/
+@interface QemuCocoaAppController : NSObject
+{
+}
+- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
+- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+- (void)toggleFullScreen:(id)sender;
+- (void)showQEMUDoc:(id)sender;
+- (void)showQEMUTec:(id)sender;
+@end
+
+@implementation QemuCocoaAppController
+- (id) init
+{
+    COCOA_DEBUG("QemuCocoaAppController: init\n");
+
+    self = [super init];
+    if (self) {
+
+        // create a view and add it to the window
+        cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
+        if(!cocoaView) {
+            fprintf(stderr, "(cocoa) can't create a view\n");
+            exit(1);
+        }
+
+        // create a window
+        normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
+            styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
+            backing:NSBackingStoreBuffered defer:NO];
+        if(!normalWindow) {
+            fprintf(stderr, "(cocoa) can't create window\n");
+            exit(1);
+        }
+        [normalWindow setAcceptsMouseMovedEvents:YES];
+        [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
+        [normalWindow setContentView:cocoaView];
+        [normalWindow useOptimizedDrawing:YES];
+        [normalWindow makeKeyAndOrderFront:self];
+               [normalWindow center];
+
+    }
+    return self;
+}
+
+- (void) dealloc
+{
+    COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
+
+    if (cocoaView)
+        [cocoaView release];
+    [super dealloc];
+}
+
+- (void)applicationDidFinishLaunching: (NSNotification *) note
+{
+    COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
+
+    // Display an open dialog box if no argument were passed or
+    // if qemu was launched from the finder ( the Finder passes "-psn" )
+    if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
+        NSOpenPanel *op = [[NSOpenPanel alloc] init];
+        [op setPrompt:@"Boot image"];
+        [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
+        [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
+              modalForWindow:normalWindow modalDelegate:self
+              didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
+    } else {
+        // or Launch Qemu, with the global args
+        [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
+    }
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification
+{
+    COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
+
+    qemu_system_shutdown_request();
+    exit(0);
+}
+
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
+{
+    return YES;
+}
+
+- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
+{
+    COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
+
+    int status;
+    status = qemu_main(argc, argv);
+    exit(status);
+}
+
+- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+    COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
+
+    if(returnCode == NSCancelButton) {
+        exit(0);
+    } else if(returnCode == NSOKButton) {
+        const char *bin = "qemu";
+        char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
+
+        char **argv = (char**)malloc( sizeof(char*)*3 );
+
+        asprintf(&argv[0], "%s", bin);
+        asprintf(&argv[1], "-hda");
+        asprintf(&argv[2], "%s", img);
+
+        printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
+
+        [self startEmulationWithArgc:3 argv:(char**)argv];
+    }
+}
+- (void)toggleFullScreen:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
+
+    [cocoaView toggleFullScreen:sender];
+}
+
+- (void)showQEMUDoc:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
+
+    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
+        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+}
+
+- (void)showQEMUTec:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
+
+    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
+        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+}
+@end
+
+
+
+// Dock Connection
+typedef struct CPSProcessSerNum
+{
+        UInt32                lo;
+        UInt32                hi;
+} CPSProcessSerNum;
+
+extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
+extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+int main (int argc, const char * argv[]) {
+
+    gArgc = argc;
+    gArgv = (char **)argv;
+    CPSProcessSerNum PSN;
+    int i;
+
+    /* In case we don't need to display a window, let's not do that */
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-vnc") ||
+            !strcmp(argv[i], "-nographic") ||
+            !strcmp(argv[i], "-curses")) {
+                return qemu_main(gArgc, gArgv);
+        }
+    }
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    [NSApplication sharedApplication];
+
+    if (!CPSGetCurrentProcess(&PSN))
+        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+            if (!CPSSetFrontProcess(&PSN))
+                [NSApplication sharedApplication];
+
+    // Add menus
+    NSMenu      *menu;
+    NSMenuItem  *menuItem;
+
+    [NSApp setMainMenu:[[NSMenu alloc] init]];
+
+    // Application menu
+    menu = [[NSMenu alloc] initWithTitle:@""];
+    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
+    [menu addItem:[NSMenuItem separatorItem]]; //Separator
+    [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
+    menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
+    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+    [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
+    [menu addItem:[NSMenuItem separatorItem]]; //Separator
+    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+    [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
+
+    // View menu
+    menu = [[NSMenu alloc] initWithTitle:@"View"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+
+    // Window menu
+    menu = [[NSMenu alloc] initWithTitle:@"Window"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+    [NSApp setWindowsMenu:menu];
+
+    // Help menu
+    menu = [[NSMenu alloc] initWithTitle:@"Help"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+
+    // Create an Application controller
+    QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
+    [NSApp setDelegate:appController];
+
+    // Start the main event loop
+    [NSApp run];
+
+    [appController release];
+    [pool release];
+
+    return 0;
+}
+
+
+
+#pragma mark qemu
+static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
+
+    NSRect rect;
+    if ([cocoaView cdx] == 1.0) {
+        rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
+    } else {
+        rect = NSMakeRect(
+            x * [cocoaView cdx],
+            ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
+            w * [cocoaView cdx],
+            h * [cocoaView cdy]);
+    }
+    [cocoaView setNeedsDisplayInRect:rect];
+}
+
+static void cocoa_resize(DisplayState *ds)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
+
+    [cocoaView resizeContentToWidth:(int)(ds_get_width(ds)) height:(int)(ds_get_height(ds)) displayState:ds];
+}
+
+static void cocoa_refresh(DisplayState *ds)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
+
+    if (kbd_mouse_is_absolute()) {
+        if (![cocoaView isAbsoluteEnabled]) {
+            if ([cocoaView isMouseGrabed]) {
+                [cocoaView ungrabMouse];
+            }
+        }
+        [cocoaView setAbsoluteEnabled:YES];
+    }
+
+    NSDate *distantPast;
+    NSEvent *event;
+    distantPast = [NSDate distantPast];
+    do {
+        event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
+                        inMode: NSDefaultRunLoopMode dequeue:YES];
+        if (event != nil) {
+            [cocoaView handleEvent:event];
+        }
+    } while(event != nil);
+    vga_hw_update();
+}
+
+static void cocoa_cleanup(void)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
+       qemu_free(dcl);
+}
+
+void cocoa_display_init(DisplayState *ds, int full_screen)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
+
+       dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+       
+    // register vga output callbacks
+    dcl->dpy_update = cocoa_update;
+    dcl->dpy_resize = cocoa_resize;
+    dcl->dpy_refresh = cocoa_refresh;
+
+       register_displaychangelistener(ds, dcl);
+
+    // register cleanup function
+    atexit(cocoa_cleanup);
+}
diff --git a/ui/curses.c b/ui/curses.c
new file mode 100644 (file)
index 0000000..ed3165e
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * QEMU curses/ncurses display driver
+ * 
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <curses.h>
+
+#ifndef _WIN32
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#endif
+
+#ifdef __OpenBSD__
+#define resize_term resizeterm
+#endif
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+static console_ch_t screen[160 * 100];
+static WINDOW *screenpad = NULL;
+static int width, height, gwidth, gheight, invalidate;
+static int px, py, sminx, sminy, smaxx, smaxy;
+
+static void curses_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    chtype *line;
+
+    line = ((chtype *) screen) + y * width;
+    for (h += y; y < h; y ++, line += width)
+        mvwaddchnstr(screenpad, y, 0, line, width);
+
+    pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
+    refresh();
+}
+
+static void curses_calc_pad(void)
+{
+    if (is_fixedsize_console()) {
+        width = gwidth;
+        height = gheight;
+    } else {
+        width = COLS;
+        height = LINES;
+    }
+
+    if (screenpad)
+        delwin(screenpad);
+
+    clear();
+    refresh();
+
+    screenpad = newpad(height, width);
+
+    if (width > COLS) {
+        px = (width - COLS) / 2;
+        sminx = 0;
+        smaxx = COLS;
+    } else {
+        px = 0;
+        sminx = (COLS - width) / 2;
+        smaxx = sminx + width;
+    }
+
+    if (height > LINES) {
+        py = (height - LINES) / 2;
+        sminy = 0;
+        smaxy = LINES;
+    } else {
+        py = 0;
+        sminy = (LINES - height) / 2;
+        smaxy = sminy + height;
+    }
+}
+
+static void curses_resize(DisplayState *ds)
+{
+    if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
+        return;
+
+    gwidth = ds_get_width(ds);
+    gheight = ds_get_height(ds);
+
+    curses_calc_pad();
+    ds->surface->width = width * FONT_WIDTH;
+    ds->surface->height = height * FONT_HEIGHT;
+}
+
+#ifndef _WIN32
+#if defined(SIGWINCH) && defined(KEY_RESIZE)
+static void curses_winch_handler(int signum)
+{
+    struct winsize {
+        unsigned short ws_row;
+        unsigned short ws_col;
+        unsigned short ws_xpixel;   /* unused */
+        unsigned short ws_ypixel;   /* unused */
+    } ws;
+
+    /* terminal size changed */
+    if (ioctl(1, TIOCGWINSZ, &ws) == -1)
+        return;
+
+    resize_term(ws.ws_row, ws.ws_col);
+    curses_calc_pad();
+    invalidate = 1;
+
+    /* some systems require this */
+    signal(SIGWINCH, curses_winch_handler);
+}
+#endif
+#endif
+
+static void curses_cursor_position(DisplayState *ds, int x, int y)
+{
+    if (x >= 0) {
+        x = sminx + x - px;
+        y = sminy + y - py;
+
+        if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
+            move(y, x);
+            curs_set(1);
+            /* it seems that curs_set(1) must always be called before
+             * curs_set(2) for the latter to have effect */
+            if (!is_graphic_console())
+                curs_set(2);
+            return;
+        }
+    }
+
+    curs_set(0);
+}
+
+/* generic keyboard conversion */
+
+#include "curses_keys.h"
+
+static kbd_layout_t *kbd_layout = NULL;
+
+static void curses_refresh(DisplayState *ds)
+{
+    int chr, nextchr, keysym, keycode, keycode_alt;
+
+    if (invalidate) {
+        clear();
+        refresh();
+        curses_calc_pad();
+        ds->surface->width = FONT_WIDTH * width;
+        ds->surface->height = FONT_HEIGHT * height;
+        vga_hw_invalidate();
+        invalidate = 0;
+    }
+
+    vga_hw_text_update(screen);
+
+    nextchr = ERR;
+    while (1) {
+        /* while there are any pending key strokes to process */
+        if (nextchr == ERR)
+            chr = getch();
+        else {
+            chr = nextchr;
+            nextchr = ERR;
+        }
+
+        if (chr == ERR)
+            break;
+
+#ifdef KEY_RESIZE
+        /* this shouldn't occur when we use a custom SIGWINCH handler */
+        if (chr == KEY_RESIZE) {
+            clear();
+            refresh();
+            curses_calc_pad();
+            curses_update(ds, 0, 0, width, height);
+            ds->surface->width = FONT_WIDTH * width;
+            ds->surface->height = FONT_HEIGHT * height;
+            continue;
+        }
+#endif
+
+        keycode = curses2keycode[chr];
+        keycode_alt = 0;
+
+        /* alt key */
+        if (keycode == 1) {
+            nextchr = getch();
+
+            if (nextchr != ERR) {
+                chr = nextchr;
+                keycode_alt = ALT;
+                keycode = curses2keycode[nextchr];
+                nextchr = ERR;
+
+                if (keycode != -1) {
+                    keycode |= ALT;
+
+                    /* process keys reserved for qemu */
+                    if (keycode >= QEMU_KEY_CONSOLE0 &&
+                            keycode < QEMU_KEY_CONSOLE0 + 9) {
+                        erase();
+                        wnoutrefresh(stdscr);
+                        console_select(keycode - QEMU_KEY_CONSOLE0);
+
+                        invalidate = 1;
+                        continue;
+                    }
+                }
+            }
+        }
+
+        if (kbd_layout) {
+            keysym = -1;
+            if (chr < CURSES_KEYS)
+                keysym = curses2keysym[chr];
+
+            if (keysym == -1) {
+                if (chr < ' ')
+                    keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
+                else
+                    keysym = chr;
+            }
+
+            keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
+            if (keycode == 0)
+                continue;
+
+            keycode |= (keysym & ~KEYSYM_MASK) >> 16;
+            keycode |= keycode_alt;
+        }
+
+        if (keycode == -1)
+            continue;
+
+        if (is_graphic_console()) {
+            /* since terminals don't know about key press and release
+             * events, we need to emit both for each key received */
+            if (keycode & SHIFT)
+                kbd_put_keycode(SHIFT_CODE);
+            if (keycode & CNTRL)
+                kbd_put_keycode(CNTRL_CODE);
+            if (keycode & ALT)
+                kbd_put_keycode(ALT_CODE);
+            if (keycode & ALTGR) {
+                kbd_put_keycode(SCANCODE_EMUL0);
+                kbd_put_keycode(ALT_CODE);
+            }
+            if (keycode & GREY)
+                kbd_put_keycode(GREY_CODE);
+            kbd_put_keycode(keycode & KEY_MASK);
+            if (keycode & GREY)
+                kbd_put_keycode(GREY_CODE);
+            kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
+            if (keycode & ALTGR) {
+                kbd_put_keycode(SCANCODE_EMUL0);
+                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
+            }
+            if (keycode & ALT)
+                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
+            if (keycode & CNTRL)
+                kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
+            if (keycode & SHIFT)
+                kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
+        } else {
+            keysym = curses2qemu[chr];
+            if (keysym == -1)
+                keysym = chr;
+
+            kbd_put_keysym(keysym);
+        }
+    }
+}
+
+static void curses_atexit(void)
+{
+    endwin();
+}
+
+static void curses_setup(void)
+{
+    int i, colour_default[8] = {
+        COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
+        COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
+    };
+
+    /* input as raw as possible, let everything be interpreted
+     * by the guest system */
+    initscr(); noecho(); intrflush(stdscr, FALSE);
+    nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
+    start_color(); raw(); scrollok(stdscr, FALSE);
+
+    for (i = 0; i < 64; i ++)
+        init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
+}
+
+static void curses_keyboard_setup(void)
+{
+#if defined(__APPLE__)
+    /* always use generic keymaps */
+    if (!keyboard_layout)
+        keyboard_layout = "en-us";
+#endif
+    if(keyboard_layout) {
+        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+        if (!kbd_layout)
+            exit(1);
+    }
+}
+
+void curses_display_init(DisplayState *ds, int full_screen)
+{
+    DisplayChangeListener *dcl;
+#ifndef _WIN32
+    if (!isatty(1)) {
+        fprintf(stderr, "We need a terminal output\n");
+        exit(1);
+    }
+#endif
+
+    curses_setup();
+    curses_keyboard_setup();
+    atexit(curses_atexit);
+
+#ifndef _WIN32
+#if defined(SIGWINCH) && defined(KEY_RESIZE)
+    /* some curses implementations provide a handler, but we
+     * want to be sure this is handled regardless of the library */
+    signal(SIGWINCH, curses_winch_handler);
+#endif
+#endif
+
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = curses_update;
+    dcl->dpy_resize = curses_resize;
+    dcl->dpy_refresh = curses_refresh;
+    dcl->dpy_text_cursor = curses_cursor_position;
+    register_displaychangelistener(ds, dcl);
+    qemu_free_displaysurface(ds);
+    ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
+
+    invalidate = 1;
+}
diff --git a/ui/curses_keys.h b/ui/curses_keys.h
new file mode 100644 (file)
index 0000000..1decd11
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Keycode and keysyms conversion tables for curses
+ * 
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <curses.h>
+#include "keymaps.h"
+
+
+#define KEY_RELEASE         0x80
+#define KEY_MASK            0x7f
+#define GREY_CODE           0xe0
+#define GREY                SCANCODE_GREY
+#define SHIFT_CODE          0x2a
+#define SHIFT               SCANCODE_SHIFT
+#define CNTRL_CODE          0x1d
+#define CNTRL               SCANCODE_CTRL
+#define ALT_CODE            0x38
+#define ALT                 SCANCODE_ALT
+#define ALTGR               SCANCODE_ALTGR
+
+#define KEYSYM_MASK         0x0ffffff
+#define KEYSYM_SHIFT        (SCANCODE_SHIFT << 16)
+#define KEYSYM_CNTRL        (SCANCODE_CTRL  << 16)
+#define KEYSYM_ALT          (SCANCODE_ALT   << 16)
+#define KEYSYM_ALTGR        (SCANCODE_ALTGR << 16)
+
+/* curses won't detect a Control + Alt + 1, so use Alt + 1 */
+#define QEMU_KEY_CONSOLE0   (2 | ALT)   /* (curses2keycode['1'] | ALT) */
+
+#define CURSES_KEYS         KEY_MAX     /* KEY_MAX defined in <curses.h> */
+
+static const int curses2keysym[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    [0x7f] = KEY_BACKSPACE,
+    ['\r'] = KEY_ENTER,
+    ['\n'] = KEY_ENTER,
+    [KEY_BTAB] = '\t' | KEYSYM_SHIFT,
+};
+
+static const int curses2keycode[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    [0x01b] = 1, /* Escape */
+    ['1'] = 2,
+    ['2'] = 3,
+    ['3'] = 4,
+    ['4'] = 5,
+    ['5'] = 6,
+    ['6'] = 7,
+    ['7'] = 8,
+    ['8'] = 9,
+    ['9'] = 10,
+    ['0'] = 11,
+    ['-'] = 12,
+    ['='] = 13,
+    [0x07f] = 14, /* Backspace */
+    [KEY_BACKSPACE] = 14, /* Backspace */
+
+    ['\t'] = 15, /* Tab */
+    ['q'] = 16,
+    ['w'] = 17,
+    ['e'] = 18,
+    ['r'] = 19,
+    ['t'] = 20,
+    ['y'] = 21,
+    ['u'] = 22,
+    ['i'] = 23,
+    ['o'] = 24,
+    ['p'] = 25,
+    ['['] = 26,
+    [']'] = 27,
+    ['\n'] = 28, /* Return */
+    ['\r'] = 28, /* Return */
+    [KEY_ENTER] = 28, /* Return */
+
+    ['a'] = 30,
+    ['s'] = 31,
+    ['d'] = 32,
+    ['f'] = 33,
+    ['g'] = 34,
+    ['h'] = 35,
+    ['j'] = 36,
+    ['k'] = 37,
+    ['l'] = 38,
+    [';'] = 39,
+    ['\''] = 40, /* Single quote */
+    ['`'] = 41,
+    ['\\'] = 43, /* Backslash */
+
+    ['z'] = 44,
+    ['x'] = 45,
+    ['c'] = 46,
+    ['v'] = 47,
+    ['b'] = 48,
+    ['n'] = 49,
+    ['m'] = 50,
+    [','] = 51,
+    ['.'] = 52,
+    ['/'] = 53,
+
+    [' '] = 57,
+
+    [KEY_F(1)] = 59, /* Function Key 1 */
+    [KEY_F(2)] = 60, /* Function Key 2 */
+    [KEY_F(3)] = 61, /* Function Key 3 */
+    [KEY_F(4)] = 62, /* Function Key 4 */
+    [KEY_F(5)] = 63, /* Function Key 5 */
+    [KEY_F(6)] = 64, /* Function Key 6 */
+    [KEY_F(7)] = 65, /* Function Key 7 */
+    [KEY_F(8)] = 66, /* Function Key 8 */
+    [KEY_F(9)] = 67, /* Function Key 9 */
+    [KEY_F(10)] = 68, /* Function Key 10 */
+    [KEY_F(11)] = 87, /* Function Key 11 */
+    [KEY_F(12)] = 88, /* Function Key 12 */
+
+    [KEY_HOME] = 71 | GREY, /* Home */
+    [KEY_UP] = 72 | GREY, /* Up Arrow */
+    [KEY_PPAGE] = 73 | GREY, /* Page Up */
+    [KEY_LEFT] = 75 | GREY, /* Left Arrow */
+    [KEY_RIGHT] = 77 | GREY, /* Right Arrow */
+    [KEY_END] = 79 | GREY, /* End */
+    [KEY_DOWN] = 80 | GREY, /* Down Arrow */
+    [KEY_NPAGE] = 81 | GREY, /* Page Down */
+    [KEY_IC] = 82 | GREY, /* Insert */
+    [KEY_DC] = 83 | GREY, /* Delete */
+
+    ['!'] = 2 | SHIFT,
+    ['@'] = 3 | SHIFT,
+    ['#'] = 4 | SHIFT,
+    ['$'] = 5 | SHIFT,
+    ['%'] = 6 | SHIFT,
+    ['^'] = 7 | SHIFT,
+    ['&'] = 8 | SHIFT,
+    ['*'] = 9 | SHIFT,
+    ['('] = 10 | SHIFT,
+    [')'] = 11 | SHIFT,
+    ['_'] = 12 | SHIFT,
+    ['+'] = 13 | SHIFT,
+
+    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
+    ['Q'] = 16 | SHIFT,
+    ['W'] = 17 | SHIFT,
+    ['E'] = 18 | SHIFT,
+    ['R'] = 19 | SHIFT,
+    ['T'] = 20 | SHIFT,
+    ['Y'] = 21 | SHIFT,
+    ['U'] = 22 | SHIFT,
+    ['I'] = 23 | SHIFT,
+    ['O'] = 24 | SHIFT,
+    ['P'] = 25 | SHIFT,
+    ['{'] = 26 | SHIFT,
+    ['}'] = 27 | SHIFT,
+
+    ['A'] = 30 | SHIFT,
+    ['S'] = 31 | SHIFT,
+    ['D'] = 32 | SHIFT,
+    ['F'] = 33 | SHIFT,
+    ['G'] = 34 | SHIFT,
+    ['H'] = 35 | SHIFT,
+    ['J'] = 36 | SHIFT,
+    ['K'] = 37 | SHIFT,
+    ['L'] = 38 | SHIFT,
+    [':'] = 39 | SHIFT,
+    ['"'] = 40 | SHIFT,
+    ['~'] = 41 | SHIFT,
+    ['|'] = 43 | SHIFT,
+
+    ['Z'] = 44 | SHIFT,
+    ['X'] = 45 | SHIFT,
+    ['C'] = 46 | SHIFT,
+    ['V'] = 47 | SHIFT,
+    ['B'] = 48 | SHIFT,
+    ['N'] = 49 | SHIFT,
+    ['M'] = 50 | SHIFT,
+    ['<'] = 51 | SHIFT,
+    ['>'] = 52 | SHIFT,
+    ['?'] = 53 | SHIFT,
+
+    [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
+    [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
+    [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
+    [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
+    [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
+    [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
+    [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
+    [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
+    [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
+    [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
+    [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
+    [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
+
+    ['Q' - '@'] = 16 | CNTRL, /* Control + q */
+    ['W' - '@'] = 17 | CNTRL, /* Control + w */
+    ['E' - '@'] = 18 | CNTRL, /* Control + e */
+    ['R' - '@'] = 19 | CNTRL, /* Control + r */
+    ['T' - '@'] = 20 | CNTRL, /* Control + t */
+    ['Y' - '@'] = 21 | CNTRL, /* Control + y */
+    ['U' - '@'] = 22 | CNTRL, /* Control + u */
+    /* Control + i collides with Tab */
+    ['O' - '@'] = 24 | CNTRL, /* Control + o */
+    ['P' - '@'] = 25 | CNTRL, /* Control + p */
+
+    ['A' - '@'] = 30 | CNTRL, /* Control + a */
+    ['S' - '@'] = 31 | CNTRL, /* Control + s */
+    ['D' - '@'] = 32 | CNTRL, /* Control + d */
+    ['F' - '@'] = 33 | CNTRL, /* Control + f */
+    ['G' - '@'] = 34 | CNTRL, /* Control + g */
+    ['H' - '@'] = 35 | CNTRL, /* Control + h */
+    /* Control + j collides with Return */
+    ['K' - '@'] = 37 | CNTRL, /* Control + k */
+    ['L' - '@'] = 38 | CNTRL, /* Control + l */
+
+    ['Z' - '@'] = 44 | CNTRL, /* Control + z */
+    ['X' - '@'] = 45 | CNTRL, /* Control + x */
+    ['C' - '@'] = 46 | CNTRL, /* Control + c */
+    ['V' - '@'] = 47 | CNTRL, /* Control + v */
+    ['B' - '@'] = 48 | CNTRL, /* Control + b */
+    ['N' - '@'] = 49 | CNTRL, /* Control + n */
+    /* Control + m collides with the keycode for Enter */
+
+};
+
+static const int curses2qemu[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    ['\n'] = '\n',
+    ['\r'] = '\n',
+
+    [0x07f] = QEMU_KEY_BACKSPACE,
+
+    [KEY_DOWN] = QEMU_KEY_DOWN,
+    [KEY_UP] = QEMU_KEY_UP,
+    [KEY_LEFT] = QEMU_KEY_LEFT,
+    [KEY_RIGHT] = QEMU_KEY_RIGHT,
+    [KEY_HOME] = QEMU_KEY_HOME,
+    [KEY_BACKSPACE] = QEMU_KEY_BACKSPACE,
+
+    [KEY_DC] = QEMU_KEY_DELETE,
+    [KEY_NPAGE] = QEMU_KEY_PAGEDOWN,
+    [KEY_PPAGE] = QEMU_KEY_PAGEUP,
+    [KEY_ENTER] = '\n',
+    [KEY_END] = QEMU_KEY_END,
+
+};
+
+static const name2keysym_t name2keysym[] = {
+    /* Plain ASCII */
+    { "space", 0x020 },
+    { "exclam", 0x021 },
+    { "quotedbl", 0x022 },
+    { "numbersign", 0x023 },
+    { "dollar", 0x024 },
+    { "percent", 0x025 },
+    { "ampersand", 0x026 },
+    { "apostrophe", 0x027 },
+    { "parenleft", 0x028 },
+    { "parenright", 0x029 },
+    { "asterisk", 0x02a },
+    { "plus", 0x02b },
+    { "comma", 0x02c },
+    { "minus", 0x02d },
+    { "period", 0x02e },
+    { "slash", 0x02f },
+    { "0", 0x030 },
+    { "1", 0x031 },
+    { "2", 0x032 },
+    { "3", 0x033 },
+    { "4", 0x034 },
+    { "5", 0x035 },
+    { "6", 0x036 },
+    { "7", 0x037 },
+    { "8", 0x038 },
+    { "9", 0x039 },
+    { "colon", 0x03a },
+    { "semicolon", 0x03b },
+    { "less", 0x03c },
+    { "equal", 0x03d },
+    { "greater", 0x03e },
+    { "question", 0x03f },
+    { "at", 0x040 },
+    { "A", 0x041 },
+    { "B", 0x042 },
+    { "C", 0x043 },
+    { "D", 0x044 },
+    { "E", 0x045 },
+    { "F", 0x046 },
+    { "G", 0x047 },
+    { "H", 0x048 },
+    { "I", 0x049 },
+    { "J", 0x04a },
+    { "K", 0x04b },
+    { "L", 0x04c },
+    { "M", 0x04d },
+    { "N", 0x04e },
+    { "O", 0x04f },
+    { "P", 0x050 },
+    { "Q", 0x051 },
+    { "R", 0x052 },
+    { "S", 0x053 },
+    { "T", 0x054 },
+    { "U", 0x055 },
+    { "V", 0x056 },
+    { "W", 0x057 },
+    { "X", 0x058 },
+    { "Y", 0x059 },
+    { "Z", 0x05a },
+    { "bracketleft", 0x05b },
+    { "backslash", 0x05c },
+    { "bracketright", 0x05d },
+    { "asciicircum", 0x05e },
+    { "underscore", 0x05f },
+    { "grave", 0x060 },
+    { "a", 0x061 },
+    { "b", 0x062 },
+    { "c", 0x063 },
+    { "d", 0x064 },
+    { "e", 0x065 },
+    { "f", 0x066 },
+    { "g", 0x067 },
+    { "h", 0x068 },
+    { "i", 0x069 },
+    { "j", 0x06a },
+    { "k", 0x06b },
+    { "l", 0x06c },
+    { "m", 0x06d },
+    { "n", 0x06e },
+    { "o", 0x06f },
+    { "p", 0x070 },
+    { "q", 0x071 },
+    { "r", 0x072 },
+    { "s", 0x073 },
+    { "t", 0x074 },
+    { "u", 0x075 },
+    { "v", 0x076 },
+    { "w", 0x077 },
+    { "x", 0x078 },
+    { "y", 0x079 },
+    { "z", 0x07a },
+    { "braceleft", 0x07b },
+    { "bar", 0x07c },
+    { "braceright", 0x07d },
+    { "asciitilde", 0x07e },
+
+    /* Latin-1 extensions */
+    { "nobreakspace", 0x0a0 },
+    { "exclamdown", 0x0a1 },
+    { "cent", 0x0a2 },
+    { "sterling", 0x0a3 },
+    { "currency", 0x0a4 },
+    { "yen", 0x0a5 },
+    { "brokenbar", 0x0a6 },
+    { "section", 0x0a7 },
+    { "diaeresis", 0x0a8 },
+    { "copyright", 0x0a9 },
+    { "ordfeminine", 0x0aa },
+    { "guillemotleft", 0x0ab },
+    { "notsign", 0x0ac },
+    { "hyphen", 0x0ad },
+    { "registered", 0x0ae },
+    { "macron", 0x0af },
+    { "degree", 0x0b0 },
+    { "plusminus", 0x0b1 },
+    { "twosuperior", 0x0b2 },
+    { "threesuperior", 0x0b3 },
+    { "acute", 0x0b4 },
+    { "mu", 0x0b5 },
+    { "paragraph", 0x0b6 },
+    { "periodcentered", 0x0b7 },
+    { "cedilla", 0x0b8 },
+    { "onesuperior", 0x0b9 },
+    { "masculine", 0x0ba },
+    { "guillemotright", 0x0bb },
+    { "onequarter", 0x0bc },
+    { "onehalf", 0x0bd },
+    { "threequarters", 0x0be },
+    { "questiondown", 0x0bf },
+    { "Agrave", 0x0c0 },
+    { "Aacute", 0x0c1 },
+    { "Acircumflex", 0x0c2 },
+    { "Atilde", 0x0c3 },
+    { "Adiaeresis", 0x0c4 },
+    { "Aring", 0x0c5 },
+    { "AE", 0x0c6 },
+    { "Ccedilla", 0x0c7 },
+    { "Egrave", 0x0c8 },
+    { "Eacute", 0x0c9 },
+    { "Ecircumflex", 0x0ca },
+    { "Ediaeresis", 0x0cb },
+    { "Igrave", 0x0cc },
+    { "Iacute", 0x0cd },
+    { "Icircumflex", 0x0ce },
+    { "Idiaeresis", 0x0cf },
+    { "ETH", 0x0d0 },
+    { "Eth", 0x0d0 },
+    { "Ntilde", 0x0d1 },
+    { "Ograve", 0x0d2 },
+    { "Oacute", 0x0d3 },
+    { "Ocircumflex", 0x0d4 },
+    { "Otilde", 0x0d5 },
+    { "Odiaeresis", 0x0d6 },
+    { "multiply", 0x0d7 },
+    { "Ooblique", 0x0d8 },
+    { "Oslash", 0x0d8 },
+    { "Ugrave", 0x0d9 },
+    { "Uacute", 0x0da },
+    { "Ucircumflex", 0x0db },
+    { "Udiaeresis", 0x0dc },
+    { "Yacute", 0x0dd },
+    { "THORN", 0x0de },
+    { "Thorn", 0x0de },
+    { "ssharp", 0x0df },
+    { "agrave", 0x0e0 },
+    { "aacute", 0x0e1 },
+    { "acircumflex", 0x0e2 },
+    { "atilde", 0x0e3 },
+    { "adiaeresis", 0x0e4 },
+    { "aring", 0x0e5 },
+    { "ae", 0x0e6 },
+    { "ccedilla", 0x0e7 },
+    { "egrave", 0x0e8 },
+    { "eacute", 0x0e9 },
+    { "ecircumflex", 0x0ea },
+    { "ediaeresis", 0x0eb },
+    { "igrave", 0x0ec },
+    { "iacute", 0x0ed },
+    { "icircumflex", 0x0ee },
+    { "idiaeresis", 0x0ef },
+    { "eth", 0x0f0 },
+    { "ntilde", 0x0f1 },
+    { "ograve", 0x0f2 },
+    { "oacute", 0x0f3 },
+    { "ocircumflex", 0x0f4 },
+    { "otilde", 0x0f5 },
+    { "odiaeresis", 0x0f6 },
+    { "division", 0x0f7 },
+    { "oslash", 0x0f8 },
+    { "ooblique", 0x0f8 },
+    { "ugrave", 0x0f9 },
+    { "uacute", 0x0fa },
+    { "ucircumflex", 0x0fb },
+    { "udiaeresis", 0x0fc },
+    { "yacute", 0x0fd },
+    { "thorn", 0x0fe },
+    { "ydiaeresis", 0x0ff },
+
+    /* Special keys */
+    { "BackSpace", KEY_BACKSPACE },
+    { "Tab", '\t' },
+    { "Return", KEY_ENTER },
+    { "Right", KEY_RIGHT },
+    { "Left", KEY_LEFT },
+    { "Up", KEY_UP },
+    { "Down", KEY_DOWN },
+    { "Page_Down", KEY_NPAGE },
+    { "Page_Up", KEY_PPAGE },
+    { "Insert", KEY_IC },
+    { "Delete", KEY_DC },
+    { "Home", KEY_HOME },
+    { "End", KEY_END },
+    { "F1", KEY_F(1) },
+    { "F2", KEY_F(2) },
+    { "F3", KEY_F(3) },
+    { "F4", KEY_F(4) },
+    { "F5", KEY_F(5) },
+    { "F6", KEY_F(6) },
+    { "F7", KEY_F(7) },
+    { "F8", KEY_F(8) },
+    { "F9", KEY_F(9) },
+    { "F10", KEY_F(10) },
+    { "F11", KEY_F(11) },
+    { "F12", KEY_F(12) },
+    { "F13", KEY_F(13) },
+    { "F14", KEY_F(14) },
+    { "F15", KEY_F(15) },
+    { "F16", KEY_F(16) },
+    { "F17", KEY_F(17) },
+    { "F18", KEY_F(18) },
+    { "F19", KEY_F(19) },
+    { "F20", KEY_F(20) },
+    { "F21", KEY_F(21) },
+    { "F22", KEY_F(22) },
+    { "F23", KEY_F(23) },
+    { "F24", KEY_F(24) },
+    { "Escape", 27 },
+
+    { NULL, 0 },
+};
diff --git a/ui/d3des.c b/ui/d3des.c
new file mode 100644 (file)
index 0000000..60c840e
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static const unsigned short bytebit[8] = {
+       01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static const unsigned long bigbyte[24] = {
+       0x800000L,      0x400000L,      0x200000L,      0x100000L,
+       0x80000L,       0x40000L,       0x20000L,       0x10000L,
+       0x8000L,        0x4000L,        0x2000L,        0x1000L,
+       0x800L,         0x400L,         0x200L,         0x100L,
+       0x80L,          0x40L,          0x20L,          0x10L,
+       0x8L,           0x4L,           0x2L,           0x1L    };
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static const unsigned char pc1[56] = {
+       56, 48, 40, 32, 24, 16,  8,      0, 57, 49, 41, 33, 25, 17,
+        9,  1, 58, 50, 42, 34, 26,     18, 10,  2, 59, 51, 43, 35,
+       62, 54, 46, 38, 30, 22, 14,      6, 61, 53, 45, 37, 29, 21,
+       13,  5, 60, 52, 44, 36, 28,     20, 12,  4, 27, 19, 11,  3 };
+
+static const unsigned char totrot[16] = {
+       1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static const unsigned char pc2[48] = {
+       13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+       22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+       40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+       43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+/* Thanks to James Gillogly & Phil Karn! */
+void deskey(unsigned char *key, int edf)
+{
+       register int i, j, l, m, n;
+       unsigned char pc1m[56], pcr[56];
+       unsigned long kn[32];
+
+       for ( j = 0; j < 56; j++ ) {
+               l = pc1[j];
+               m = l & 07;
+               pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+               }
+       for( i = 0; i < 16; i++ ) {
+               if( edf == DE1 ) m = (15 - i) << 1;
+               else m = i << 1;
+               n = m + 1;
+               kn[m] = kn[n] = 0L;
+               for( j = 0; j < 28; j++ ) {
+                       l = j + totrot[i];
+                       if( l < 28 ) pcr[j] = pc1m[l];
+                       else pcr[j] = pc1m[l - 28];
+                       }
+               for( j = 28; j < 56; j++ ) {
+                   l = j + totrot[i];
+                   if( l < 56 ) pcr[j] = pc1m[l];
+                   else pcr[j] = pc1m[l - 28];
+                   }
+               for( j = 0; j < 24; j++ ) {
+                       if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+                       if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+                       }
+               }
+       cookey(kn);
+       return;
+       }
+
+static void cookey(register unsigned long *raw1)
+{
+       register unsigned long *cook, *raw0;
+       unsigned long dough[32];
+       register int i;
+
+       cook = dough;
+       for( i = 0; i < 16; i++, raw1++ ) {
+               raw0 = raw1++;
+               *cook    = (*raw0 & 0x00fc0000L) << 6;
+               *cook   |= (*raw0 & 0x00000fc0L) << 10;
+               *cook   |= (*raw1 & 0x00fc0000L) >> 10;
+               *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+               *cook    = (*raw0 & 0x0003f000L) << 12;
+               *cook   |= (*raw0 & 0x0000003fL) << 16;
+               *cook   |= (*raw1 & 0x0003f000L) >> 4;
+               *cook++ |= (*raw1 & 0x0000003fL);
+               }
+       usekey(dough);
+       return;
+       }
+
+void cpkey(register unsigned long *into)
+{
+       register unsigned long *from, *endp;
+
+       from = KnL, endp = &KnL[32];
+       while( from < endp ) *into++ = *from++;
+       return;
+       }
+
+void usekey(register unsigned long *from)
+{
+       register unsigned long *to, *endp;
+
+       to = KnL, endp = &KnL[32];
+       while( to < endp ) *to++ = *from++;
+       return;
+       }
+
+void des(unsigned char *inblock, unsigned char *outblock)
+{
+       unsigned long work[2];
+
+       scrunch(inblock, work);
+       desfunc(work, KnL);
+       unscrun(work, outblock);
+       return;
+       }
+
+static void scrunch(register unsigned char *outof, register unsigned long *into)
+{
+       *into    = (*outof++ & 0xffL) << 24;
+       *into   |= (*outof++ & 0xffL) << 16;
+       *into   |= (*outof++ & 0xffL) << 8;
+       *into++ |= (*outof++ & 0xffL);
+       *into    = (*outof++ & 0xffL) << 24;
+       *into   |= (*outof++ & 0xffL) << 16;
+       *into   |= (*outof++ & 0xffL) << 8;
+       *into   |= (*outof   & 0xffL);
+       return;
+       }
+
+static void unscrun(register unsigned long *outof, register unsigned char *into)
+{
+       *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+       *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+       *into++ = (unsigned char)((*outof >>  8) & 0xffL);
+       *into++ = (unsigned char)(*outof++       & 0xffL);
+       *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+       *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+       *into++ = (unsigned char)((*outof >>  8) & 0xffL);
+       *into   =  (unsigned char)(*outof        & 0xffL);
+       return;
+       }
+
+static const unsigned long SP1[64] = {
+       0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+       0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+       0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+       0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+       0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+       0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+       0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+       0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+       0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+       0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+       0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+       0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+       0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+       0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+       0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+       0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static const unsigned long SP2[64] = {
+       0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+       0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+       0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+       0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+       0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+       0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+       0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+       0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+       0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+       0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+       0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+       0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+       0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+       0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+       0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+       0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static const unsigned long SP3[64] = {
+       0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+       0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+       0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+       0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+       0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+       0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+       0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+       0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+       0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+       0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+       0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+       0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+       0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+       0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+       0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+       0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static const unsigned long SP4[64] = {
+       0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+       0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+       0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+       0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+       0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+       0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+       0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+       0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+       0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+       0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+       0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+       0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+       0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+       0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+       0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+       0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static const unsigned long SP5[64] = {
+       0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+       0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+       0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+       0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+       0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+       0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+       0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+       0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+       0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+       0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+       0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+       0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+       0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+       0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+       0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+       0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static const unsigned long SP6[64] = {
+       0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+       0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+       0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+       0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+       0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+       0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+       0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+       0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+       0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+       0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+       0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+       0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+       0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+       0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+       0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+       0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static const unsigned long SP7[64] = {
+       0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+       0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+       0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+       0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+       0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+       0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+       0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+       0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+       0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+       0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+       0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+       0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+       0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+       0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+       0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+       0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static const unsigned long SP8[64] = {
+       0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+       0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+       0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+       0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+       0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+       0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+       0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+       0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+       0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+       0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+       0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+       0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+       0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+       0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+       0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+       0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(register unsigned long *block, register unsigned long *keys)
+{
+       register unsigned long fval, work, right, leftt;
+       register int round;
+
+       leftt = block[0];
+       right = block[1];
+       work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+       right ^= work;
+       leftt ^= (work << 4);
+       work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+       right ^= work;
+       leftt ^= (work << 16);
+       work = ((right >> 2) ^ leftt) & 0x33333333L;
+       leftt ^= work;
+       right ^= (work << 2);
+       work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+       leftt ^= work;
+       right ^= (work << 8);
+       right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+       work = (leftt ^ right) & 0xaaaaaaaaL;
+       leftt ^= work;
+       right ^= work;
+       leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+       for( round = 0; round < 8; round++ ) {
+               work  = (right << 28) | (right >> 4);
+               work ^= *keys++;
+               fval  = SP7[ work                & 0x3fL];
+               fval |= SP5[(work >>  8) & 0x3fL];
+               fval |= SP3[(work >> 16) & 0x3fL];
+               fval |= SP1[(work >> 24) & 0x3fL];
+               work  = right ^ *keys++;
+               fval |= SP8[ work                & 0x3fL];
+               fval |= SP6[(work >>  8) & 0x3fL];
+               fval |= SP4[(work >> 16) & 0x3fL];
+               fval |= SP2[(work >> 24) & 0x3fL];
+               leftt ^= fval;
+               work  = (leftt << 28) | (leftt >> 4);
+               work ^= *keys++;
+               fval  = SP7[ work                & 0x3fL];
+               fval |= SP5[(work >>  8) & 0x3fL];
+               fval |= SP3[(work >> 16) & 0x3fL];
+               fval |= SP1[(work >> 24) & 0x3fL];
+               work  = leftt ^ *keys++;
+               fval |= SP8[ work                & 0x3fL];
+               fval |= SP6[(work >>  8) & 0x3fL];
+               fval |= SP4[(work >> 16) & 0x3fL];
+               fval |= SP2[(work >> 24) & 0x3fL];
+               right ^= fval;
+               }
+
+       right = (right << 31) | (right >> 1);
+       work = (leftt ^ right) & 0xaaaaaaaaL;
+       leftt ^= work;
+       right ^= work;
+       leftt = (leftt << 31) | (leftt >> 1);
+       work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+       right ^= work;
+       leftt ^= (work << 8);
+       work = ((leftt >> 2) ^ right) & 0x33333333L;
+       right ^= work;
+       leftt ^= (work << 2);
+       work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+       leftt ^= work;
+       right ^= (work << 16);
+       work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+       leftt ^= work;
+       right ^= (work << 4);
+       *block++ = right;
+       *block = leftt;
+       return;
+       }
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key   : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key   : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/ui/d3des.h b/ui/d3des.h
new file mode 100644 (file)
index 0000000..ea3da44
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* d3des.h -
+ *
+ *     Headers and defines for d3des.c
+ *     Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *     (GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0    0       /* MODE == encrypt */
+#define DE1    1       /* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/*                   hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/*                 cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/*                cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/*                 from[8]           to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/ui/keymaps.c b/ui/keymaps.c
new file mode 100644 (file)
index 0000000..78c7ea3
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * QEMU keysym to keycode conversion using rdesktop keymaps
+ *
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "keymaps.h"
+#include "sysemu.h"
+
+static int get_keysym(const name2keysym_t *table,
+                     const char *name)
+{
+    const name2keysym_t *p;
+    for(p = table; p->name != NULL; p++) {
+        if (!strcmp(p->name, name))
+            return p->keysym;
+    }
+    return 0;
+}
+
+
+static void add_to_key_range(struct key_range **krp, int code) {
+    struct key_range *kr;
+    for (kr = *krp; kr; kr = kr->next) {
+       if (code >= kr->start && code <= kr->end)
+           break;
+       if (code == kr->start - 1) {
+           kr->start--;
+           break;
+       }
+       if (code == kr->end + 1) {
+           kr->end++;
+           break;
+       }
+    }
+    if (kr == NULL) {
+       kr = qemu_mallocz(sizeof(*kr));
+        kr->start = kr->end = code;
+        kr->next = *krp;
+        *krp = kr;
+    }
+}
+
+static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) {
+    if (keysym < MAX_NORMAL_KEYCODE) {
+       //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
+       k->keysym2keycode[keysym] = keycode;
+    } else {
+       if (k->extra_count >= MAX_EXTRA_COUNT) {
+           fprintf(stderr,
+                   "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n",
+                   line, keysym);
+       } else {
+#if 0
+           fprintf(stderr, "Setting %d: %d,%d\n",
+                   k->extra_count, keysym, keycode);
+#endif
+           k->keysym2keycode_extra[k->extra_count].
+               keysym = keysym;
+           k->keysym2keycode_extra[k->extra_count].
+               keycode = keycode;
+           k->extra_count++;
+       }
+    }
+}
+
+static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
+                                          const char *language,
+                                          kbd_layout_t * k)
+{
+    FILE *f;
+    char * filename;
+    char line[1024];
+    int len;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
+
+    if (!k)
+       k = qemu_mallocz(sizeof(kbd_layout_t));
+    if (!(filename && (f = fopen(filename, "r")))) {
+       fprintf(stderr,
+               "Could not read keymap file: '%s'\n", language);
+       return NULL;
+    }
+    qemu_free(filename);
+    for(;;) {
+       if (fgets(line, 1024, f) == NULL)
+            break;
+        len = strlen(line);
+        if (len > 0 && line[len - 1] == '\n')
+            line[len - 1] = '\0';
+        if (line[0] == '#')
+           continue;
+       if (!strncmp(line, "map ", 4))
+           continue;
+       if (!strncmp(line, "include ", 8)) {
+           parse_keyboard_layout(table, line + 8, k);
+        } else {
+           char *end_of_keysym = line;
+           while (*end_of_keysym != 0 && *end_of_keysym != ' ')
+               end_of_keysym++;
+           if (*end_of_keysym) {
+               int keysym;
+               *end_of_keysym = 0;
+               keysym = get_keysym(table, line);
+               if (keysym == 0) {
+                    //             fprintf(stderr, "Warning: unknown keysym %s\n", line);
+               } else {
+                   const char *rest = end_of_keysym + 1;
+                   char *rest2;
+                   int keycode = strtol(rest, &rest2, 0);
+
+                   if (rest && strstr(rest, "numlock")) {
+                       add_to_key_range(&k->keypad_range, keycode);
+                       add_to_key_range(&k->numlock_range, keysym);
+                       //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode);
+                   }
+
+                   if (rest && strstr(rest, "shift"))
+                       keycode |= SCANCODE_SHIFT;
+                   if (rest && strstr(rest, "altgr"))
+                       keycode |= SCANCODE_ALTGR;
+                   if (rest && strstr(rest, "ctrl"))
+                       keycode |= SCANCODE_CTRL;
+
+                   add_keysym(line, keysym, keycode, k);
+
+                   if (rest && strstr(rest, "addupper")) {
+                       char *c;
+                       for (c = line; *c; c++)
+                           *c = toupper(*c);
+                       keysym = get_keysym(table, line);
+                       if (keysym)
+                           add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k);
+                   }
+               }
+           }
+       }
+    }
+    fclose(f);
+    return k;
+}
+
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language)
+{
+    return parse_keyboard_layout(table, language, NULL);
+}
+
+
+int keysym2scancode(void *kbd_layout, int keysym)
+{
+    kbd_layout_t *k = kbd_layout;
+    if (keysym < MAX_NORMAL_KEYCODE) {
+       if (k->keysym2keycode[keysym] == 0)
+           fprintf(stderr, "Warning: no scancode found for keysym %d\n",
+                   keysym);
+       return k->keysym2keycode[keysym];
+    } else {
+       int i;
+#ifdef XK_ISO_Left_Tab
+       if (keysym == XK_ISO_Left_Tab)
+           keysym = XK_Tab;
+#endif
+       for (i = 0; i < k->extra_count; i++)
+           if (k->keysym2keycode_extra[i].keysym == keysym)
+               return k->keysym2keycode_extra[i].keycode;
+    }
+    return 0;
+}
+
+int keycode_is_keypad(void *kbd_layout, int keycode)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->keypad_range; kr; kr = kr->next)
+        if (keycode >= kr->start && keycode <= kr->end)
+            return 1;
+    return 0;
+}
+
+int keysym_is_numlock(void *kbd_layout, int keysym)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->numlock_range; kr; kr = kr->next)
+        if (keysym >= kr->start && keysym <= kr->end)
+            return 1;
+    return 0;
+}
diff --git a/ui/keymaps.h b/ui/keymaps.h
new file mode 100644 (file)
index 0000000..a7600d5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * QEMU keysym to keycode conversion using rdesktop keymaps
+ *
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_KEYMAPS_H__
+#define __QEMU_KEYMAPS_H__
+
+#include "qemu-common.h"
+
+typedef struct {
+       const char* name;
+       int keysym;
+} name2keysym_t;
+
+struct key_range {
+    int start;
+    int end;
+    struct key_range *next;
+};
+
+#define MAX_NORMAL_KEYCODE 512
+#define MAX_EXTRA_COUNT 256
+typedef struct {
+    uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+    struct {
+       int keysym;
+       uint16_t keycode;
+    } keysym2keycode_extra[MAX_EXTRA_COUNT];
+    int extra_count;
+    struct key_range *keypad_range;
+    struct key_range *numlock_range;
+} kbd_layout_t;
+
+/* scancode without modifiers */
+#define SCANCODE_KEYMASK 0xff
+/* scancode without grey or up bit */
+#define SCANCODE_KEYCODEMASK 0x7f
+
+/* "grey" keys will usually need a 0xe0 prefix */
+#define SCANCODE_GREY   0x80
+#define SCANCODE_EMUL0  0xE0
+/* "up" flag */
+#define SCANCODE_UP     0x80
+
+/* Additional modifiers to use if not catched another way. */
+#define SCANCODE_SHIFT  0x100
+#define SCANCODE_CTRL   0x200
+#define SCANCODE_ALT    0x400
+#define SCANCODE_ALTGR  0x800
+
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language);
+int keysym2scancode(void *kbd_layout, int keysym);
+int keycode_is_keypad(void *kbd_layout, int keycode);
+int keysym_is_numlock(void *kbd_layout, int keysym);
+
+#endif /* __QEMU_KEYMAPS_H__ */
diff --git a/ui/sdl.c b/ui/sdl.c
new file mode 100644 (file)
index 0000000..0072680
--- /dev/null
+++ b/ui/sdl.c
@@ -0,0 +1,879 @@
+/*
+ * QEMU SDL display driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <SDL.h>
+#include <SDL_syswm.h>
+
+#ifndef _WIN32
+#include <signal.h>
+#endif
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+#include "x_keymap.h"
+#include "sdl_zoom.h"
+
+static DisplayChangeListener *dcl;
+static SDL_Surface *real_screen;
+static SDL_Surface *guest_screen = NULL;
+static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
+static int last_vm_running;
+static int gui_saved_grab;
+static int gui_fullscreen;
+static int gui_noframe;
+static int gui_key_modifier_pressed;
+static int gui_keysym;
+static int gui_fullscreen_initial_grab;
+static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
+static uint8_t modifiers_state[256];
+static int width, height;
+static SDL_Cursor *sdl_cursor_normal;
+static SDL_Cursor *sdl_cursor_hidden;
+static int absolute_enabled = 0;
+static int guest_cursor = 0;
+static int guest_x, guest_y;
+static SDL_Cursor *guest_sprite = NULL;
+static uint8_t allocator;
+static SDL_PixelFormat host_format;
+static int scaling_active = 0;
+static Notifier mouse_mode_notifier;
+
+static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
+    SDL_Rect rec;
+    rec.x = x;
+    rec.y = y;
+    rec.w = w;
+    rec.h = h;
+
+    if (guest_screen) {
+        if (!scaling_active) {
+            SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
+        } else {
+            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
+                fprintf(stderr, "Zoom blit failed\n");
+                exit(1);
+            }
+        }
+    } 
+    SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
+}
+
+static void sdl_setdata(DisplayState *ds)
+{
+    SDL_Rect rec;
+    rec.x = 0;
+    rec.y = 0;
+    rec.w = real_screen->w;
+    rec.h = real_screen->h;
+
+    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
+
+    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
+                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
+                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
+                                            ds->surface->pf.bmask, ds->surface->pf.amask);
+}
+
+static void do_sdl_resize(int new_width, int new_height, int bpp)
+{
+    int flags;
+
+    //    printf("resizing to %d %d\n", w, h);
+
+    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
+    if (gui_fullscreen)
+        flags |= SDL_FULLSCREEN;
+    if (gui_noframe)
+        flags |= SDL_NOFRAME;
+
+    width = new_width;
+    height = new_height;
+    real_screen = SDL_SetVideoMode(width, height, bpp, flags);
+    if (!real_screen) {
+       fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
+               height, bpp, SDL_GetError());
+        exit(1);
+    }
+}
+
+static void sdl_resize(DisplayState *ds)
+{
+    if  (!allocator) {
+        if (!scaling_active)
+            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
+            do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
+        sdl_setdata(ds);
+    } else {
+        if (guest_screen != NULL) {
+            SDL_FreeSurface(guest_screen);
+            guest_screen = NULL;
+        }
+    }
+}
+
+static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
+{
+    PixelFormat qemu_pf;
+
+    memset(&qemu_pf, 0x00, sizeof(PixelFormat));
+
+    qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
+    qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
+    qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
+
+    qemu_pf.rmask = sdl_pf->Rmask;
+    qemu_pf.gmask = sdl_pf->Gmask;
+    qemu_pf.bmask = sdl_pf->Bmask;
+    qemu_pf.amask = sdl_pf->Amask;
+
+    qemu_pf.rshift = sdl_pf->Rshift;
+    qemu_pf.gshift = sdl_pf->Gshift;
+    qemu_pf.bshift = sdl_pf->Bshift;
+    qemu_pf.ashift = sdl_pf->Ashift;
+
+    qemu_pf.rbits = 8 - sdl_pf->Rloss;
+    qemu_pf.gbits = 8 - sdl_pf->Gloss;
+    qemu_pf.bbits = 8 - sdl_pf->Bloss;
+    qemu_pf.abits = 8 - sdl_pf->Aloss;
+
+    qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
+    qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
+    qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
+    qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
+
+    return qemu_pf;
+}
+
+static DisplaySurface* sdl_create_displaysurface(int width, int height)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    if (surface == NULL) {
+        fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
+        exit(1);
+    }
+
+    surface->width = width;
+    surface->height = height;
+    
+    if (scaling_active) {
+        if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
+            surface->linesize = width * 4;
+            surface->pf = qemu_default_pixelformat(32);
+        } else {
+            surface->linesize = width * host_format.BytesPerPixel;
+            surface->pf = sdl_to_qemu_pixelformat(&host_format);
+        }
+#ifdef HOST_WORDS_BIGENDIAN
+        surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+        surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+        surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+
+        return surface;
+    }
+
+    if (host_format.BitsPerPixel == 16)
+        do_sdl_resize(width, height, 16);
+    else
+        do_sdl_resize(width, height, 32);
+
+    surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
+    surface->linesize = real_screen->pitch;
+    surface->data = real_screen->pixels;
+
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_REALPIXELS_FLAG;
+#endif
+    allocator = 1;
+
+    return surface;
+}
+
+static void sdl_free_displaysurface(DisplaySurface *surface)
+{
+    allocator = 0;
+    if (surface == NULL)
+        return;
+
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
+}
+
+static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
+{
+    sdl_free_displaysurface(surface);
+    return sdl_create_displaysurface(width, height);
+}
+
+/* generic keyboard conversion */
+
+#include "sdl_keysym.h"
+
+static kbd_layout_t *kbd_layout = NULL;
+
+static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
+{
+    int keysym;
+    /* workaround for X11+SDL bug with AltGR */
+    keysym = ev->keysym.sym;
+    if (keysym == 0 && ev->keysym.scancode == 113)
+        keysym = SDLK_MODE;
+    /* For Japanese key '\' and '|' */
+    if (keysym == 92 && ev->keysym.scancode == 133) {
+        keysym = 0xa5;
+    }
+    return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
+}
+
+/* specific keyboard conversions from scan codes */
+
+#if defined(_WIN32)
+
+static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
+{
+    return ev->keysym.scancode;
+}
+
+#else
+
+#if defined(SDL_VIDEO_DRIVER_X11)
+#include <X11/XKBlib.h>
+
+static int check_for_evdev(void)
+{
+    SDL_SysWMinfo info;
+    XkbDescPtr desc = NULL;
+    int has_evdev = 0;
+    char *keycodes = NULL;
+
+    SDL_VERSION(&info.version);
+    if (!SDL_GetWMInfo(&info)) {
+        return 0;
+    }
+    desc = XkbGetKeyboard(info.info.x11.display,
+                          XkbGBN_AllComponentsMask,
+                          XkbUseCoreKbd);
+    if (desc && desc->names) {
+        keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
+        if (keycodes == NULL) {
+            fprintf(stderr, "could not lookup keycode name\n");
+        } else if (strstart(keycodes, "evdev", NULL)) {
+            has_evdev = 1;
+        } else if (!strstart(keycodes, "xfree86", NULL)) {
+            fprintf(stderr, "unknown keycodes `%s', please report to "
+                    "qemu-devel@nongnu.org\n", keycodes);
+        }
+    }
+
+    if (desc) {
+        XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
+    }
+    if (keycodes) {
+        XFree(keycodes);
+    }
+    return has_evdev;
+}
+#else
+static int check_for_evdev(void)
+{
+       return 0;
+}
+#endif
+
+static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
+{
+    int keycode;
+    static int has_evdev = -1;
+
+    if (has_evdev == -1)
+        has_evdev = check_for_evdev();
+
+    keycode = ev->keysym.scancode;
+
+    if (keycode < 9) {
+        keycode = 0;
+    } else if (keycode < 97) {
+        keycode -= 8; /* just an offset */
+    } else if (keycode < 158) {
+        /* use conversion table */
+        if (has_evdev)
+            keycode = translate_evdev_keycode(keycode - 97);
+        else
+            keycode = translate_xfree86_keycode(keycode - 97);
+    } else if (keycode == 208) { /* Hiragana_Katakana */
+        keycode = 0x70;
+    } else if (keycode == 211) { /* backslash */
+        keycode = 0x73;
+    } else {
+        keycode = 0;
+    }
+    return keycode;
+}
+
+#endif
+
+static void reset_keys(void)
+{
+    int i;
+    for(i = 0; i < 256; i++) {
+        if (modifiers_state[i]) {
+            if (i & SCANCODE_GREY)
+                kbd_put_keycode(SCANCODE_EMUL0);
+            kbd_put_keycode(i | SCANCODE_UP);
+            modifiers_state[i] = 0;
+        }
+    }
+}
+
+static void sdl_process_key(SDL_KeyboardEvent *ev)
+{
+    int keycode, v;
+
+    if (ev->keysym.sym == SDLK_PAUSE) {
+        /* specific case */
+        v = 0;
+        if (ev->type == SDL_KEYUP)
+            v |= SCANCODE_UP;
+        kbd_put_keycode(0xe1);
+        kbd_put_keycode(0x1d | v);
+        kbd_put_keycode(0x45 | v);
+        return;
+    }
+
+    if (kbd_layout) {
+        keycode = sdl_keyevent_to_keycode_generic(ev);
+    } else {
+        keycode = sdl_keyevent_to_keycode(ev);
+    }
+
+    switch(keycode) {
+    case 0x00:
+        /* sent when leaving window: reset the modifiers state */
+        reset_keys();
+        return;
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                         /* Right ALT */
+        if (ev->type == SDL_KEYUP)
+            modifiers_state[keycode] = 0;
+        else
+            modifiers_state[keycode] = 1;
+        break;
+    case 0x45: /* num lock */
+    case 0x3a: /* caps lock */
+        /* SDL does not send the key up event, so we generate it */
+        kbd_put_keycode(keycode);
+        kbd_put_keycode(keycode | SCANCODE_UP);
+        return;
+    }
+
+    /* now send the key code */
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    if (ev->type == SDL_KEYUP)
+        kbd_put_keycode(keycode | SCANCODE_UP);
+    else
+        kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+}
+
+static void sdl_update_caption(void)
+{
+    char win_title[1024];
+    char icon_title[1024];
+    const char *status = "";
+
+    if (!vm_running)
+        status = " [Stopped]";
+    else if (gui_grab) {
+        if (alt_grab)
+            status = " - Press Ctrl-Alt-Shift to exit mouse grab";
+        else if (ctrl_grab)
+            status = " - Press Right-Ctrl to exit mouse grab";
+        else
+            status = " - Press Ctrl-Alt to exit mouse grab";
+    }
+
+    if (qemu_name) {
+        snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
+        snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
+    } else {
+        snprintf(win_title, sizeof(win_title), "QEMU%s", status);
+        snprintf(icon_title, sizeof(icon_title), "QEMU");
+    }
+
+    SDL_WM_SetCaption(win_title, icon_title);
+}
+
+static void sdl_hide_cursor(void)
+{
+    if (!cursor_hide)
+        return;
+
+    if (kbd_mouse_is_absolute()) {
+        SDL_ShowCursor(1);
+        SDL_SetCursor(sdl_cursor_hidden);
+    } else {
+        SDL_ShowCursor(0);
+    }
+}
+
+static void sdl_show_cursor(void)
+{
+    if (!cursor_hide)
+        return;
+
+    if (!kbd_mouse_is_absolute()) {
+        SDL_ShowCursor(1);
+        if (guest_cursor &&
+                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+            SDL_SetCursor(guest_sprite);
+        else
+            SDL_SetCursor(sdl_cursor_normal);
+    }
+}
+
+static void sdl_grab_start(void)
+{
+    if (guest_cursor) {
+        SDL_SetCursor(guest_sprite);
+        if (!kbd_mouse_is_absolute() && !absolute_enabled)
+            SDL_WarpMouse(guest_x, guest_y);
+    } else
+        sdl_hide_cursor();
+
+    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
+        gui_grab = 1;
+        sdl_update_caption();
+    } else
+        sdl_show_cursor();
+}
+
+static void sdl_grab_end(void)
+{
+    SDL_WM_GrabInput(SDL_GRAB_OFF);
+    gui_grab = 0;
+    sdl_show_cursor();
+    sdl_update_caption();
+}
+
+static void sdl_mouse_mode_change(Notifier *notify)
+{
+    if (kbd_mouse_is_absolute()) {
+        if (!absolute_enabled) {
+            sdl_hide_cursor();
+            if (gui_grab) {
+                sdl_grab_end();
+            }
+            absolute_enabled = 1;
+        }
+    } else if (absolute_enabled) {
+       sdl_show_cursor();
+       absolute_enabled = 0;
+    }
+}
+
+static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
+{
+    int buttons;
+    buttons = 0;
+    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
+        buttons |= MOUSE_EVENT_LBUTTON;
+    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
+        buttons |= MOUSE_EVENT_RBUTTON;
+    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
+        buttons |= MOUSE_EVENT_MBUTTON;
+
+    if (kbd_mouse_is_absolute()) {
+       dx = x * 0x7FFF / (width - 1);
+       dy = y * 0x7FFF / (height - 1);
+    } else if (guest_cursor) {
+        x -= guest_x;
+        y -= guest_y;
+        guest_x += x;
+        guest_y += y;
+        dx = x;
+        dy = y;
+    }
+
+    kbd_mouse_event(dx, dy, dz, buttons);
+}
+
+static void toggle_full_screen(DisplayState *ds)
+{
+    gui_fullscreen = !gui_fullscreen;
+    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
+    if (gui_fullscreen) {
+        scaling_active = 0;
+        gui_saved_grab = gui_grab;
+        sdl_grab_start();
+    } else {
+        if (!gui_saved_grab)
+            sdl_grab_end();
+    }
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void sdl_refresh(DisplayState *ds)
+{
+    SDL_Event ev1, *ev = &ev1;
+    int mod_state;
+    int buttonstate = SDL_GetMouseState(NULL, NULL);
+
+    if (last_vm_running != vm_running) {
+        last_vm_running = vm_running;
+        sdl_update_caption();
+    }
+
+    vga_hw_update();
+    SDL_EnableUNICODE(!is_graphic_console());
+
+    while (SDL_PollEvent(ev)) {
+        switch (ev->type) {
+        case SDL_VIDEOEXPOSE:
+            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
+            break;
+        case SDL_KEYDOWN:
+        case SDL_KEYUP:
+            if (ev->type == SDL_KEYDOWN) {
+                if (alt_grab) {
+                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+                                (gui_grab_code | KMOD_LSHIFT);
+                } else if (ctrl_grab) {
+                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
+                } else {
+                    mod_state = (SDL_GetModState() & gui_grab_code) ==
+                                gui_grab_code;
+                }
+                gui_key_modifier_pressed = mod_state;
+                if (gui_key_modifier_pressed) {
+                    int keycode;
+                    keycode = sdl_keyevent_to_keycode(&ev->key);
+                    switch(keycode) {
+                    case 0x21: /* 'f' key on US keyboard */
+                        toggle_full_screen(ds);
+                        gui_keysym = 1;
+                        break;
+                    case 0x16: /* 'u' key on US keyboard */
+                        scaling_active = 0;
+                        sdl_resize(ds);
+                        vga_hw_invalidate();
+                        vga_hw_update();
+                        break;
+                    case 0x02 ... 0x0a: /* '1' to '9' keys */
+                        /* Reset the modifiers sent to the current console */
+                        reset_keys();
+                        console_select(keycode - 0x02);
+                        if (!is_graphic_console()) {
+                            /* display grab if going to a text console */
+                            if (gui_grab)
+                                sdl_grab_end();
+                        }
+                        gui_keysym = 1;
+                        break;
+                    default:
+                        break;
+                    }
+                } else if (!is_graphic_console()) {
+                    int keysym;
+                    keysym = 0;
+                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+                        switch(ev->key.keysym.sym) {
+                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
+                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
+                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
+                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
+                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
+                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
+                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
+                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
+                        default: break;
+                        }
+                    } else {
+                        switch(ev->key.keysym.sym) {
+                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
+                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
+                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
+                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
+                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
+                        case SDLK_END: keysym = QEMU_KEY_END; break;
+                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
+                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
+                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
+                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
+                        default: break;
+                        }
+                    }
+                    if (keysym) {
+                        kbd_put_keysym(keysym);
+                    } else if (ev->key.keysym.unicode != 0) {
+                        kbd_put_keysym(ev->key.keysym.unicode);
+                    }
+                }
+            } else if (ev->type == SDL_KEYUP) {
+                if (!alt_grab) {
+                    mod_state = (ev->key.keysym.mod & gui_grab_code);
+                } else {
+                    mod_state = (ev->key.keysym.mod &
+                                 (gui_grab_code | KMOD_LSHIFT));
+                }
+                if (!mod_state) {
+                    if (gui_key_modifier_pressed) {
+                        gui_key_modifier_pressed = 0;
+                        if (gui_keysym == 0) {
+                            /* exit/enter grab if pressing Ctrl-Alt */
+                            if (!gui_grab) {
+                                /* if the application is not active,
+                                   do not try to enter grab state. It
+                                   prevents
+                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
+                                   from blocking all the application
+                                   (SDL bug). */
+                                if (SDL_GetAppState() & SDL_APPACTIVE)
+                                    sdl_grab_start();
+                            } else {
+                                sdl_grab_end();
+                            }
+                            /* SDL does not send back all the
+                               modifiers key, so we must correct it */
+                            reset_keys();
+                            break;
+                        }
+                        gui_keysym = 0;
+                    }
+                }
+            }
+            if (is_graphic_console() && !gui_keysym)
+                sdl_process_key(&ev->key);
+            break;
+        case SDL_QUIT:
+            if (!no_quit)
+                qemu_system_shutdown_request();
+            break;
+        case SDL_MOUSEMOTION:
+            if (gui_grab || kbd_mouse_is_absolute() ||
+                absolute_enabled) {
+                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
+                       ev->motion.x, ev->motion.y, ev->motion.state);
+            }
+            break;
+        case SDL_MOUSEBUTTONDOWN:
+        case SDL_MOUSEBUTTONUP:
+            {
+                SDL_MouseButtonEvent *bev = &ev->button;
+                if (!gui_grab && !kbd_mouse_is_absolute()) {
+                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
+                        (bev->button == SDL_BUTTON_LEFT)) {
+                        /* start grabbing all events */
+                        sdl_grab_start();
+                    }
+                } else {
+                    int dz;
+                    dz = 0;
+                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
+                        buttonstate |= SDL_BUTTON(bev->button);
+                    } else {
+                        buttonstate &= ~SDL_BUTTON(bev->button);
+                    }
+#ifdef SDL_BUTTON_WHEELUP
+                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
+                        dz = -1;
+                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
+                        dz = 1;
+                    }
+#endif
+                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
+                }
+            }
+            break;
+        case SDL_ACTIVEEVENT:
+            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
+                !ev->active.gain && !gui_fullscreen_initial_grab) {
+                sdl_grab_end();
+            }
+            if (ev->active.state & SDL_APPACTIVE) {
+                if (ev->active.gain) {
+                    /* Back to default interval */
+                    dcl->gui_timer_interval = 0;
+                    dcl->idle = 0;
+                } else {
+                    /* Sleeping interval */
+                    dcl->gui_timer_interval = 500;
+                    dcl->idle = 1;
+                }
+            }
+            break;
+       case SDL_VIDEORESIZE:
+        {
+           SDL_ResizeEvent *rev = &ev->resize;
+            int bpp = real_screen->format->BitsPerPixel;
+            if (bpp != 16 && bpp != 32)
+                bpp = 32;
+            do_sdl_resize(rev->w, rev->h, bpp);
+            scaling_active = 1;
+            if (!is_buffer_shared(ds->surface)) {
+                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
+                dpy_resize(ds);
+            }
+            vga_hw_invalidate();
+            vga_hw_update();
+            break;
+        }
+        default:
+            break;
+        }
+    }
+}
+
+static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
+{
+    SDL_Rect dst = { x, y, w, h };
+    SDL_FillRect(real_screen, &dst, c);
+}
+
+static void sdl_mouse_warp(int x, int y, int on)
+{
+    if (on) {
+        if (!guest_cursor)
+            sdl_show_cursor();
+        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+            SDL_SetCursor(guest_sprite);
+            if (!kbd_mouse_is_absolute() && !absolute_enabled)
+                SDL_WarpMouse(x, y);
+        }
+    } else if (gui_grab)
+        sdl_hide_cursor();
+    guest_cursor = on;
+    guest_x = x, guest_y = y;
+}
+
+static void sdl_mouse_define(QEMUCursor *c)
+{
+    uint8_t *image, *mask;
+    int bpl;
+
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
+
+    bpl = cursor_get_mono_bpl(c);
+    image = qemu_mallocz(bpl * c->height);
+    mask  = qemu_mallocz(bpl * c->height);
+    cursor_get_mono_image(c, 0x000000, image);
+    cursor_get_mono_mask(c, 0, mask);
+    guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
+                                    c->hot_x, c->hot_y);
+    qemu_free(image);
+    qemu_free(mask);
+
+    if (guest_cursor &&
+            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+        SDL_SetCursor(guest_sprite);
+}
+
+static void sdl_cleanup(void)
+{
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
+    SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
+{
+    int flags;
+    uint8_t data = 0;
+    DisplayAllocator *da;
+    const SDL_VideoInfo *vi;
+
+#if defined(__APPLE__)
+    /* always use generic keymaps */
+    if (!keyboard_layout)
+        keyboard_layout = "en-us";
+#endif
+    if(keyboard_layout) {
+        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+        if (!kbd_layout)
+            exit(1);
+    }
+
+    if (no_frame)
+        gui_noframe = 1;
+
+    if (!full_screen) {
+        setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
+    }
+
+    flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
+    if (SDL_Init (flags)) {
+        fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
+                SDL_GetError());
+        exit(1);
+    }
+    vi = SDL_GetVideoInfo();
+    host_format = *(vi->vfmt);
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = sdl_update;
+    dcl->dpy_resize = sdl_resize;
+    dcl->dpy_refresh = sdl_refresh;
+    dcl->dpy_setdata = sdl_setdata;
+    dcl->dpy_fill = sdl_fill;
+    ds->mouse_set = sdl_mouse_warp;
+    ds->cursor_define = sdl_mouse_define;
+    register_displaychangelistener(ds, dcl);
+
+    da = qemu_mallocz(sizeof(DisplayAllocator));
+    da->create_displaysurface = sdl_create_displaysurface;
+    da->resize_displaysurface = sdl_resize_displaysurface;
+    da->free_displaysurface = sdl_free_displaysurface;
+    if (register_displayallocator(ds, da) == da) {
+        dpy_resize(ds);
+    }
+
+    mouse_mode_notifier.notify = sdl_mouse_mode_change;
+    qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
+
+    sdl_update_caption();
+    SDL_EnableKeyRepeat(250, 50);
+    gui_grab = 0;
+
+    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
+    sdl_cursor_normal = SDL_GetCursor();
+
+    atexit(sdl_cleanup);
+    if (full_screen) {
+        gui_fullscreen = 1;
+        gui_fullscreen_initial_grab = 1;
+        sdl_grab_start();
+    }
+}
diff --git a/ui/sdl_keysym.h b/ui/sdl_keysym.h
new file mode 100644 (file)
index 0000000..ee90480
--- /dev/null
@@ -0,0 +1,277 @@
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                0x020},
+    { "exclam",               0x021},
+    { "quotedbl",             0x022},
+    { "numbersign",           0x023},
+    { "dollar",               0x024},
+    { "percent",              0x025},
+    { "ampersand",            0x026},
+    { "apostrophe",           0x027},
+    { "parenleft",            0x028},
+    { "parenright",           0x029},
+    { "asterisk",             0x02a},
+    { "plus",                 0x02b},
+    { "comma",                0x02c},
+    { "minus",                0x02d},
+    { "period",               0x02e},
+    { "slash",                0x02f},
+    { "0",                    0x030},
+    { "1",                    0x031},
+    { "2",                    0x032},
+    { "3",                    0x033},
+    { "4",                    0x034},
+    { "5",                    0x035},
+    { "6",                    0x036},
+    { "7",                    0x037},
+    { "8",                    0x038},
+    { "9",                    0x039},
+    { "colon",                0x03a},
+    { "semicolon",            0x03b},
+    { "less",                 0x03c},
+    { "equal",                0x03d},
+    { "greater",              0x03e},
+    { "question",             0x03f},
+    { "at",                   0x040},
+    { "A",                    0x041},
+    { "B",                    0x042},
+    { "C",                    0x043},
+    { "D",                    0x044},
+    { "E",                    0x045},
+    { "F",                    0x046},
+    { "G",                    0x047},
+    { "H",                    0x048},
+    { "I",                    0x049},
+    { "J",                    0x04a},
+    { "K",                    0x04b},
+    { "L",                    0x04c},
+    { "M",                    0x04d},
+    { "N",                    0x04e},
+    { "O",                    0x04f},
+    { "P",                    0x050},
+    { "Q",                    0x051},
+    { "R",                    0x052},
+    { "S",                    0x053},
+    { "T",                    0x054},
+    { "U",                    0x055},
+    { "V",                    0x056},
+    { "W",                    0x057},
+    { "X",                    0x058},
+    { "Y",                    0x059},
+    { "Z",                    0x05a},
+    { "bracketleft",          0x05b},
+    { "backslash",            0x05c},
+    { "bracketright",         0x05d},
+    { "asciicircum",          0x05e},
+    { "underscore",           0x05f},
+    { "grave",                0x060},
+    { "a",                    0x061},
+    { "b",                    0x062},
+    { "c",                    0x063},
+    { "d",                    0x064},
+    { "e",                    0x065},
+    { "f",                    0x066},
+    { "g",                    0x067},
+    { "h",                    0x068},
+    { "i",                    0x069},
+    { "j",                    0x06a},
+    { "k",                    0x06b},
+    { "l",                    0x06c},
+    { "m",                    0x06d},
+    { "n",                    0x06e},
+    { "o",                    0x06f},
+    { "p",                    0x070},
+    { "q",                    0x071},
+    { "r",                    0x072},
+    { "s",                    0x073},
+    { "t",                    0x074},
+    { "u",                    0x075},
+    { "v",                    0x076},
+    { "w",                    0x077},
+    { "x",                    0x078},
+    { "y",                    0x079},
+    { "z",                    0x07a},
+    { "braceleft",            0x07b},
+    { "bar",                  0x07c},
+    { "braceright",           0x07d},
+    { "asciitilde",           0x07e},
+
+/* latin 1 extensions */
+{ "nobreakspace",         0x0a0},
+{ "exclamdown",           0x0a1},
+{ "cent",                0x0a2},
+{ "sterling",             0x0a3},
+{ "currency",             0x0a4},
+{ "yen",                  0x0a5},
+{ "brokenbar",            0x0a6},
+{ "section",              0x0a7},
+{ "diaeresis",            0x0a8},
+{ "copyright",            0x0a9},
+{ "ordfeminine",          0x0aa},
+{ "guillemotleft",        0x0ab},
+{ "notsign",              0x0ac},
+{ "hyphen",               0x0ad},
+{ "registered",           0x0ae},
+{ "macron",               0x0af},
+{ "degree",               0x0b0},
+{ "plusminus",            0x0b1},
+{ "twosuperior",          0x0b2},
+{ "threesuperior",        0x0b3},
+{ "acute",                0x0b4},
+{ "mu",                   0x0b5},
+{ "paragraph",            0x0b6},
+{ "periodcentered",       0x0b7},
+{ "cedilla",              0x0b8},
+{ "onesuperior",          0x0b9},
+{ "masculine",            0x0ba},
+{ "guillemotright",       0x0bb},
+{ "onequarter",           0x0bc},
+{ "onehalf",              0x0bd},
+{ "threequarters",        0x0be},
+{ "questiondown",         0x0bf},
+{ "Agrave",               0x0c0},
+{ "Aacute",               0x0c1},
+{ "Acircumflex",          0x0c2},
+{ "Atilde",               0x0c3},
+{ "Adiaeresis",           0x0c4},
+{ "Aring",                0x0c5},
+{ "AE",                   0x0c6},
+{ "Ccedilla",             0x0c7},
+{ "Egrave",               0x0c8},
+{ "Eacute",               0x0c9},
+{ "Ecircumflex",          0x0ca},
+{ "Ediaeresis",           0x0cb},
+{ "Igrave",               0x0cc},
+{ "Iacute",               0x0cd},
+{ "Icircumflex",          0x0ce},
+{ "Idiaeresis",           0x0cf},
+{ "ETH",                  0x0d0},
+{ "Eth",                  0x0d0},
+{ "Ntilde",               0x0d1},
+{ "Ograve",               0x0d2},
+{ "Oacute",               0x0d3},
+{ "Ocircumflex",          0x0d4},
+{ "Otilde",               0x0d5},
+{ "Odiaeresis",           0x0d6},
+{ "multiply",             0x0d7},
+{ "Ooblique",             0x0d8},
+{ "Oslash",               0x0d8},
+{ "Ugrave",               0x0d9},
+{ "Uacute",               0x0da},
+{ "Ucircumflex",          0x0db},
+{ "Udiaeresis",           0x0dc},
+{ "Yacute",               0x0dd},
+{ "THORN",                0x0de},
+{ "Thorn",                0x0de},
+{ "ssharp",               0x0df},
+{ "agrave",               0x0e0},
+{ "aacute",               0x0e1},
+{ "acircumflex",          0x0e2},
+{ "atilde",               0x0e3},
+{ "adiaeresis",           0x0e4},
+{ "aring",                0x0e5},
+{ "ae",                   0x0e6},
+{ "ccedilla",             0x0e7},
+{ "egrave",               0x0e8},
+{ "eacute",               0x0e9},
+{ "ecircumflex",          0x0ea},
+{ "ediaeresis",           0x0eb},
+{ "igrave",               0x0ec},
+{ "iacute",               0x0ed},
+{ "icircumflex",          0x0ee},
+{ "idiaeresis",           0x0ef},
+{ "eth",                  0x0f0},
+{ "ntilde",               0x0f1},
+{ "ograve",               0x0f2},
+{ "oacute",               0x0f3},
+{ "ocircumflex",          0x0f4},
+{ "otilde",               0x0f5},
+{ "odiaeresis",           0x0f6},
+{ "division",             0x0f7},
+{ "oslash",               0x0f8},
+{ "ooblique",             0x0f8},
+{ "ugrave",               0x0f9},
+{ "uacute",               0x0fa},
+{ "ucircumflex",          0x0fb},
+{ "udiaeresis",           0x0fc},
+{ "yacute",               0x0fd},
+{ "thorn",                0x0fe},
+{ "ydiaeresis",           0x0ff},
+{"EuroSign", SDLK_EURO},
+
+    /* modifiers */
+{"Control_L", SDLK_LCTRL},
+{"Control_R", SDLK_RCTRL},
+{"Alt_L", SDLK_LALT},
+{"Alt_R", SDLK_RALT},
+{"Caps_Lock", SDLK_CAPSLOCK},
+{"Meta_L", SDLK_LMETA},
+{"Meta_R", SDLK_RMETA},
+{"Shift_L", SDLK_LSHIFT},
+{"Shift_R", SDLK_RSHIFT},
+{"Super_L", SDLK_LSUPER},
+{"Super_R", SDLK_RSUPER},
+
+    /* special keys */
+{"BackSpace", SDLK_BACKSPACE},
+{"Tab", SDLK_TAB},
+{"Return", SDLK_RETURN},
+{"Right", SDLK_RIGHT},
+{"Left", SDLK_LEFT},
+{"Up", SDLK_UP},
+{"Down", SDLK_DOWN},
+{"Page_Down", SDLK_PAGEDOWN},
+{"Page_Up", SDLK_PAGEUP},
+{"Insert", SDLK_INSERT},
+{"Delete", SDLK_DELETE},
+{"Home", SDLK_HOME},
+{"End", SDLK_END},
+{"Scroll_Lock", SDLK_SCROLLOCK},
+{"F1", SDLK_F1},
+{"F2", SDLK_F2},
+{"F3", SDLK_F3},
+{"F4", SDLK_F4},
+{"F5", SDLK_F5},
+{"F6", SDLK_F6},
+{"F7", SDLK_F7},
+{"F8", SDLK_F8},
+{"F9", SDLK_F9},
+{"F10", SDLK_F10},
+{"F11", SDLK_F11},
+{"F12", SDLK_F12},
+{"F13", SDLK_F13},
+{"F14", SDLK_F14},
+{"F15", SDLK_F15},
+{"Sys_Req", SDLK_SYSREQ},
+{"KP_0", SDLK_KP0},
+{"KP_1", SDLK_KP1},
+{"KP_2", SDLK_KP2},
+{"KP_3", SDLK_KP3},
+{"KP_4", SDLK_KP4},
+{"KP_5", SDLK_KP5},
+{"KP_6", SDLK_KP6},
+{"KP_7", SDLK_KP7},
+{"KP_8", SDLK_KP8},
+{"KP_9", SDLK_KP9},
+{"KP_Add", SDLK_KP_PLUS},
+{"KP_Decimal", SDLK_KP_PERIOD},
+{"KP_Divide", SDLK_KP_DIVIDE},
+{"KP_Enter", SDLK_KP_ENTER},
+{"KP_Equal", SDLK_KP_EQUALS},
+{"KP_Multiply", SDLK_KP_MULTIPLY},
+{"KP_Subtract", SDLK_KP_MINUS},
+{"help", SDLK_HELP},
+{"Menu", SDLK_MENU},
+{"Power", SDLK_POWER},
+{"Print", SDLK_PRINT},
+{"Mode_switch", SDLK_MODE},
+{"Multi_Key", SDLK_COMPOSE},
+{"Num_Lock", SDLK_NUMLOCK},
+{"Pause", SDLK_PAUSE},
+{"Escape", SDLK_ESCAPE},
+
+{NULL, 0},
+};
diff --git a/ui/sdl_zoom.c b/ui/sdl_zoom.c
new file mode 100644 (file)
index 0000000..a986c7c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sdl_zoom.h"
+#include "osdep.h"
+#include <stdint.h>
+#include <stdio.h>
+
+static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+
+#define BPP 32
+#include  "sdl_zoom_template.h"
+#undef BPP
+#define BPP 16
+#include  "sdl_zoom_template.h"
+#undef BPP
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth,
+                  SDL_Rect *in_rect)
+{
+    SDL_Rect zoom, src_rect;
+    int extra;
+
+    /* Grow the size of the modified rectangle to avoid edge artefacts */
+    src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0;
+    src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0;
+
+    src_rect.w = in_rect->w + 1;
+    if (src_rect.x + src_rect.w > src_sfc->w)
+        src_rect.w = src_sfc->w - src_rect.x;
+
+    src_rect.h = in_rect->h + 1;
+    if (src_rect.y + src_rect.h > src_sfc->h)
+        src_rect.h = src_sfc->h - src_rect.y;
+
+    /* (x,y) : round down */
+    zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w));
+    zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h));
+
+    /* (w,h) : round up */
+    zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) /
+                     (double)(src_sfc->w));
+
+    zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) /
+                     (double)(src_sfc->h));
+
+    /* Account for any (x,y) rounding by adding one-source-pixel's worth
+     * of destination pixels and then edge checking.
+     */
+
+    extra = ((dst_sfc->w-1) / src_sfc->w) + 1;
+
+    if ((zoom.x + zoom.w) < (dst_sfc->w - extra))
+        zoom.w += extra;
+    else
+        zoom.w = dst_sfc->w - zoom.x;
+
+    extra = ((dst_sfc->h-1) / src_sfc->h) + 1;
+
+    if ((zoom.y + zoom.h) < (dst_sfc->h - extra))
+        zoom.h += extra;
+    else
+        zoom.h = dst_sfc->h - zoom.y;
+
+    /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the
+     * destination surface that needs to be updated.
+     */
+    if (src_sfc->format->BitsPerPixel == 32)
+        sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom);
+    else if (src_sfc->format->BitsPerPixel == 16)
+        sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom);
+    else {
+        fprintf(stderr, "pixel format not supported\n");
+        return -1;
+    }
+
+    /* Return the rectangle of the update to the caller */
+    *in_rect = zoom;
+
+    return 0;
+}
+
diff --git a/ui/sdl_zoom.h b/ui/sdl_zoom.h
new file mode 100644 (file)
index 0000000..74955bc
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef SDL_zoom_h
+#define SDL_zoom_h
+
+#include <SDL.h>
+
+#define SMOOTHING_OFF          0
+#define SMOOTHING_ON           1
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc,
+                  int smooth, SDL_Rect *src_rect);
+
+#endif /* SDL_zoom_h */
diff --git a/ui/sdl_zoom_template.h b/ui/sdl_zoom_template.h
new file mode 100644 (file)
index 0000000..64bbca8
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * SDL_zoom_template - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#if BPP == 16
+#define SDL_TYPE Uint16
+#elif BPP == 32
+#define SDL_TYPE Uint32
+#else
+#error unsupport depth
+#endif
+
+/*  
+ *  Simple helper functions to make the code looks nicer
+ *
+ *  Assume spf = source SDL_PixelFormat
+ *         dpf = dest SDL_PixelFormat
+ *
+ */
+#define getRed(color)   (((color) & spf->Rmask) >> spf->Rshift)
+#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift)
+#define getBlue(color)  (((color) & spf->Bmask) >> spf->Bshift)
+#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift)
+
+#define setRed(r, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \
+              (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \
+} while (0);
+
+#define setGreen(g, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \
+              (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \
+} while (0);
+
+#define setBlue(b, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \
+              (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \
+} while (0);
+
+#define setAlpha(a, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Amask))) + \
+              (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \
+} while (0);
+
+static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                                   SDL_Rect *dst_rect)
+{
+    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump;
+    SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp;
+    int d_gap;
+    SDL_PixelFormat *spf = src->format;
+    SDL_PixelFormat *dpf = dst->format;
+
+    if (smooth) { 
+        /* For interpolation: assume source dimension is one pixel.
+         * Smaller here to avoid overflow on right and bottom edge.
+         */
+        sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+        sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+    } else {
+        sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+        sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+    }
+
+    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+        return (-1);
+    }
+    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+        free(sax);
+        return (-1);
+    }
+
+    sp = csp = (SDL_TYPE *) src->pixels;
+    dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch +
+                       dst_rect->x * dst->format->BytesPerPixel);
+
+    csx = 0;
+    csax = sax;
+    for (x = 0; x <= dst->w; x++) {
+        *csax = csx;
+        csax++;
+        csx &= 0xffff;
+        csx += sx;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y <= dst->h; y++) {
+        *csay = csy;
+        csay++;
+        csy &= 0xffff;
+        csy += sy;
+    }
+
+    d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel;
+
+    if (smooth) {
+        csay = say;
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0; y < dst_rect->h ; y++) {
+            /* Setup colour source pointers */
+            c00 = csp + sstep_jump;
+            c01 = c00 + 1;
+            c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump;
+            c11 = c10 + 1;
+            csax = sax + dst_rect->x; 
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Interpolate colours */
+                ex = (*csax & 0xffff);
+                ey = (*csay & 0xffff);
+                t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) +
+                     getRed(*c00)) & (dpf->Rmask >> dpf->Rshift);
+                t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) +
+                     getRed(*c10)) & (dpf->Rmask >> dpf->Rshift);
+                setRed((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) +
+                     getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift);
+                t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) +
+                     getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift);
+                setGreen((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) +
+                     getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift);
+                t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) +
+                     getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift);
+                setBlue((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) +
+                     getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift);
+                t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) +
+                     getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift);
+                setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); 
+
+                /* Advance source pointers */
+                csax++; 
+                sstep = (*csax >> 16);
+                c00 += sstep;
+                c01 += sstep;
+                c10 += sstep;
+                c11 += sstep;
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointer */
+            csay++;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+            /* Advance destination pointers */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+
+
+    } else {
+        csay = say;
+
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0 ; y < dst_rect->h ; y++) {
+            sp = csp + sstep_jump;
+            csax = sax + dst_rect->x;
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Draw */
+                *dp = *sp;
+
+                /* Advance source pointers */
+                csax++;
+                sstep = (*csax >> 16);
+                sp += sstep;
+
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointers */
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+
+            /* Advance destination pointer */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+    }
+
+    free(sax);
+    free(say);
+    return (0);
+}
+
+#undef SDL_TYPE
+
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
new file mode 100644 (file)
index 0000000..a51ddc8
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+
+/* Max amount of data we send/recv for SASL steps to prevent DOS */
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+
+void vnc_sasl_client_cleanup(VncState *vs)
+{
+    if (vs->sasl.conn) {
+        vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0;
+        vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
+        vs->sasl.encoded = NULL;
+        free(vs->sasl.username);
+        free(vs->sasl.mechlist);
+        vs->sasl.username = vs->sasl.mechlist = NULL;
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+    }
+}
+
+
+long vnc_client_write_sasl(VncState *vs)
+{
+    long ret;
+
+    VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
+              "Encoded: %p size %d offset %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
+
+    if (!vs->sasl.encoded) {
+        int err;
+        err = sasl_encode(vs->sasl.conn,
+                          (char *)vs->output.buffer,
+                          vs->output.offset,
+                          (const char **)&vs->sasl.encoded,
+                          &vs->sasl.encodedLength);
+        if (err != SASL_OK)
+            return vnc_client_io_error(vs, -1, EIO);
+
+        vs->sasl.encodedOffset = 0;
+    }
+
+    ret = vnc_client_write_buf(vs,
+                               vs->sasl.encoded + vs->sasl.encodedOffset,
+                               vs->sasl.encodedLength - vs->sasl.encodedOffset);
+    if (!ret)
+        return 0;
+
+    vs->sasl.encodedOffset += ret;
+    if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
+        vs->output.offset = 0;
+        vs->sasl.encoded = NULL;
+        vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
+    }
+
+    /* Can't merge this block with one above, because
+     * someone might have written more unencrypted
+     * data in vs->output while we were processing
+     * SASL encoded output
+     */
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+long vnc_client_read_sasl(VncState *vs)
+{
+    long ret;
+    uint8_t encoded[4096];
+    const char *decoded;
+    unsigned int decodedLen;
+    int err;
+
+    ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
+    if (!ret)
+        return 0;
+
+    err = sasl_decode(vs->sasl.conn,
+                      (char *)encoded, ret,
+                      &decoded, &decodedLen);
+
+    if (err != SASL_OK)
+        return vnc_client_io_error(vs, -1, -EIO);
+    VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
+              encoded, ret, decoded, decodedLen);
+    buffer_reserve(&vs->input, decodedLen);
+    buffer_append(&vs->input, decoded, decodedLen);
+    return decodedLen;
+}
+
+
+static int vnc_auth_sasl_check_access(VncState *vs)
+{
+    const void *val;
+    int err;
+    int allow;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        return -1;
+    }
+    if (val == NULL) {
+        VNC_DEBUG("no client username was found, denying access\n");
+        return -1;
+    }
+    VNC_DEBUG("SASL client username %s\n", (const char *)val);
+
+    vs->sasl.username = qemu_strdup((const char*)val);
+
+    if (vs->vd->sasl.acl == NULL) {
+        VNC_DEBUG("no ACL activated, allowing access\n");
+        return 0;
+    }
+
+    allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
+
+    VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
+              allow ? "allowed" : "denied");
+    return allow ? 0 : -1;
+}
+
+static int vnc_auth_sasl_check_ssf(VncState *vs)
+{
+    const void *val;
+    int err, ssf;
+
+    if (!vs->sasl.wantSSF)
+        return 1;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
+    if (err != SASL_OK)
+        return 0;
+
+    ssf = *(const int *)val;
+    VNC_DEBUG("negotiated an SSF of %d\n", ssf);
+    if (ssf < 56)
+        return 0; /* 56 is good for Kerberos */
+
+    /* Only setup for read initially, because we're about to send an RPC
+     * reply which must be in plain text. When the next incoming RPC
+     * arrives, we'll switch on writes too
+     *
+     * cf qemudClientReadSASL  in qemud.c
+     */
+    vs->sasl.runSSF = 1;
+
+    /* We have a SSF that's good enough */
+    return 1;
+}
+
+/*
+ * Step Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
+
+static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
+              clientdata, datalen);
+    err = sasl_server_step(vs->sasl.conn,
+                           clientdata,
+                           datalen,
+                           &serverout,
+                           &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl step failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl step reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        /*
+         * Delay writing in SSF encoded mode until pending output
+         * buffer is written
+         */
+        if (vs->sasl.runSSF)
+            vs->sasl.waitWriteSSF = vs->output.offset;
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t steplen = read_u32(data, 0);
+    VNC_DEBUG("Got client step len %d\n", steplen);
+    if (steplen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", steplen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (steplen == 0)
+        return protocol_client_auth_sasl_step(vs, NULL, 0);
+    else
+        vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
+    return 0;
+}
+
+/*
+ * Start Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
+              vs->sasl.mechlist, clientdata, datalen);
+    err = sasl_server_start(vs->sasl.conn,
+                            vs->sasl.mechlist,
+                            clientdata,
+                            datalen,
+                            &serverout,
+                            &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl start failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl start reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t startlen = read_u32(data, 0);
+    VNC_DEBUG("Got client start len %d\n", startlen);
+    if (startlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", startlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (startlen == 0)
+        return protocol_client_auth_sasl_start(vs, NULL, 0);
+
+    vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
+    return 0;
+}
+
+static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
+{
+    char *mechname = malloc(len + 1);
+    if (!mechname) {
+        VNC_DEBUG("Out of memory reading mechname\n");
+        vnc_client_error(vs);
+    }
+    strncpy(mechname, (char*)data, len);
+    mechname[len] = '\0';
+    VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
+              mechname, vs->sasl.mechlist);
+
+    if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
+        if (vs->sasl.mechlist[len] != '\0' &&
+            vs->sasl.mechlist[len] != ',') {
+            VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
+            vnc_client_error(vs);
+            return -1;
+        }
+    } else {
+        char *offset = strstr(vs->sasl.mechlist, mechname);
+        VNC_DEBUG("Two %p\n", offset);
+        if (!offset) {
+            vnc_client_error(vs);
+            return -1;
+        }
+        VNC_DEBUG("Two '%s'\n", offset);
+        if (offset[-1] != ',' ||
+            (offset[len] != '\0'&&
+             offset[len] != ',')) {
+            vnc_client_error(vs);
+            return -1;
+        }
+    }
+
+    free(vs->sasl.mechlist);
+    vs->sasl.mechlist = mechname;
+
+    VNC_DEBUG("Validated mechname '%s'\n", mechname);
+    vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
+    return 0;
+}
+
+static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t mechlen = read_u32(data, 0);
+    VNC_DEBUG("Got client mechname len %d\n", mechlen);
+    if (mechlen > 100) {
+        VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    if (mechlen < 1) {
+        VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
+    return 0;
+}
+
+#define USES_X509_AUTH(vs)                              \
+    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+
+
+void start_auth_sasl(VncState *vs)
+{
+    const char *mechlist = NULL;
+    sasl_security_properties_t secprops;
+    int err;
+    char *localAddr, *remoteAddr;
+    int mechlistlen;
+
+    VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
+
+    /* Get local & remote client addresses in form  IPADDR;PORT */
+    if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
+        goto authabort;
+
+    if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
+        free(localAddr);
+        goto authabort;
+    }
+
+    err = sasl_server_new("vnc",
+                          NULL, /* FQDN - just delegates to gethostname */
+                          NULL, /* User realm */
+                          localAddr,
+                          remoteAddr,
+                          NULL, /* Callbacks, not needed */
+                          SASL_SUCCESS_DATA,
+                          &vs->sasl.conn);
+    free(localAddr);
+    free(remoteAddr);
+    localAddr = remoteAddr = NULL;
+
+    if (err != SASL_OK) {
+        VNC_DEBUG("sasl context setup failed %d (%s)",
+                  err, sasl_errstring(err, NULL, NULL));
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+#ifdef CONFIG_VNC_TLS
+    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
+    if (vs->vd->auth == VNC_AUTH_VENCRYPT &&
+        vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
+        gnutls_cipher_algorithm_t cipher;
+        sasl_ssf_t ssf;
+
+        cipher = gnutls_cipher_get(vs->tls.session);
+        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
+            VNC_DEBUG("%s", "cannot TLS get cipher size\n");
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+        ssf *= 8; /* tls key size is bytes, sasl wants bits */
+
+        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
+        if (err != SASL_OK) {
+            VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
+                      err, sasl_errstring(err, NULL, NULL));
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        vs->sasl.wantSSF = 1;
+
+    memset (&secprops, 0, sizeof secprops);
+    /* Inform SASL that we've got an external SSF layer from TLS */
+    if (strncmp(vs->vd->display, "unix:", 5) == 0
+#ifdef CONFIG_VNC_TLS
+        /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
+           is not sufficiently strong */
+        || (vs->vd->auth == VNC_AUTH_VENCRYPT &&
+            vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+#endif /* CONFIG_VNC_TLS */
+        ) {
+        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
+        secprops.min_ssf = 0;
+        secprops.max_ssf = 0;
+        secprops.maxbufsize = 8192;
+        secprops.security_flags = 0;
+    } else {
+        /* Plain TCP, better get an SSF layer */
+        secprops.min_ssf = 56; /* Good enough to require kerberos */
+        secprops.max_ssf = 100000; /* Arbitrary big number */
+        secprops.maxbufsize = 8192;
+        /* Forbid any anonymous or trivially crackable auth */
+        secprops.security_flags =
+            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
+    }
+
+    err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot set SASL security props %d (%s)\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    err = sasl_listmech(vs->sasl.conn,
+                        NULL, /* Don't need to set user */
+                        "", /* Prefix */
+                        ",", /* Separator */
+                        "", /* Suffix */
+                        &mechlist,
+                        NULL,
+                        NULL);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
+
+    if (!(vs->sasl.mechlist = strdup(mechlist))) {
+        VNC_DEBUG("Out of memory");
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    mechlistlen = strlen(mechlist);
+    vnc_write_u32(vs, mechlistlen);
+    vnc_write(vs, mechlist, mechlistlen);
+    vnc_flush(vs);
+
+    VNC_DEBUG("Wait for client mechname length\n");
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
+
+    return;
+
+ authabort:
+    vnc_client_error(vs);
+    return;
+}
+
+
diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h
new file mode 100644 (file)
index 0000000..fd9b18a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef __QEMU_VNC_AUTH_SASL_H__
+#define __QEMU_VNC_AUTH_SASL_H__
+
+
+#include <sasl/sasl.h>
+
+typedef struct VncStateSASL VncStateSASL;
+typedef struct VncDisplaySASL VncDisplaySASL;
+
+#include "acl.h"
+
+struct VncStateSASL {
+    sasl_conn_t *conn;
+    /* If we want to negotiate an SSF layer with client */
+    int wantSSF :1;
+    /* If we are now running the SSF layer */
+    int runSSF :1;
+    /*
+     * If this is non-zero, then wait for that many bytes
+     * to be written plain, before switching to SSF encoding
+     * This allows the VNC auth result to finish being
+     * written in plain.
+     */
+    unsigned int waitWriteSSF;
+
+    /*
+     * Buffering encoded data to allow more clear data
+     * to be stuffed onto the output buffer
+     */
+    const uint8_t *encoded;
+    unsigned int encodedLength;
+    unsigned int encodedOffset;
+    char *username;
+    char *mechlist;
+};
+
+struct VncDisplaySASL {
+    qemu_acl *acl;
+};
+
+void vnc_sasl_client_cleanup(VncState *vs);
+
+long vnc_client_read_sasl(VncState *vs);
+long vnc_client_write_sasl(VncState *vs);
+
+void start_auth_sasl(VncState *vs);
+
+#endif /* __QEMU_VNC_AUTH_SASL_H__ */
+
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
new file mode 100644 (file)
index 0000000..07c1691
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * QEMU VNC display driver: VeNCrypt authentication setup
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+
+
+static void start_auth_vencrypt_subauth(VncState *vs)
+{
+    switch (vs->vd->subauth) {
+    case VNC_AUTH_VENCRYPT_TLSNONE:
+    case VNC_AUTH_VENCRYPT_X509NONE:
+       VNC_DEBUG("Accept TLS auth none\n");
+       vnc_write_u32(vs, 0); /* Accept auth completion */
+       start_client_init(vs);
+       break;
+
+    case VNC_AUTH_VENCRYPT_TLSVNC:
+    case VNC_AUTH_VENCRYPT_X509VNC:
+       VNC_DEBUG("Start TLS auth VNC\n");
+       start_auth_vnc(vs);
+       break;
+
+#ifdef CONFIG_VNC_SASL
+    case VNC_AUTH_VENCRYPT_TLSSASL:
+    case VNC_AUTH_VENCRYPT_X509SASL:
+      VNC_DEBUG("Start TLS auth SASL\n");
+      return start_auth_sasl(vs);
+#endif /* CONFIG_VNC_SASL */
+
+    default: /* Should not be possible, but just in case */
+       VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth);
+       vnc_write_u8(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Unsupported authentication type";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    }
+}
+
+static void vnc_tls_handshake_io(void *opaque);
+
+static int vnc_start_vencrypt_handshake(struct VncState *vs) {
+    int ret;
+
+    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
+       if (!gnutls_error_is_fatal(ret)) {
+           VNC_DEBUG("Handshake interrupted (blocking)\n");
+           if (!gnutls_record_get_direction(vs->tls.session))
+               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
+           else
+               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
+           return 0;
+       }
+       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
+       vnc_client_error(vs);
+       return -1;
+    }
+
+    if (vs->vd->tls.x509verify) {
+        if (vnc_tls_validate_certificate(vs) < 0) {
+            VNC_DEBUG("Client verification failed\n");
+            vnc_client_error(vs);
+            return -1;
+        } else {
+            VNC_DEBUG("Client verification passed\n");
+        }
+    }
+
+    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
+    vs->tls.wiremode = VNC_WIREMODE_TLS;
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+
+    start_auth_vencrypt_subauth(vs);
+
+    return 0;
+}
+
+static void vnc_tls_handshake_io(void *opaque) {
+    struct VncState *vs = (struct VncState *)opaque;
+
+    VNC_DEBUG("Handshake IO continue\n");
+    vnc_start_vencrypt_handshake(vs);
+}
+
+
+
+#define NEED_X509_AUTH(vs)                              \
+    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+
+
+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
+{
+    int auth = read_u32(data, 0);
+
+    if (auth != vs->vd->subauth) {
+        VNC_DEBUG("Rejecting auth %d\n", auth);
+        vnc_write_u8(vs, 0); /* Reject auth */
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
+        vnc_write_u8(vs, 1); /* Accept auth */
+        vnc_flush(vs);
+
+        if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
+            VNC_DEBUG("Failed to setup TLS\n");
+            return 0;
+        }
+
+        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
+        if (vnc_start_vencrypt_handshake(vs) < 0) {
+            VNC_DEBUG("Failed to start TLS handshake\n");
+            return 0;
+        }
+    }
+    return 0;
+}
+
+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
+{
+    if (data[0] != 0 ||
+        data[1] != 2) {
+        VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
+        vnc_write_u8(vs, 1); /* Reject version */
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
+        vnc_write_u8(vs, 0); /* Accept version */
+        vnc_write_u8(vs, 1); /* Number of sub-auths */
+        vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
+        vnc_flush(vs);
+        vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
+    }
+    return 0;
+}
+
+
+void start_auth_vencrypt(VncState *vs)
+{
+    /* Send VeNCrypt version 0.2 */
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 2);
+
+    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
+}
+
diff --git a/ui/vnc-auth-vencrypt.h b/ui/vnc-auth-vencrypt.h
new file mode 100644 (file)
index 0000000..9f674c5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__
+#define __QEMU_VNC_AUTH_VENCRYPT_H__
+
+void start_auth_vencrypt(VncState *vs);
+
+#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
diff --git a/ui/vnc-encoding-hextile.c b/ui/vnc-encoding-hextile.c
new file mode 100644 (file)
index 0000000..728f25e
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * QEMU VNC display driver: hextile encoding
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+
+static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
+{
+    ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
+    ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
+}
+
+#define BPP 8
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 16
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+
+#define GENERIC
+#define BPP 8
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 16
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
+                                        int y, int w, int h)
+{
+    int i, j;
+    int has_fg, has_bg;
+    uint8_t *last_fg, *last_bg;
+    VncDisplay *vd = vs->vd;
+
+    last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
+    has_fg = has_bg = 0;
+    for (j = y; j < (y + h); j += 16) {
+        for (i = x; i < (x + w); i += 16) {
+            vs->send_hextile_tile(vs, i, j,
+                                  MIN(16, x + w - i), MIN(16, y + h - j),
+                                  last_bg, last_fg, &has_bg, &has_fg);
+        }
+    }
+    free(last_fg);
+    free(last_bg);
+
+    return 1;
+}
+
+void vnc_hextile_set_pixel_conversion(VncState *vs, int generic)
+{
+    if (!generic) {
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_32;
+                break;
+        }
+    } else {
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_generic_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_generic_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_generic_32;
+                break;
+        }
+    }
+}
diff --git a/ui/vnc-encoding-tight.c b/ui/vnc-encoding-tight.c
new file mode 100644 (file)
index 0000000..c1a292b
--- /dev/null
@@ -0,0 +1,1520 @@
+/*
+ * QEMU VNC display driver: tight encoding
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+
+#ifdef CONFIG_VNC_JPEG
+#include <stdio.h>
+#include <jpeglib.h>
+#endif
+
+#include "bswap.h"
+#include "qdict.h"
+#include "qint.h"
+#include "vnc.h"
+#include "vnc-encoding-tight.h"
+
+/* Compression level stuff. The following array contains various
+   encoder parameters for each of 10 compression levels (0..9).
+   Last three parameters correspond to JPEG quality levels (0..9). */
+
+static const struct {
+    int max_rect_size, max_rect_width;
+    int mono_min_rect_size, gradient_min_rect_size;
+    int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level;
+    int gradient_threshold, gradient_threshold24;
+    int idx_max_colors_divisor;
+    int jpeg_quality, jpeg_threshold, jpeg_threshold24;
+} tight_conf[] = {
+    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
+    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
+    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
+    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
+    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
+    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
+    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
+    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
+    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
+    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
+};
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+static uint
+tight_detect_smooth_image24(VncState *vs, int w, int h)
+{
+    int off;
+    int x, y, d, dx;
+    uint c;
+    uint stats[256];
+    int pixels = 0;
+    int pix, left[3];
+    uint errors;
+    unsigned char *buf = vs->tight.buffer;
+
+    /*
+     * If client is big-endian, color samples begin from the second
+     * byte (offset 1) of a 32-bit pixel value.
+     */
+    off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+
+    memset(stats, 0, sizeof (stats));
+
+    for (y = 0, x = 0; y < h && x < w;) {
+        for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH;
+             d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    stats[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixels++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    /* 95% smooth or more ... */
+    if (stats[0] * 33 / pixels >= 95) {
+        return 0;
+    }
+
+    errors = 0;
+    for (c = 1; c < 8; c++) {
+        errors += stats[c] * (c * c);
+        if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
+            return 0;
+        }
+    }
+    for (; c < 256; c++) {
+        errors += stats[c] * (c * c);
+    }
+    errors /= (pixels * 3 - stats[0]);
+
+    return errors;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                     \
+                                                                        \
+    static uint                                                         \
+    tight_detect_smooth_image##bpp(VncState *vs, int w, int h) {        \
+        bool endian;                                                    \
+        uint##bpp##_t pix;                                              \
+        int max[3], shift[3];                                           \
+        int x, y, d, dx;                                                \
+        uint c;                                                         \
+        uint stats[256];                                                \
+        int pixels = 0;                                                 \
+        int sample, sum, left[3];                                       \
+        uint errors;                                                    \
+        unsigned char *buf = vs->tight.buffer;                          \
+                                                                        \
+        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
+                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
+                                                                        \
+                                                                        \
+        max[0] = vs->clientds.pf.rmax;                                  \
+        max[1] = vs->clientds.pf.gmax;                                  \
+        max[2] = vs->clientds.pf.bmax;                                  \
+        shift[0] = vs->clientds.pf.rshift;                              \
+        shift[1] = vs->clientds.pf.gshift;                              \
+        shift[2] = vs->clientds.pf.bshift;                              \
+                                                                        \
+        memset(stats, 0, sizeof(stats));                                \
+                                                                        \
+        y = 0, x = 0;                                                   \
+        while (y < h && x < w) {                                        \
+            for (d = 0; d < h - y &&                                    \
+                     d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) {  \
+                pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d];              \
+                if (endian) {                                           \
+                    pix = bswap_##bpp(pix);                             \
+                }                                                       \
+                for (c = 0; c < 3; c++) {                               \
+                    left[c] = (int)(pix >> shift[c] & max[c]);          \
+                }                                                       \
+                for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH;       \
+                     dx++) {                                            \
+                    pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx];       \
+                    if (endian) {                                       \
+                        pix = bswap_##bpp(pix);                         \
+                    }                                                   \
+                    sum = 0;                                            \
+                    for (c = 0; c < 3; c++) {                           \
+                        sample = (int)(pix >> shift[c] & max[c]);       \
+                        sum += abs(sample - left[c]);                   \
+                        left[c] = sample;                               \
+                    }                                                   \
+                    if (sum > 255) {                                    \
+                        sum = 255;                                      \
+                    }                                                   \
+                    stats[sum]++;                                       \
+                    pixels++;                                           \
+                }                                                       \
+            }                                                           \
+            if (w > h) {                                                \
+                x += h;                                                 \
+                y = 0;                                                  \
+            } else {                                                    \
+                x = 0;                                                  \
+                y += w;                                                 \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        errors = 0;                                                     \
+        for (c = 1; c < 8; c++) {                                       \
+            errors += stats[c] * (c * c);                               \
+            if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {           \
+                return 0;                                               \
+            }                                                           \
+        }                                                               \
+        for (; c < 256; c++) {                                          \
+            errors += stats[c] * (c * c);                               \
+        }                                                               \
+        errors /= (pixels - stats[0]);                                  \
+                                                                        \
+        return errors;                                                  \
+    }
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+static int
+tight_detect_smooth_image(VncState *vs, int w, int h)
+{
+    uint errors;
+    int compression = vs->tight_compression;
+    int quality = vs->tight_quality;
+
+    if (!vs->vd->lossy) {
+        return 0;
+    }
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+        vs->clientds.pf.bytes_per_pixel == 1 ||
+        w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
+        return 0;
+    }
+
+    if (vs->tight_quality != -1) {
+        if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if (w * h < tight_conf[compression].gradient_min_rect_size) {
+            return 0;
+        }
+    }
+
+    if (vs->clientds.pf.bytes_per_pixel == 4) {
+        if (vs->tight_pixel24) {
+            errors = tight_detect_smooth_image24(vs, w, h);
+            if (vs->tight_quality != -1) {
+                return (errors < tight_conf[quality].jpeg_threshold24);
+            }
+            return (errors < tight_conf[compression].gradient_threshold24);
+        } else {
+            errors = tight_detect_smooth_image32(vs, w, h);
+        }
+    } else {
+        errors = tight_detect_smooth_image16(vs, w, h);
+    }
+    if (quality != -1) {
+        return (errors < tight_conf[quality].jpeg_threshold);
+    }
+    return (errors < tight_conf[compression].gradient_threshold);
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void tight_palette_rgb2buf(uint32_t rgb, int bpp, uint8_t buf[6])
+{
+    memset(buf, 0, 6);
+
+    if (bpp == 32) {
+        buf[0] = ((rgb >> 24) & 0xFF);
+        buf[1] = ((rgb >> 16) & 0xFF);
+        buf[2] = ((rgb >>  8) & 0xFF);
+        buf[3] = ((rgb >>  0) & 0xFF);
+        buf[4] = ((buf[0] & 1) == 0) << 3 | ((buf[1] & 1) == 0) << 2;
+        buf[4]|= ((buf[2] & 1) == 0) << 1 | ((buf[3] & 1) == 0) << 0;
+        buf[0] |= 1;
+        buf[1] |= 1;
+        buf[2] |= 1;
+        buf[3] |= 1;
+    }
+    if (bpp == 16) {
+        buf[0] = ((rgb >> 8) & 0xFF);
+        buf[1] = ((rgb >> 0) & 0xFF);
+        buf[2] = ((buf[0] & 1) == 0) << 1 | ((buf[1] & 1) == 0) << 0;
+        buf[0] |= 1;
+        buf[1] |= 1;
+    }
+}
+
+static uint32_t tight_palette_buf2rgb(int bpp, const uint8_t *buf)
+{
+    uint32_t rgb = 0;
+
+    if (bpp == 32) {
+        rgb |= ((buf[0] & ~1) | !((buf[4] >> 3) & 1)) << 24;
+        rgb |= ((buf[1] & ~1) | !((buf[4] >> 2) & 1)) << 16;
+        rgb |= ((buf[2] & ~1) | !((buf[4] >> 1) & 1)) <<  8;
+        rgb |= ((buf[3] & ~1) | !((buf[4] >> 0) & 1)) <<  0;
+    }
+    if (bpp == 16) {
+        rgb |= ((buf[0] & ~1) | !((buf[2] >> 1) & 1)) << 8;
+        rgb |= ((buf[1] & ~1) | !((buf[2] >> 0) & 1)) << 0;
+    }
+    return rgb;
+}
+
+
+static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
+{
+    uint8_t key[6];
+    int idx = qdict_size(palette);
+    bool present;
+
+    tight_palette_rgb2buf(rgb, bpp, key);
+    present = qdict_haskey(palette, (char *)key);
+    if (idx >= max && !present) {
+        return 0;
+    }
+    if (!present) {
+        qdict_put(palette, (char *)key, qint_from_int(idx));
+    }
+    return qdict_size(palette);
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
+                                                                        \
+    static int                                                          \
+    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
+                            int max, size_t count,                      \
+                            uint32_t *bg, uint32_t *fg,                 \
+                            struct QDict **palette) {                   \
+        uint##bpp##_t *data;                                            \
+        uint##bpp##_t c0, c1, ci;                                       \
+        int i, n0, n1;                                                  \
+                                                                        \
+        data = (uint##bpp##_t *)vs->tight.buffer;                       \
+                                                                        \
+        c0 = data[0];                                                   \
+        i = 1;                                                          \
+        while (i < count && data[i] == c0)                              \
+            i++;                                                        \
+        if (i >= count) {                                               \
+            *bg = *fg = c0;                                             \
+            return 1;                                                   \
+        }                                                               \
+                                                                        \
+        if (max < 2) {                                                  \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        n0 = i;                                                         \
+        c1 = data[i];                                                   \
+        n1 = 0;                                                         \
+        for (i++; i < count; i++) {                                     \
+            ci = data[i];                                               \
+            if (ci == c0) {                                             \
+                n0++;                                                   \
+            } else if (ci == c1) {                                      \
+                n1++;                                                   \
+            } else                                                      \
+                break;                                                  \
+        }                                                               \
+        if (i >= count) {                                               \
+            if (n0 > n1) {                                              \
+                *bg = (uint32_t)c0;                                     \
+                *fg = (uint32_t)c1;                                     \
+            } else {                                                    \
+                *bg = (uint32_t)c1;                                     \
+                *fg = (uint32_t)c0;                                     \
+            }                                                           \
+            return 2;                                                   \
+        }                                                               \
+                                                                        \
+        if (max == 2) {                                                 \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        *palette = qdict_new();                                         \
+        tight_palette_insert(*palette, c0, bpp, max);                   \
+        tight_palette_insert(*palette, c1, bpp, max);                   \
+        tight_palette_insert(*palette, ci, bpp, max);                   \
+                                                                        \
+        for (i++; i < count; i++) {                                     \
+            if (data[i] == ci) {                                        \
+                continue;                                               \
+            } else {                                                    \
+                if (!tight_palette_insert(*palette, (uint32_t)ci,       \
+                                          bpp, max)) {                  \
+                    return 0;                                           \
+                }                                                       \
+                ci = data[i];                                           \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        return qdict_size(*palette);                                    \
+    }
+
+DEFINE_FILL_PALETTE_FUNCTION(8)
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+static int tight_fill_palette(VncState *vs, int x, int y,
+                              size_t count, uint32_t *bg, uint32_t *fg,
+                              struct QDict **palette)
+{
+    int max;
+
+    max = count / tight_conf[vs->tight_compression].idx_max_colors_divisor;
+    if (max < 2 &&
+        count >= tight_conf[vs->tight_compression].mono_min_rect_size) {
+        max = 2;
+    }
+    if (max >= 256) {
+        max = 256;
+    }
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+        return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
+    case 2:
+        return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
+    default:
+        max = 2;
+        return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
+    }
+    return 0;
+}
+
+/* Callback to dump a palette with qdict_iter
+static void print_palette(const char *key, QObject *obj, void *opaque)
+{
+    uint8_t idx = qint_get_int(qobject_to_qint(obj));
+    uint32_t rgb = tight_palette_buf2rgb(32, (uint8_t *)key);
+
+    fprintf(stderr, "%.2x ", (unsigned char)*key);
+    while (*key++)
+        fprintf(stderr, "%.2x ", (unsigned char)*key);
+
+    fprintf(stderr, ": idx: %x rgb: %x\n", idx, rgb);
+}
+*/
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
+                                                                        \
+    static void                                                         \
+    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
+                                   struct QDict *palette) {             \
+        uint##bpp##_t *src;                                             \
+        uint##bpp##_t rgb;                                              \
+        uint8_t key[6];                                                 \
+        int i, rep;                                                     \
+        uint8_t idx;                                                    \
+                                                                        \
+        src = (uint##bpp##_t *) buf;                                    \
+                                                                        \
+        for (i = 0; i < count; i++) {                                   \
+            rgb = *src++;                                               \
+            rep = 0;                                                    \
+            while (i < count && *src == rgb) {                          \
+                rep++, src++, i++;                                      \
+            }                                                           \
+            tight_palette_rgb2buf(rgb, bpp, key);                       \
+            if (!qdict_haskey(palette, (char *)key)) {                  \
+                /*                                                      \
+                 * Should never happen, but don't break everything      \
+                 * if it does, use the first color instead              \
+                 */                                                     \
+                idx = 0;                                                \
+            } else {                                                    \
+                idx = qdict_get_int(palette, (char *)key);              \
+            }                                                           \
+            while (rep >= 0) {                                          \
+                *buf++ = idx;                                           \
+                rep--;                                                  \
+            }                                                           \
+        }                                                               \
+    }
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
+                                                                        \
+    static void                                                         \
+    tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h,             \
+                                uint##bpp##_t bg, uint##bpp##_t fg) {   \
+        uint##bpp##_t *ptr;                                             \
+        unsigned int value, mask;                                       \
+        int aligned_width;                                              \
+        int x, y, bg_bits;                                              \
+                                                                        \
+        ptr = (uint##bpp##_t *) buf;                                    \
+        aligned_width = w - w % 8;                                      \
+                                                                        \
+        for (y = 0; y < h; y++) {                                       \
+            for (x = 0; x < aligned_width; x += 8) {                    \
+                for (bg_bits = 0; bg_bits < 8; bg_bits++) {             \
+                    if (*ptr++ != bg) {                                 \
+                        break;                                          \
+                    }                                                   \
+                }                                                       \
+                if (bg_bits == 8) {                                     \
+                    *buf++ = 0;                                         \
+                    continue;                                           \
+                }                                                       \
+                mask = 0x80 >> bg_bits;                                 \
+                value = mask;                                           \
+                for (bg_bits++; bg_bits < 8; bg_bits++) {               \
+                    mask >>= 1;                                         \
+                    if (*ptr++ != bg) {                                 \
+                        value |= mask;                                  \
+                    }                                                   \
+                }                                                       \
+                *buf++ = (uint8_t)value;                                \
+            }                                                           \
+                                                                        \
+            mask = 0x80;                                                \
+            value = 0;                                                  \
+            if (x >= w) {                                               \
+                continue;                                               \
+            }                                                           \
+                                                                        \
+            for (; x < w; x++) {                                        \
+                if (*ptr++ != bg) {                                     \
+                    value |= mask;                                      \
+                }                                                       \
+                mask >>= 1;                                             \
+            }                                                           \
+            *buf++ = (uint8_t)value;                                    \
+        }                                                               \
+    }
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+{
+    uint32_t *buf32;
+    uint32_t pix32;
+    int shift[3];
+    int *prev;
+    int here[3], upper[3], left[3], upperleft[3];
+    int prediction;
+    int x, y, c;
+
+    buf32 = (uint32_t *)buf;
+    memset(vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));
+
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
+        shift[0] = vs->clientds.pf.rshift;
+        shift[1] = vs->clientds.pf.gshift;
+        shift[2] = vs->clientds.pf.bshift;
+    } else {
+        shift[0] = 24 - vs->clientds.pf.rshift;
+        shift[1] = 24 - vs->clientds.pf.gshift;
+        shift[2] = 24 - vs->clientds.pf.bshift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            upper[c] = 0;
+            here[c] = 0;
+        }
+        prev = (int *)vs->tight_gradient.buffer;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                upperleft[c] = upper[c];
+                left[c] = here[c];
+                upper[c] = *prev;
+                here[c] = (int)(pix32 >> shift[c] & 0xFF);
+                *prev++ = here[c];
+
+                prediction = left[c] + upper[c] - upperleft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(here[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                            \
+                                                                        \
+    static void                                                         \
+    tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf,        \
+                               int w, int h) {                          \
+        uint##bpp##_t pix, diff;                                        \
+        bool endian;                                                    \
+        int *prev;                                                      \
+        int max[3], shift[3];                                           \
+        int here[3], upper[3], left[3], upperleft[3];                   \
+        int prediction;                                                 \
+        int x, y, c;                                                    \
+                                                                        \
+        memset (vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));     \
+                                                                        \
+        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
+                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
+                                                                        \
+        max[0] = vs->clientds.pf.rmax;                                  \
+        max[1] = vs->clientds.pf.gmax;                                  \
+        max[2] = vs->clientds.pf.bmax;                                  \
+        shift[0] = vs->clientds.pf.rshift;                              \
+        shift[1] = vs->clientds.pf.gshift;                              \
+        shift[2] = vs->clientds.pf.bshift;                              \
+                                                                        \
+        for (y = 0; y < h; y++) {                                       \
+            for (c = 0; c < 3; c++) {                                   \
+                upper[c] = 0;                                           \
+                here[c] = 0;                                            \
+            }                                                           \
+            prev = (int *)vs->tight_gradient.buffer;                    \
+            for (x = 0; x < w; x++) {                                   \
+                pix = *buf;                                             \
+                if (endian) {                                           \
+                    pix = bswap_##bpp(pix);                             \
+                }                                                       \
+                diff = 0;                                               \
+                for (c = 0; c < 3; c++) {                               \
+                    upperleft[c] = upper[c];                            \
+                    left[c] = here[c];                                  \
+                    upper[c] = *prev;                                   \
+                    here[c] = (int)(pix >> shift[c] & max[c]);          \
+                    *prev++ = here[c];                                  \
+                                                                        \
+                    prediction = left[c] + upper[c] - upperleft[c];     \
+                    if (prediction < 0) {                               \
+                        prediction = 0;                                 \
+                    } else if (prediction > max[c]) {                   \
+                        prediction = max[c];                            \
+                    }                                                   \
+                    diff |= ((here[c] - prediction) & max[c])           \
+                        << shift[c];                                    \
+                }                                                       \
+                if (endian) {                                           \
+                    diff = bswap_##bpp(diff);                           \
+                }                                                       \
+                *buf++ = diff;                                          \
+            }                                                           \
+        }                                                               \
+    }
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                \
+                                                                        \
+    static bool                                                         \
+    check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h,     \
+                          uint32_t* color, bool samecolor)              \
+    {                                                                   \
+        VncDisplay *vd = vs->vd;                                        \
+        uint##bpp##_t *fbptr;                                           \
+        uint##bpp##_t c;                                                \
+        int dx, dy;                                                     \
+                                                                        \
+        fbptr = (uint##bpp##_t *)                                       \
+            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
+             x * ds_get_bytes_per_pixel(vs->ds));                       \
+                                                                        \
+        c = *fbptr;                                                     \
+        if (samecolor && (uint32_t)c != *color) {                       \
+            return false;                                               \
+        }                                                               \
+                                                                        \
+        for (dy = 0; dy < h; dy++) {                                    \
+            for (dx = 0; dx < w; dx++) {                                \
+                if (c != fbptr[dx]) {                                   \
+                    return false;                                       \
+                }                                                       \
+            }                                                           \
+            fbptr = (uint##bpp##_t *)                                   \
+                ((uint8_t *)fbptr + ds_get_linesize(vs->ds));           \
+        }                                                               \
+                                                                        \
+        *color = (uint32_t)c;                                           \
+        return true;                                                    \
+    }
+
+DEFINE_CHECK_SOLID_FUNCTION(32)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(8)
+
+static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
+                             uint32_t* color, bool samecolor)
+{
+    VncDisplay *vd = vs->vd;
+
+    switch(vd->server->pf.bytes_per_pixel) {
+    case 4:
+        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
+    case 2:
+        return check_solid_tile16(vs, x, y, w, h, color, samecolor);
+    default:
+        return check_solid_tile8(vs, x, y, w, h, color, samecolor);
+    }
+}
+
+static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
+                                 uint32_t color, int *w_ptr, int *h_ptr)
+{
+    int dx, dy, dw, dh;
+    int w_prev;
+    int w_best = 0, h_best = 0;
+
+    w_prev = w;
+
+    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+
+        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
+        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
+
+        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
+            break;
+        }
+
+        for (dx = x + dw; dx < x + w_prev;) {
+            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
+
+            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
+                break;
+            }
+            dx += dw;
+        }
+
+        w_prev = dx - x;
+        if (w_prev * (dy + dh - y) > w_best * h_best) {
+            w_best = w_prev;
+            h_best = dy + dh - y;
+        }
+    }
+
+    *w_ptr = w_best;
+    *h_ptr = h_best;
+}
+
+static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
+                              uint32_t color, int *x_ptr, int *y_ptr,
+                              int *w_ptr, int *h_ptr)
+{
+    int cx, cy;
+
+    /* Try to extend the area upwards. */
+    for ( cy = *y_ptr - 1;
+          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
+          cy-- );
+    *h_ptr += *y_ptr - (cy + 1);
+    *y_ptr = cy + 1;
+
+    /* ... downwards. */
+    for ( cy = *y_ptr + *h_ptr;
+          cy < y + h &&
+              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
+          cy++ );
+    *h_ptr += cy - (*y_ptr + *h_ptr);
+
+    /* ... to the left. */
+    for ( cx = *x_ptr - 1;
+          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
+          cx-- );
+    *w_ptr += *x_ptr - (cx + 1);
+    *x_ptr = cx + 1;
+
+    /* ... to the right. */
+    for ( cx = *x_ptr + *w_ptr;
+          cx < x + w &&
+              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
+          cx++ );
+    *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+static int tight_init_stream(VncState *vs, int stream_id,
+                             int level, int strategy)
+{
+    z_streamp zstream = &vs->tight_stream[stream_id];
+
+    if (zstream->opaque == NULL) {
+        int err;
+
+        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
+        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, strategy);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        vs->tight_levels[stream_id] = level;
+        zstream->opaque = vs;
+    }
+
+    if (vs->tight_levels[stream_id] != level) {
+        if (deflateParams(zstream, level, strategy) != Z_OK) {
+            return -1;
+        }
+        vs->tight_levels[stream_id] = level;
+    }
+    return 0;
+}
+
+static void tight_send_compact_size(VncState *vs, size_t len)
+{
+    int lpc = 0;
+    int bytes = 0;
+    char buf[3] = {0, 0, 0};
+
+    buf[bytes++] = len & 0x7F;
+    if (len > 0x7F) {
+        buf[bytes-1] |= 0x80;
+        buf[bytes++] = (len >> 7) & 0x7F;
+        if (len > 0x3FFF) {
+            buf[bytes-1] |= 0x80;
+            buf[bytes++] = (len >> 14) & 0xFF;
+        }
+    }
+    for (lpc = 0; lpc < bytes; lpc++) {
+        vnc_write_u8(vs, buf[lpc]);
+    }
+}
+
+static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
+                               int level, int strategy)
+{
+    z_streamp zstream = &vs->tight_stream[stream_id];
+    int previous_out;
+
+    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
+        vnc_write(vs, vs->tight.buffer, vs->tight.offset);
+        return bytes;
+    }
+
+    if (tight_init_stream(vs, stream_id, level, strategy)) {
+        return -1;
+    }
+
+    /* reserve memory in output buffer */
+    buffer_reserve(&vs->tight_zlib, bytes + 64);
+
+    /* set pointers */
+    zstream->next_in = vs->tight.buffer;
+    zstream->avail_in = vs->tight.offset;
+    zstream->next_out = vs->tight_zlib.buffer + vs->tight_zlib.offset;
+    zstream->avail_out = vs->tight_zlib.capacity - vs->tight_zlib.offset;
+    zstream->data_type = Z_BINARY;
+    previous_out = zstream->total_out;
+
+    /* start encoding */
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during tight compression\n");
+        return -1;
+    }
+
+    vs->tight_zlib.offset = vs->tight_zlib.capacity - zstream->avail_out;
+    bytes = zstream->total_out - previous_out;
+
+    tight_send_compact_size(vs, bytes);
+    vnc_write(vs, vs->tight_zlib.buffer, bytes);
+
+    buffer_reset(&vs->tight_zlib);
+
+    return bytes;
+}
+
+/*
+ * Subencoding implementations.
+ */
+static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
+{
+    uint32_t *buf32;
+    uint32_t pix;
+    int rshift, gshift, bshift;
+
+    buf32 = (uint32_t *)buf;
+
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
+        rshift = vs->clientds.pf.rshift;
+        gshift = vs->clientds.pf.gshift;
+        bshift = vs->clientds.pf.bshift;
+    } else {
+        rshift = 24 - vs->clientds.pf.rshift;
+        gshift = 24 - vs->clientds.pf.gshift;
+        bshift = 24 - vs->clientds.pf.bshift;
+    }
+
+    if (ret) {
+        *ret = count * 3;
+    }
+
+    while (count--) {
+        pix = *buf32++;
+        *buf++ = (char)(pix >> rshift);
+        *buf++ = (char)(pix >> gshift);
+        *buf++ = (char)(pix >> bshift);
+    }
+}
+
+static int send_full_color_rect(VncState *vs, int w, int h)
+{
+    int stream = 0;
+    size_t bytes;
+
+    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
+
+    if (vs->tight_pixel24) {
+        tight_pack24(vs, vs->tight.buffer, w * h, &vs->tight.offset);
+        bytes = 3;
+    } else {
+        bytes = vs->clientds.pf.bytes_per_pixel;
+    }
+
+    bytes = tight_compress_data(vs, stream, w * h * bytes,
+                                tight_conf[vs->tight_compression].raw_zlib_level,
+                                Z_DEFAULT_STRATEGY);
+
+    return (bytes >= 0);
+}
+
+static int send_solid_rect(VncState *vs)
+{
+    size_t bytes;
+
+    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
+
+    if (vs->tight_pixel24) {
+        tight_pack24(vs, vs->tight.buffer, 1, &vs->tight.offset);
+        bytes = 3;
+    } else {
+        bytes = vs->clientds.pf.bytes_per_pixel;
+    }
+
+    vnc_write(vs, vs->tight.buffer, bytes);
+    return 1;
+}
+
+static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
+{
+    size_t bytes;
+    int stream = 1;
+    int level = tight_conf[vs->tight_compression].mono_zlib_level;
+
+    bytes = ((w + 7) / 8) * h;
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
+    vnc_write_u8(vs, 1);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+    {
+        uint32_t buf[2] = {bg, fg};
+        size_t ret = sizeof (buf);
+
+        if (vs->tight_pixel24) {
+            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
+        }
+        vnc_write(vs, buf, ret);
+
+        tight_encode_mono_rect32(vs->tight.buffer, w, h, bg, fg);
+        break;
+    }
+    case 2:
+        vnc_write(vs, &bg, 2);
+        vnc_write(vs, &fg, 2);
+        tight_encode_mono_rect16(vs->tight.buffer, w, h, bg, fg);
+        break;
+    default:
+        vnc_write_u8(vs, bg);
+        vnc_write_u8(vs, fg);
+        tight_encode_mono_rect8(vs->tight.buffer, w, h, bg, fg);
+        break;
+    }
+    vs->tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
+    return (bytes >= 0);
+}
+
+struct palette_cb_priv {
+    VncState *vs;
+    uint8_t *header;
+};
+
+static void write_palette(const char *key, QObject *obj, void *opaque)
+{
+    struct palette_cb_priv *priv = opaque;
+    VncState *vs = priv->vs;
+    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
+    uint8_t idx = qint_get_int(qobject_to_qint(obj));
+
+    if (bytes == 4) {
+        uint32_t color = tight_palette_buf2rgb(32, (uint8_t *)key);
+
+        ((uint32_t*)priv->header)[idx] = color;
+    } else {
+        uint16_t color = tight_palette_buf2rgb(16, (uint8_t *)key);
+
+        ((uint16_t*)priv->header)[idx] = color;
+    }
+}
+
+static bool send_gradient_rect(VncState *vs, int w, int h)
+{
+    int stream = 3;
+    int level = tight_conf[vs->tight_compression].gradient_zlib_level;
+    size_t bytes;
+
+    if (vs->clientds.pf.bytes_per_pixel == 1)
+        return send_full_color_rect(vs, w, h);
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
+
+    buffer_reserve(&vs->tight_gradient, w * 3 * sizeof (int));
+
+    if (vs->tight_pixel24) {
+        tight_filter_gradient24(vs, vs->tight.buffer, w, h);
+        bytes = 3;
+    } else if (vs->clientds.pf.bytes_per_pixel == 4) {
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight.buffer, w, h);
+        bytes = 4;
+    } else {
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight.buffer, w, h);
+        bytes = 2;
+    }
+
+    buffer_reset(&vs->tight_gradient);
+
+    bytes = w * h * bytes;
+    vs->tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes,
+                                level, Z_FILTERED);
+    return (bytes >= 0);
+}
+
+static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
+{
+    int stream = 2;
+    int level = tight_conf[vs->tight_compression].idx_zlib_level;
+    int colors;
+    size_t bytes;
+
+    colors = qdict_size(palette);
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
+    vnc_write_u8(vs, colors - 1);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+    {
+        size_t old_offset, offset;
+        uint32_t header[qdict_size(palette)];
+        struct palette_cb_priv priv = { vs, (uint8_t *)header };
+
+        old_offset = vs->output.offset;
+        qdict_iter(palette, write_palette, &priv);
+        vnc_write(vs, header, sizeof(header));
+
+        if (vs->tight_pixel24) {
+            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
+            vs->output.offset = old_offset + offset;
+        }
+
+        tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
+        break;
+    }
+    case 2:
+    {
+        uint16_t header[qdict_size(palette)];
+        struct palette_cb_priv priv = { vs, (uint8_t *)header };
+
+        qdict_iter(palette, write_palette, &priv);
+        vnc_write(vs, header, sizeof(header));
+        tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
+        break;
+    }
+    default:
+        return -1; /* No palette for 8bits colors */
+        break;
+    }
+    bytes = w * h;
+    vs->tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes,
+                                level, Z_DEFAULT_STRATEGY);
+    return (bytes >= 0);
+}
+
+/*
+ * JPEG compression stuff.
+ */
+#ifdef CONFIG_VNC_JPEG
+static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
+                                     int count)
+{
+    VncDisplay *vd = vs->vd;
+    uint32_t *fbptr;
+    uint32_t pix;
+
+    fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) +
+                         x * ds_get_bytes_per_pixel(vs->ds));
+
+    while (count--) {
+        pix = *fbptr++;
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift);
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift);
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift);
+    }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                               \
+                                                                        \
+    static void                                                         \
+    jpeg_prepare_row##bpp(VncState *vs, uint8_t *dst,                   \
+                                int x, int y, int count)                \
+    {                                                                   \
+        VncDisplay *vd = vs->vd;                                        \
+        uint##bpp##_t *fbptr;                                           \
+        uint##bpp##_t pix;                                              \
+        int r, g, b;                                                    \
+                                                                        \
+        fbptr = (uint##bpp##_t *)                                       \
+            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
+             x * ds_get_bytes_per_pixel(vs->ds));                       \
+                                                                        \
+        while (count--) {                                               \
+            pix = *fbptr++;                                             \
+                                                                        \
+            r = (int)((pix >> vs->ds->surface->pf.rshift)               \
+                      & vs->ds->surface->pf.rmax);                      \
+            g = (int)((pix >> vs->ds->surface->pf.gshift)               \
+                      & vs->ds->surface->pf.gmax);                      \
+            b = (int)((pix >> vs->ds->surface->pf.bshift)               \
+                      & vs->ds->surface->pf.bmax);                      \
+                                                                        \
+            *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \
+                               / vs->ds->surface->pf.rmax);             \
+            *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \
+                               / vs->ds->surface->pf.gmax);             \
+            *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \
+                               / vs->ds->surface->pf.bmax);             \
+        }                                                               \
+    }
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
+                                       int count)
+{
+    if (vs->tight_pixel24)
+        jpeg_prepare_row24(vs, dst, x, y, count);
+    else if (ds_get_bytes_per_pixel(vs->ds) == 4)
+        jpeg_prepare_row32(vs, dst, x, y, count);
+    else
+        jpeg_prepare_row16(vs, dst, x, y, count);
+}
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+/* This is called once per encoding */
+static void jpeg_init_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
+    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
+}
+
+/* This is called when we ran out of buffer (shouldn't happen!) */
+static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    buffer->offset = buffer->capacity;
+    buffer_reserve(buffer, 2048);
+    jpeg_init_destination(cinfo);
+    return TRUE;
+}
+
+/* This is called when we are done processing data */
+static void jpeg_term_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
+}
+
+static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
+{
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    struct jpeg_destination_mgr manager;
+    JSAMPROW row[1];
+    uint8_t *buf;
+    int dy;
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1)
+        return send_full_color_rect(vs, w, h);
+
+    buf = qemu_malloc(w * 3);
+    row[0] = buf;
+    buffer_reserve(&vs->tight_jpeg, 2048);
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.client_data = vs;
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, true);
+
+    manager.init_destination = jpeg_init_destination;
+    manager.empty_output_buffer = jpeg_empty_output_buffer;
+    manager.term_destination = jpeg_term_destination;
+    cinfo.dest = &manager;
+
+    jpeg_start_compress(&cinfo, true);
+
+    for (dy = 0; dy < h; dy++) {
+        jpeg_prepare_row(vs, buf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, row, 1);
+    }
+
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
+
+    tight_send_compact_size(vs, vs->tight_jpeg.offset);
+    vnc_write(vs, vs->tight_jpeg.buffer, vs->tight_jpeg.offset);
+    buffer_reset(&vs->tight_jpeg);
+
+    return 1;
+}
+#endif /* CONFIG_VNC_JPEG */
+
+static void vnc_tight_start(VncState *vs)
+{
+    buffer_reset(&vs->tight);
+
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->tight_tmp = vs->output;
+    vs->output = vs->tight;
+}
+
+static void vnc_tight_stop(VncState *vs)
+{
+    // switch back to normal output/zlib buffers
+    vs->tight = vs->output;
+    vs->output = vs->tight_tmp;
+}
+
+static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+{
+    struct QDict *palette = NULL;
+    uint32_t bg = 0, fg = 0;
+    int colors;
+    int ret = 0;
+
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+
+    vnc_tight_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    vnc_tight_stop(vs);
+
+    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
+
+    if (colors == 0) {
+        if (tight_detect_smooth_image(vs, w, h)) {
+            if (vs->tight_quality == -1) {
+                ret = send_gradient_rect(vs, w, h);
+            } else {
+#ifdef CONFIG_VNC_JPEG
+                int quality = tight_conf[vs->tight_quality].jpeg_quality;
+
+                ret = send_jpeg_rect(vs, x, y, w, h, quality);
+#else
+                ret = send_full_color_rect(vs, w, h);
+#endif
+            }
+        } else {
+            ret = send_full_color_rect(vs, w, h);
+        }
+    } else if (colors == 1) {
+        ret = send_solid_rect(vs);
+    } else if (colors == 2) {
+        ret = send_mono_rect(vs, w, h, bg, fg);
+    } else if (colors <= 256) {
+#ifdef CONFIG_VNC_JPEG
+        if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
+            tight_detect_smooth_image(vs, w, h)) {
+            int quality = tight_conf[vs->tight_quality].jpeg_quality;
+
+            ret = send_jpeg_rect(vs, x, y, w, h, quality);
+        } else {
+            ret = send_palette_rect(vs, w, h, palette);
+        }
+#else
+        ret = send_palette_rect(vs, w, h, palette);
+#endif
+    }
+    QDECREF(palette);
+    return ret;
+}
+
+static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
+{
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+
+    vnc_tight_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    vnc_tight_stop(vs);
+
+    return send_solid_rect(vs);
+}
+
+static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
+{
+    int max_size, max_width;
+    int max_sub_width, max_sub_height;
+    int dx, dy;
+    int rw, rh;
+    int n = 0;
+
+    max_size = tight_conf[vs->tight_compression].max_rect_size;
+    max_width = tight_conf[vs->tight_compression].max_rect_width;
+
+    if (w > max_width || w * h > max_size) {
+        max_sub_width = (w > max_width) ? max_width : w;
+        max_sub_height = max_size / max_sub_width;
+
+        for (dy = 0; dy < h; dy += max_sub_height) {
+            for (dx = 0; dx < w; dx += max_width) {
+                rw = MIN(max_sub_width, w - dx);
+                rh = MIN(max_sub_height, h - dy);
+                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
+            }
+        }
+    } else {
+        n += send_sub_rect(vs, x, y, w, h);
+    }
+
+    return n;
+}
+
+static int find_large_solid_color_rect(VncState *vs, int x, int y,
+                                       int w, int h, int max_rows)
+{
+    int dx, dy, dw, dh;
+    int n = 0;
+
+    /* Try to find large solid-color areas and send them separately. */
+
+    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+
+        /* If a rectangle becomes too large, send its upper part now. */
+
+        if (dy - y >= max_rows) {
+            n += send_rect_simple(vs, x, y, w, max_rows);
+            y += max_rows;
+            h -= max_rows;
+        }
+
+        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
+
+        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+            uint32_t color_value;
+            int x_best, y_best, w_best, h_best;
+
+            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
+
+            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
+                continue ;
+            }
+
+            /* Get dimensions of solid-color area. */
+
+            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
+                                 color_value, &w_best, &h_best);
+
+            /* Make sure a solid rectangle is large enough
+               (or the whole rectangle is of the same color). */
+
+            if (w_best * h_best != w * h &&
+                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
+                continue;
+            }
+
+            /* Try to extend solid rectangle to maximum size. */
+
+            x_best = dx; y_best = dy;
+            extend_solid_area(vs, x, y, w, h, color_value,
+                              &x_best, &y_best, &w_best, &h_best);
+
+            /* Send rectangles at top and left to solid-color area. */
+
+            if (y_best != y) {
+                n += send_rect_simple(vs, x, y, w, y_best-y);
+            }
+            if (x_best != x) {
+                n += vnc_tight_send_framebuffer_update(vs, x, y_best,
+                                                       x_best-x, h_best);
+            }
+
+            /* Send solid-color rectangle. */
+            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
+
+            /* Send remaining rectangles (at right and bottom). */
+
+            if (x_best + w_best != x + w) {
+                n += vnc_tight_send_framebuffer_update(vs, x_best+w_best,
+                                                       y_best,
+                                                       w-(x_best-x)-w_best,
+                                                       h_best);
+            }
+            if (y_best + h_best != y + h) {
+                n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best,
+                                                       w, h-(y_best-y)-h_best);
+            }
+
+            /* Return after all recursive calls are done. */
+            return n;
+        }
+    }
+    return n + send_rect_simple(vs, x, y, w, h);
+}
+
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                      int w, int h)
+{
+    int max_rows;
+
+    if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
+        vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
+        vs->tight_pixel24 = true;
+    } else {
+        vs->tight_pixel24 = false;
+    }
+
+    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE)
+        return send_rect_simple(vs, x, y, w, h);
+
+    /* Calculate maximum number of rows in one non-solid rectangle. */
+
+    max_rows = tight_conf[vs->tight_compression].max_rect_size;
+    max_rows /= MIN(tight_conf[vs->tight_compression].max_rect_width, w);
+
+    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
+}
+
+void vnc_tight_clear(VncState *vs)
+{
+    int i;
+    for (i=0; i<ARRAY_SIZE(vs->tight_stream); i++) {
+        if (vs->tight_stream[i].opaque) {
+            deflateEnd(&vs->tight_stream[i]);
+        }
+    }
+
+    buffer_free(&vs->tight);
+    buffer_free(&vs->tight_zlib);
+    buffer_free(&vs->tight_gradient);
+#ifdef CONFIG_VNC_JPEG
+    buffer_free(&vs->tight_jpeg);
+#endif
+}
diff --git a/ui/vnc-encoding-tight.h b/ui/vnc-encoding-tight.h
new file mode 100644 (file)
index 0000000..9b0910c
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * QEMU VNC display driver: tight encoding
+ *
+ * From libvncserver/rfb/rfbproto.h
+ * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
+ * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef VNC_ENCODING_TIGHT_H
+#define VNC_ENCODING_TIGHT_H
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.
+ *
+ *-- The first byte of each Tight-encoded rectangle is a "compression control
+ *   byte". Its format is as follows (bit 0 is the least significant one):
+ *
+ *   bit 0:    if 1, then compression stream 0 should be reset;
+ *   bit 1:    if 1, then compression stream 1 should be reset;
+ *   bit 2:    if 1, then compression stream 2 should be reset;
+ *   bit 3:    if 1, then compression stream 3 should be reset;
+ *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
+ *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 0xxx, then the compression type is "basic",
+ *             values greater than 1001 are not valid.
+ *
+ * If the compression type is "basic", then bits 6..4 of the
+ * compression control byte (those xxx in 0xxx) specify the following:
+ *
+ *   bits 5-4:  decimal representation is the index of a particular zlib
+ *              stream which should be used for decompressing the data;
+ *   bit 6:     if 1, then a "filter id" byte is following this byte.
+ *
+ *-- The data that follows after the compression control byte described
+ * above depends on the compression type ("fill", "jpeg" or "basic").
+ *
+ *-- If the compression type is "fill", then the only pixel value follows, in
+ * client pixel format (see NOTE 1). This value applies to all pixels of the
+ * rectangle.
+ *
+ *-- If the compression type is "jpeg", the following data stream looks like
+ * this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     JPEG image.
+ *
+ * Data size is compactly represented in one, two or three bytes, according
+ * to the following scheme:
+ *
+ *  0xxxxxxx                    (for values 0..127)
+ *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
+ *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
+ *
+ * Here each character denotes one bit, xxxxxxx are the least significant 7
+ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
+ * most significant 8 bits (bits 14-21). For example, decimal value 10000
+ * should be represented as two bytes: binary 10010000 01001110, or
+ * hexadecimal 90 4E.
+ *
+ *-- If the compression type is "basic" and bit 6 of the compression control
+ * byte was set to 1, then the next (second) byte specifies "filter id" which
+ * tells the decoder what filter type was used by the encoder to pre-process
+ * pixel data before the compression. The "filter id" byte can be one of the
+ * following:
+ *
+ *   0:  no filter ("copy" filter);
+ *   1:  "palette" filter;
+ *   2:  "gradient" filter.
+ *
+ *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
+ * byte), or if the filter id is 0, then raw pixel values in the client
+ * format (see NOTE 1) will be compressed. See below details on the
+ * compression.
+ *
+ *-- The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better.
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ *   if (P[i,j] < 0) then P[i,j] := 0;
+ *   if (P[i,j] > MAX) then P[i,j] := MAX;
+ *   D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.
+ *
+ *-- The "palette" filter converts true-color pixel data to indexed colors
+ * and a palette which can consist of 2..256 colors. If the number of colors
+ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
+ * encode one pixel. 1-bit encoding is performed such way that the most
+ * significant bits correspond to the leftmost pixels, and each raw of pixels
+ * is aligned to the byte boundary. When "palette" filter is used, the
+ * palette is sent before the pixel data. The palette begins with an unsigned
+ * byte which value is the number of colors in the palette minus 1 (i.e. 1
+ * means 2 colors, 255 means 256 colors in the palette). Then follows the
+ * palette itself which consist of pixel values in client pixel format (see
+ * NOTE 1).
+ *
+ *-- The pixel data is compressed using the zlib library. But if the data
+ * size after applying the filter but before the compression is less then 12,
+ * then the data is sent as is, uncompressed. Four separate zlib streams
+ * (0..3) can be used and the decoder should read the actual stream id from
+ * the compression control byte (see NOTE 2).
+ *
+ * If the compression is not used, then the pixel data is sent as is,
+ * otherwise the data stream looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     zlib-compressed data.
+ *
+ * Data size is compactly represented in one, two or three bytes, just like
+ * in the "jpeg" compression method (see above).
+ *
+ *-- NOTE 1. If the color depth is 24, and all three color components are
+ * 8-bit wide, then one pixel in Tight encoding is always represented by
+ * three bytes, where the first byte is red component, the second byte is
+ * green component, and the third byte is blue component of the pixel color
+ * value. This applies to colors in palettes as well.
+ *
+ *-- NOTE 2. The decoder must reset compression streams' states before
+ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
+ * byte are set to 1. Note that the decoder must reset zlib streams even if
+ * the compression type is "fill" or "jpeg".
+ *
+ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
+ * when bits-per-pixel value is either 16 or 32, not 8.
+ *
+ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
+ * pixels. If a rectangle is wider, it must be split into several rectangles
+ * and each one should be encoded separately.
+ *
+ */
+
+#define VNC_TIGHT_EXPLICIT_FILTER       0x04
+#define VNC_TIGHT_FILL                  0x08
+#define VNC_TIGHT_JPEG                  0x09
+#define VNC_TIGHT_MAX_SUBENCODING       0x09
+
+/* Filters to improve compression efficiency */
+#define VNC_TIGHT_FILTER_COPY             0x00
+#define VNC_TIGHT_FILTER_PALETTE          0x01
+#define VNC_TIGHT_FILTER_GRADIENT         0x02
+
+/* Note: The following constant should not be changed. */
+#define VNC_TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define VNC_TIGHT_MIN_SPLIT_RECT_SIZE     4096
+#define VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE  2048
+#define VNC_TIGHT_MAX_SPLIT_TILE_SIZE       16
+
+#define VNC_TIGHT_JPEG_MIN_RECT_SIZE      4096
+#define VNC_TIGHT_DETECT_SUBROW_WIDTH        7
+#define VNC_TIGHT_DETECT_MIN_WIDTH           8
+#define VNC_TIGHT_DETECT_MIN_HEIGHT          8
+
+#endif /* VNC_ENCODING_TIGHT_H */
diff --git a/ui/vnc-encoding-zlib.c b/ui/vnc-encoding-zlib.c
new file mode 100644 (file)
index 0000000..a99bc38
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * QEMU VNC display driver: zlib encoding
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+
+#define ZALLOC_ALIGNMENT 16
+
+void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = qemu_mallocz(size);
+
+    return (p);
+}
+
+void vnc_zlib_zfree(void *x, void *addr)
+{
+    qemu_free(addr);
+}
+
+static void vnc_zlib_start(VncState *vs)
+{
+    buffer_reset(&vs->zlib);
+
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->zlib_tmp = vs->output;
+    vs->output = vs->zlib;
+}
+
+static int vnc_zlib_stop(VncState *vs)
+{
+    z_streamp zstream = &vs->zlib_stream;
+    int previous_out;
+
+    // switch back to normal output/zlib buffers
+    vs->zlib = vs->output;
+    vs->output = vs->zlib_tmp;
+
+    // compress the zlib buffer
+
+    // initialize the stream
+    // XXX need one stream per session
+    if (zstream->opaque != vs) {
+        int err;
+
+        VNC_DEBUG("VNC: initializing zlib stream\n");
+        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        vs->zlib_level = vs->tight_compression;
+        zstream->opaque = vs;
+    }
+
+    if (vs->tight_compression != vs->zlib_level) {
+        if (deflateParams(zstream, vs->tight_compression,
+                          Z_DEFAULT_STRATEGY) != Z_OK) {
+            return -1;
+        }
+        vs->zlib_level = vs->tight_compression;
+    }
+
+    // reserve memory in output buffer
+    buffer_reserve(&vs->output, vs->zlib.offset + 64);
+
+    // set pointers
+    zstream->next_in = vs->zlib.buffer;
+    zstream->avail_in = vs->zlib.offset;
+    zstream->next_out = vs->output.buffer + vs->output.offset;
+    zstream->avail_out = vs->output.capacity - vs->output.offset;
+    zstream->data_type = Z_BINARY;
+    previous_out = zstream->total_out;
+
+    // start encoding
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zlib compression\n");
+        return -1;
+    }
+
+    vs->output.offset = vs->output.capacity - zstream->avail_out;
+    return zstream->total_out - previous_out;
+}
+
+int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int old_offset, new_offset, bytes_written;
+
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
+
+    // remember where we put in the follow-up size
+    old_offset = vs->output.offset;
+    vnc_write_s32(vs, 0);
+
+    // compress the stream
+    vnc_zlib_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    bytes_written = vnc_zlib_stop(vs);
+
+    if (bytes_written == -1)
+        return 0;
+
+    // hack in the size
+    new_offset = vs->output.offset;
+    vs->output.offset = old_offset;
+    vnc_write_u32(vs, bytes_written);
+    vs->output.offset = new_offset;
+
+    return 1;
+}
+
+void vnc_zlib_clear(VncState *vs)
+{
+    if (vs->zlib_stream.opaque) {
+        deflateEnd(&vs->zlib_stream);
+    }
+    buffer_free(&vs->zlib);
+}
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
new file mode 100644 (file)
index 0000000..dec626c
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * QEMU VNC display driver: TLS helpers
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-x509.h"
+#include "vnc.h"
+#include "qemu_socket.h"
+
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
+static void vnc_debug_gnutls_log(int level, const char* str) {
+    VNC_DEBUG("%d %s", level, str);
+}
+#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
+
+
+#define DH_BITS 1024
+static gnutls_dh_params_t dh_params;
+
+static int vnc_tls_initialize(void)
+{
+    static int tlsinitialized = 0;
+
+    if (tlsinitialized)
+        return 1;
+
+    if (gnutls_global_init () < 0)
+        return 0;
+
+    /* XXX ought to re-generate diffie-hellmen params periodically */
+    if (gnutls_dh_params_init (&dh_params) < 0)
+        return 0;
+    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
+        return 0;
+
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
+    gnutls_global_set_log_level(10);
+    gnutls_global_set_log_function(vnc_debug_gnutls_log);
+#endif
+
+    tlsinitialized = 1;
+
+    return 1;
+}
+
+static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
+                            const void *data,
+                            size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = send(vs->csock, data, len, 0);
+    if (ret < 0) {
+        if (errno == EINTR)
+            goto retry;
+        return -1;
+    }
+    return ret;
+}
+
+
+static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
+                            void *data,
+                            size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = recv(vs->csock, data, len, 0);
+    if (ret < 0) {
+        if (errno == EINTR)
+            goto retry;
+        return -1;
+    }
+    return ret;
+}
+
+
+static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
+{
+    gnutls_anon_server_credentials anon_cred;
+    int ret;
+
+    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
+        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+        return NULL;
+    }
+
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
+
+    return anon_cred;
+}
+
+
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
+{
+    gnutls_certificate_credentials_t x509_cred;
+    int ret;
+
+    if (!vd->tls.x509cacert) {
+        VNC_DEBUG("No CA x509 certificate specified\n");
+        return NULL;
+    }
+    if (!vd->tls.x509cert) {
+        VNC_DEBUG("No server x509 certificate specified\n");
+        return NULL;
+    }
+    if (!vd->tls.x509key) {
+        VNC_DEBUG("No server private key specified\n");
+        return NULL;
+    }
+
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
+        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+        return NULL;
+    }
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
+                                                      vd->tls.x509cacert,
+                                                      GNUTLS_X509_FMT_PEM)) < 0) {
+        VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+        gnutls_certificate_free_credentials(x509_cred);
+        return NULL;
+    }
+
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
+                                                     vd->tls.x509cert,
+                                                     vd->tls.x509key,
+                                                     GNUTLS_X509_FMT_PEM)) < 0) {
+        VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
+        gnutls_certificate_free_credentials(x509_cred);
+        return NULL;
+    }
+
+    if (vd->tls.x509cacrl) {
+        if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
+                                                        vd->tls.x509cacrl,
+                                                        GNUTLS_X509_FMT_PEM)) < 0) {
+            VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
+            gnutls_certificate_free_credentials(x509_cred);
+            return NULL;
+        }
+    }
+
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+    return x509_cred;
+}
+
+
+int vnc_tls_validate_certificate(struct VncState *vs)
+{
+    int ret;
+    unsigned int status;
+    const gnutls_datum_t *certs;
+    unsigned int nCerts, i;
+    time_t now;
+
+    VNC_DEBUG("Validating client certificate\n");
+    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
+        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
+        return -1;
+    }
+
+    if ((now = time(NULL)) == ((time_t)-1)) {
+        return -1;
+    }
+
+    if (status != 0) {
+        if (status & GNUTLS_CERT_INVALID)
+            VNC_DEBUG("The certificate is not trusted.\n");
+
+        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+            VNC_DEBUG("The certificate hasn't got a known issuer.\n");
+
+        if (status & GNUTLS_CERT_REVOKED)
+            VNC_DEBUG("The certificate has been revoked.\n");
+
+        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+            VNC_DEBUG("The certificate uses an insecure algorithm\n");
+
+        return -1;
+    } else {
+        VNC_DEBUG("Certificate is valid!\n");
+    }
+
+    /* Only support x509 for now */
+    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
+        return -1;
+
+    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
+        return -1;
+
+    for (i = 0 ; i < nCerts ; i++) {
+        gnutls_x509_crt_t cert;
+        VNC_DEBUG ("Checking certificate chain %d\n", i);
+        if (gnutls_x509_crt_init (&cert) < 0)
+            return -1;
+
+        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
+            VNC_DEBUG("The certificate has expired\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_activation_time (cert) > now) {
+            VNC_DEBUG("The certificate is not yet activated\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_activation_time (cert) > now) {
+            VNC_DEBUG("The certificate is not yet activated\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (i == 0) {
+            size_t dnameSize = 1024;
+            vs->tls.dname = qemu_malloc(dnameSize);
+        requery:
+            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
+                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+                    vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
+                    goto requery;
+                }
+                gnutls_x509_crt_deinit (cert);
+                VNC_DEBUG("Cannot get client distinguished name: %s",
+                          gnutls_strerror (ret));
+                return -1;
+            }
+
+            if (vs->vd->tls.x509verify) {
+                int allow;
+                if (!vs->vd->tls.acl) {
+                    VNC_DEBUG("no ACL activated, allowing access");
+                    gnutls_x509_crt_deinit (cert);
+                    continue;
+                }
+
+                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
+                                                  vs->tls.dname);
+
+                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
+                          vs->tls.dname, allow ? "allowed" : "denied");
+                if (!allow) {
+                    gnutls_x509_crt_deinit (cert);
+                    return -1;
+                }
+            }
+        }
+
+        gnutls_x509_crt_deinit (cert);
+    }
+
+    return 0;
+}
+
+
+int vnc_tls_client_setup(struct VncState *vs,
+                         int needX509Creds) {
+    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
+
+    VNC_DEBUG("Do TLS setup\n");
+    if (vnc_tls_initialize() < 0) {
+        VNC_DEBUG("Failed to init TLS\n");
+        vnc_client_error(vs);
+        return -1;
+    }
+    if (vs->tls.session == NULL) {
+        if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_set_default_priority(vs->tls.session) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (needX509Creds) {
+            gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
+            if (!x509_cred) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                gnutls_certificate_free_credentials(x509_cred);
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (vs->vd->tls.x509verify) {
+                VNC_DEBUG("Requesting a client certificate\n");
+                gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
+            }
+
+        } else {
+            gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
+            if (!anon_cred) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                gnutls_anon_free_server_credentials(anon_cred);
+                vnc_client_error(vs);
+                return -1;
+            }
+        }
+
+        gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
+        gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
+        gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
+    }
+    return 0;
+}
+
+
+void vnc_tls_client_cleanup(struct VncState *vs)
+{
+    if (vs->tls.session) {
+        gnutls_deinit(vs->tls.session);
+        vs->tls.session = NULL;
+    }
+    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
+    free(vs->tls.dname);
+}
+
+
+
+static int vnc_set_x509_credential(VncDisplay *vd,
+                                   const char *certdir,
+                                   const char *filename,
+                                   char **cred,
+                                   int ignoreMissing)
+{
+    struct stat sb;
+
+    if (*cred) {
+        qemu_free(*cred);
+        *cred = NULL;
+    }
+
+    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
+
+    strcpy(*cred, certdir);
+    strcat(*cred, "/");
+    strcat(*cred, filename);
+
+    VNC_DEBUG("Check %s\n", *cred);
+    if (stat(*cred, &sb) < 0) {
+        qemu_free(*cred);
+        *cred = NULL;
+        if (ignoreMissing && errno == ENOENT)
+            return 0;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
+                               const char *certdir)
+{
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
+        goto cleanup;
+
+    return 0;
+
+ cleanup:
+    qemu_free(vd->tls.x509cacert);
+    qemu_free(vd->tls.x509cacrl);
+    qemu_free(vd->tls.x509cert);
+    qemu_free(vd->tls.x509key);
+    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
+    return -1;
+}
+
diff --git a/ui/vnc-tls.h b/ui/vnc-tls.h
new file mode 100644 (file)
index 0000000..2b93633
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * QEMU VNC display driver. TLS helpers
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef __QEMU_VNC_TLS_H__
+#define __QEMU_VNC_TLS_H__
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "acl.h"
+
+enum {
+    VNC_WIREMODE_CLEAR,
+    VNC_WIREMODE_TLS,
+};
+
+typedef struct VncDisplayTLS VncDisplayTLS;
+typedef struct VncStateTLS VncStateTLS;
+
+/* Server state */
+struct VncDisplayTLS {
+    int x509verify; /* Non-zero if server requests & validates client cert */
+    qemu_acl *acl;
+
+    /* Paths to x509 certs/keys */
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+};
+
+/* Per client state */
+struct VncStateTLS {
+    /* Whether data is being TLS encrypted yet */
+    int wiremode;
+    gnutls_session_t session;
+
+    /* Client's Distinguished Name from the x509 cert */
+    char *dname;
+};
+
+int vnc_tls_client_setup(VncState *vs, int x509Creds);
+void vnc_tls_client_cleanup(VncState *vs);
+
+int vnc_tls_validate_certificate(VncState *vs);
+
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
+                              const char *path);
+
+
+#endif /* __QEMU_VNC_TLS_H__ */
+
diff --git a/ui/vnc.c b/ui/vnc.c
new file mode 100644 (file)
index 0000000..ccd7aad
--- /dev/null
+++ b/ui/vnc.c
@@ -0,0 +1,2631 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+#include "sysemu.h"
+#include "qemu_socket.h"
+#include "qemu-timer.h"
+#include "acl.h"
+#include "qemu-objects.h"
+
+#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"
+
+#define count_bits(c, v) { \
+    for (c = 0; v; v >>= 1) \
+    { \
+        c += v & 1; \
+    } \
+}
+
+
+static VncDisplay *vnc_display; /* needed for info vnc */
+static DisplayChangeListener *dcl;
+
+static int vnc_cursor_define(VncState *vs);
+
+static char *addr_to_string(const char *format,
+                            struct sockaddr_storage *sa,
+                            socklen_t salen) {
+    char *addr;
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+    size_t addrlen;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return NULL;
+    }
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = qemu_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+
+char *vnc_socket_local_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+char *vnc_socket_remote_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
+                          socklen_t salen)
+{
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return -1;
+    }
+
+    qdict_put(qdict, "host", qstring_from_str(host));
+    qdict_put(qdict, "service", qstring_from_str(serv));
+    qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
+
+    return 0;
+}
+
+static int vnc_server_addr_put(QDict *qdict, int fd)
+{
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
+        return -1;
+    }
+
+    return put_addr_qdict(qdict, &sa, salen);
+}
+
+static int vnc_qdict_remote_addr(QDict *qdict, int fd)
+{
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
+        return -1;
+    }
+
+    return put_addr_qdict(qdict, &sa, salen);
+}
+
+static const char *vnc_auth_name(VncDisplay *vd) {
+    switch (vd->auth) {
+    case VNC_AUTH_INVALID:
+        return "invalid";
+    case VNC_AUTH_NONE:
+        return "none";
+    case VNC_AUTH_VNC:
+        return "vnc";
+    case VNC_AUTH_RA2:
+        return "ra2";
+    case VNC_AUTH_RA2NE:
+        return "ra2ne";
+    case VNC_AUTH_TIGHT:
+        return "tight";
+    case VNC_AUTH_ULTRA:
+        return "ultra";
+    case VNC_AUTH_TLS:
+        return "tls";
+    case VNC_AUTH_VENCRYPT:
+#ifdef CONFIG_VNC_TLS
+        switch (vd->subauth) {
+        case VNC_AUTH_VENCRYPT_PLAIN:
+            return "vencrypt+plain";
+        case VNC_AUTH_VENCRYPT_TLSNONE:
+            return "vencrypt+tls+none";
+        case VNC_AUTH_VENCRYPT_TLSVNC:
+            return "vencrypt+tls+vnc";
+        case VNC_AUTH_VENCRYPT_TLSPLAIN:
+            return "vencrypt+tls+plain";
+        case VNC_AUTH_VENCRYPT_X509NONE:
+            return "vencrypt+x509+none";
+        case VNC_AUTH_VENCRYPT_X509VNC:
+            return "vencrypt+x509+vnc";
+        case VNC_AUTH_VENCRYPT_X509PLAIN:
+            return "vencrypt+x509+plain";
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            return "vencrypt+tls+sasl";
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            return "vencrypt+x509+sasl";
+        default:
+            return "vencrypt";
+        }
+#else
+        return "vencrypt";
+#endif
+    case VNC_AUTH_SASL:
+        return "sasl";
+    }
+    return "unknown";
+}
+
+static int vnc_server_info_put(QDict *qdict)
+{
+    if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
+        return -1;
+    }
+
+    qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
+    return 0;
+}
+
+static void vnc_client_cache_auth(VncState *client)
+{
+    QDict *qdict;
+
+    if (!client->info) {
+        return;
+    }
+
+    qdict = qobject_to_qdict(client->info);
+
+#ifdef CONFIG_VNC_TLS
+    if (client->tls.session &&
+        client->tls.dname) {
+        qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (client->sasl.conn &&
+        client->sasl.username) {
+        qdict_put(qdict, "sasl_username",
+                  qstring_from_str(client->sasl.username));
+    }
+#endif
+}
+
+static void vnc_client_cache_addr(VncState *client)
+{
+    QDict *qdict;
+
+    qdict = qdict_new();
+    if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
+        QDECREF(qdict);
+        /* XXX: how to report the error? */
+        return;
+    }
+
+    client->info = QOBJECT(qdict);
+}
+
+static void vnc_qmp_event(VncState *vs, MonitorEvent event)
+{
+    QDict *server;
+    QObject *data;
+
+    if (!vs->info) {
+        return;
+    }
+
+    server = qdict_new();
+    if (vnc_server_info_put(server) < 0) {
+        QDECREF(server);
+        return;
+    }
+
+    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
+                              vs->info, QOBJECT(server));
+
+    monitor_protocol_event(event, data);
+
+    qobject_incref(vs->info);
+    qobject_decref(data);
+}
+
+static void info_vnc_iter(QObject *obj, void *opaque)
+{
+    QDict *client;
+    Monitor *mon = opaque;
+
+    client = qobject_to_qdict(obj);
+    monitor_printf(mon, "Client:\n");
+    monitor_printf(mon, "     address: %s:%s\n",
+                   qdict_get_str(client, "host"),
+                   qdict_get_str(client, "service"));
+
+#ifdef CONFIG_VNC_TLS
+    monitor_printf(mon, "  x509_dname: %s\n",
+        qdict_haskey(client, "x509_dname") ?
+        qdict_get_str(client, "x509_dname") : "none");
+#endif
+#ifdef CONFIG_VNC_SASL
+    monitor_printf(mon, "    username: %s\n",
+        qdict_haskey(client, "sasl_username") ?
+        qdict_get_str(client, "sasl_username") : "none");
+#endif
+}
+
+void do_info_vnc_print(Monitor *mon, const QObject *data)
+{
+    QDict *server;
+    QList *clients;
+
+    server = qobject_to_qdict(data);
+    if (qdict_get_bool(server, "enabled") == 0) {
+        monitor_printf(mon, "Server: disabled\n");
+        return;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    monitor_printf(mon, "     address: %s:%s\n",
+                   qdict_get_str(server, "host"),
+                   qdict_get_str(server, "service"));
+    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
+
+    clients = qdict_get_qlist(server, "clients");
+    if (qlist_empty(clients)) {
+        monitor_printf(mon, "Client: none\n");
+    } else {
+        qlist_iter(clients, info_vnc_iter, mon);
+    }
+}
+
+void do_info_vnc(Monitor *mon, QObject **ret_data)
+{
+    if (vnc_display == NULL || vnc_display->display == NULL) {
+        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+    } else {
+        QList *clist;
+        VncState *client;
+
+        clist = qlist_new();
+        QTAILQ_FOREACH(client, &vnc_display->clients, next) {
+            if (client->info) {
+                /* incref so that it's not freed by upper layers */
+                qobject_incref(client->info);
+                qlist_append_obj(clist, client->info);
+            }
+        }
+
+        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
+                                       QOBJECT(clist));
+        assert(*ret_data != NULL);
+
+        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
+            qobject_decref(*ret_data);
+            *ret_data = NULL;
+        }
+    }
+}
+
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+    return (vs->features & (1 << feature));
+}
+
+/* TODO
+   1) Get the queue working for IO.
+   2) there is some weirdness when using the -S option (the screen is grey
+      and not totally invalidated
+   3) resolutions > 1024
+*/
+
+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);
+static void vnc_remove_timer(VncDisplay *vd);
+
+static void vnc_colordepth(VncState *vs);
+static void framebuffer_update_request(VncState *vs, int incremental,
+                                       int x_position, int y_position,
+                                       int w, int h);
+static void vnc_refresh(void *opaque);
+static int vnc_refresh_server_surface(VncDisplay *vd);
+
+static inline void vnc_set_bit(uint32_t *d, int k)
+{
+    d[k >> 5] |= 1 << (k & 0x1f);
+}
+
+static inline void vnc_clear_bit(uint32_t *d, int k)
+{
+    d[k >> 5] &= ~(1 << (k & 0x1f));
+}
+
+static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
+{
+    int j;
+
+    j = 0;
+    while (n >= 32) {
+        d[j++] = -1;
+        n -= 32;
+    }
+    if (n > 0)
+        d[j++] = (1 << n) - 1;
+    while (j < nb_words)
+        d[j++] = 0;
+}
+
+static inline int vnc_get_bit(const uint32_t *d, int k)
+{
+    return (d[k >> 5] >> (k & 0x1f)) & 1;
+}
+
+static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
+                               int nb_words)
+{
+    int i;
+    for(i = 0; i < nb_words; i++) {
+        if ((d1[i] & d2[i]) != 0)
+            return 1;
+    }
+    return 0;
+}
+
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    int i;
+    VncDisplay *vd = ds->opaque;
+    struct VncSurface *s = &vd->guest;
+
+    h += y;
+
+    /* round x down to ensure the loop only spans one 16-pixel block per,
+       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
+       two 16-pixel blocks but we only mark the first as dirty
+    */
+    w += (x % 16);
+    x -= (x % 16);
+
+    x = MIN(x, s->ds->width);
+    y = MIN(y, s->ds->height);
+    w = MIN(x + w, s->ds->width) - x;
+    h = MIN(h, s->ds->height);
+
+    for (; y < h; y++)
+        for (i = 0; i < w; i += 16)
+            vnc_set_bit(s->dirty[y], (x + i) / 16);
+}
+
+void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+                            int32_t encoding)
+{
+    vnc_write_u16(vs, x);
+    vnc_write_u16(vs, y);
+    vnc_write_u16(vs, w);
+    vnc_write_u16(vs, h);
+
+    vnc_write_s32(vs, encoding);
+}
+
+void buffer_reserve(Buffer *buffer, size_t len)
+{
+    if ((buffer->capacity - buffer->offset) < len) {
+        buffer->capacity += (len + 1024);
+        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        if (buffer->buffer == NULL) {
+            fprintf(stderr, "vnc: out of memory\n");
+            exit(1);
+        }
+    }
+}
+
+int buffer_empty(Buffer *buffer)
+{
+    return buffer->offset == 0;
+}
+
+uint8_t *buffer_end(Buffer *buffer)
+{
+    return buffer->buffer + buffer->offset;
+}
+
+void buffer_reset(Buffer *buffer)
+{
+        buffer->offset = 0;
+}
+
+void buffer_free(Buffer *buffer)
+{
+    qemu_free(buffer->buffer);
+    buffer->offset = 0;
+    buffer->capacity = 0;
+    buffer->buffer = NULL;
+}
+
+void buffer_append(Buffer *buffer, const void *data, size_t len)
+{
+    memcpy(buffer->buffer + buffer->offset, data, len);
+    buffer->offset += len;
+}
+
+static void vnc_desktop_resize(VncState *vs)
+{
+    DisplayState *ds = vs->ds;
+
+    if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+        return;
+    }
+    if (vs->client_width == ds_get_width(ds) &&
+        vs->client_height == ds_get_height(ds)) {
+        return;
+    }
+    vs->client_width = ds_get_width(ds);
+    vs->client_height = ds_get_height(ds);
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1); /* number of rects */
+    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
+                           VNC_ENCODING_DESKTOPRESIZE);
+    vnc_flush(vs);
+}
+
+static void vnc_dpy_resize(DisplayState *ds)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs;
+
+    /* server surface */
+    if (!vd->server)
+        vd->server = qemu_mallocz(sizeof(*vd->server));
+    if (vd->server->data)
+        qemu_free(vd->server->data);
+    *(vd->server) = *(ds->surface);
+    vd->server->data = qemu_mallocz(vd->server->linesize *
+                                    vd->server->height);
+
+    /* guest surface */
+    if (!vd->guest.ds)
+        vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
+    if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
+        console_color_init(ds);
+    *(vd->guest.ds) = *(ds->surface);
+    memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_colordepth(vs);
+        vnc_desktop_resize(vs);
+        if (vs->vd->cursor) {
+            vnc_cursor_define(vs);
+        }
+        memset(vs->dirty, 0xFF, sizeof(vs->dirty));
+    }
+}
+
+/* fastest code */
+static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
+                                  void *pixels, int size)
+{
+    vnc_write(vs, pixels, size);
+}
+
+/* slowest but generic code. */
+void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
+{
+    uint8_t r, g, b;
+    VncDisplay *vd = vs->vd;
+
+    r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
+        vd->server->pf.rbits);
+    g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
+        vd->server->pf.gbits);
+    b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
+        vd->server->pf.bbits);
+    v = (r << vs->clientds.pf.rshift) |
+        (g << vs->clientds.pf.gshift) |
+        (b << vs->clientds.pf.bshift);
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 1:
+        buf[0] = v;
+        break;
+    case 2:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 8;
+            buf[1] = v;
+        } else {
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    default:
+    case 4:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 24;
+            buf[1] = v >> 16;
+            buf[2] = v >> 8;
+            buf[3] = v;
+        } else {
+            buf[3] = v >> 24;
+            buf[2] = v >> 16;
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    }
+}
+
+static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
+                                     void *pixels1, int size)
+{
+    uint8_t buf[4];
+
+    if (pf->bytes_per_pixel == 4) {
+        uint32_t *pixels = pixels1;
+        int n, i;
+        n = size >> 2;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (pf->bytes_per_pixel == 2) {
+        uint16_t *pixels = pixels1;
+        int n, i;
+        n = size >> 1;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (pf->bytes_per_pixel == 1) {
+        uint8_t *pixels = pixels1;
+        int n, i;
+        n = size;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else {
+        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
+    }
+}
+
+int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int i;
+    uint8_t *row;
+    VncDisplay *vd = vs->vd;
+
+    row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    for (i = 0; i < h; i++) {
+        vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
+        row += ds_get_linesize(vs->ds);
+    }
+    return 1;
+}
+
+static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int n = 0;
+
+    switch(vs->vnc_encoding) {
+        case VNC_ENCODING_ZLIB:
+            n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
+            n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_TIGHT:
+            n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        default:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+            n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+            break;
+    }
+    return n;
+}
+
+static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    /* send bitblit op to the vnc client */
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1); /* number of rects */
+    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
+    vnc_write_u16(vs, src_x);
+    vnc_write_u16(vs, src_y);
+    vnc_flush(vs);
+}
+
+static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs, *vn;
+    uint8_t *src_row;
+    uint8_t *dst_row;
+    int i,x,y,pitch,depth,inc,w_lim,s;
+    int cmp_bytes;
+
+    vnc_refresh_server_surface(vd);
+    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vs->force_update = 1;
+            vnc_update_client(vs, 1);
+            /* vs might be free()ed here */
+        }
+    }
+
+    /* do bitblit op on the local surface too */
+    pitch = ds_get_linesize(vd->ds);
+    depth = ds_get_bytes_per_pixel(vd->ds);
+    src_row = vd->server->data + pitch * src_y + depth * src_x;
+    dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
+    y = dst_y;
+    inc = 1;
+    if (dst_y > src_y) {
+        /* copy backwards */
+        src_row += pitch * (h-1);
+        dst_row += pitch * (h-1);
+        pitch = -pitch;
+        y = dst_y + h - 1;
+        inc = -1;
+    }
+    w_lim = w - (16 - (dst_x % 16));
+    if (w_lim < 0)
+        w_lim = w;
+    else
+        w_lim = w - (w_lim % 16);
+    for (i = 0; i < h; i++) {
+        for (x = 0; x <= w_lim;
+                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
+            if (x == w_lim) {
+                if ((s = w - w_lim) == 0)
+                    break;
+            } else if (!x) {
+                s = (16 - (dst_x % 16));
+                s = MIN(s, w_lim);
+            } else {
+                s = 16;
+            }
+            cmp_bytes = s * depth;
+            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
+                continue;
+            memmove(dst_row, src_row, cmp_bytes);
+            QTAILQ_FOREACH(vs, &vd->clients, next) {
+                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+                    vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
+                }
+            }
+        }
+        src_row += pitch - w * depth;
+        dst_row += pitch - w * depth;
+        y += inc;
+    }
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
+        }
+    }
+}
+
+static void vnc_mouse_set(int x, int y, int visible)
+{
+    /* can we ask the client(s) to move the pointer ??? */
+}
+
+static int vnc_cursor_define(VncState *vs)
+{
+    QEMUCursor *c = vs->vd->cursor;
+    PixelFormat pf = qemu_default_pixelformat(32);
+    int isize;
+
+    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
+        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs,  0);  /*  padding     */
+        vnc_write_u16(vs, 1);  /*  # of rects  */
+        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
+                               VNC_ENCODING_RICH_CURSOR);
+        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
+        vnc_write_pixels_generic(vs, &pf, c->data, isize);
+        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
+        return 0;
+    }
+    return -1;
+}
+
+static void vnc_dpy_cursor_define(QEMUCursor *c)
+{
+    VncDisplay *vd = vnc_display;
+    VncState *vs;
+
+    cursor_put(vd->cursor);
+    qemu_free(vd->cursor_mask);
+
+    vd->cursor = c;
+    cursor_get(vd->cursor);
+    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
+    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
+    cursor_get_mono_mask(c, 0, vd->cursor_mask);
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_cursor_define(vs);
+    }
+}
+
+static int find_and_clear_dirty_height(struct VncState *vs,
+                                       int y, int last_x, int x)
+{
+    int h;
+    VncDisplay *vd = vs->vd;
+
+    for (h = 1; h < (vd->server->height - y); h++) {
+        int tmp_x;
+        if (!vnc_get_bit(vs->dirty[y + h], last_x))
+            break;
+        for (tmp_x = last_x; tmp_x < x; tmp_x++)
+            vnc_clear_bit(vs->dirty[y + h], tmp_x);
+    }
+
+    return h;
+}
+
+static int vnc_update_client(VncState *vs, int has_dirty)
+{
+    if (vs->need_update && vs->csock != -1) {
+        VncDisplay *vd = vs->vd;
+        int y;
+        int n_rectangles;
+        int saved_offset;
+        int width, height;
+        int n;
+
+        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
+            /* kernel send buffers are full -> drop frames to throttle */
+            return 0;
+
+        if (!has_dirty && !vs->audio_cap && !vs->force_update)
+            return 0;
+
+        /*
+         * Send screen updates to the vnc client using the server
+         * surface and server dirty map.  guest surface updates
+         * happening in parallel don't disturb us, the next pass will
+         * send them to the client.
+         */
+        n_rectangles = 0;
+        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs, 0);
+        saved_offset = vs->output.offset;
+        vnc_write_u16(vs, 0);
+
+        width = MIN(vd->server->width, vs->client_width);
+        height = MIN(vd->server->height, vs->client_height);
+
+        for (y = 0; y < height; y++) {
+            int x;
+            int last_x = -1;
+            for (x = 0; x < width / 16; x++) {
+                if (vnc_get_bit(vs->dirty[y], x)) {
+                    if (last_x == -1) {
+                        last_x = x;
+                    }
+                    vnc_clear_bit(vs->dirty[y], x);
+                } else {
+                    if (last_x != -1) {
+                        int h = find_and_clear_dirty_height(vs, y, last_x, x);
+                        n = send_framebuffer_update(vs, last_x * 16, y,
+                                                    (x - last_x) * 16, h);
+                        n_rectangles += n;
+                    }
+                    last_x = -1;
+                }
+            }
+            if (last_x != -1) {
+                int h = find_and_clear_dirty_height(vs, y, last_x, x);
+                n = send_framebuffer_update(vs, last_x * 16, y,
+                                            (x - last_x) * 16, h);
+                n_rectangles += n;
+            }
+        }
+        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+        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 */
+static void audio_capture_notify(void *opaque, audcnotification_e cmd)
+{
+    VncState *vs = opaque;
+
+    switch (cmd) {
+    case AUD_CNOTIFY_DISABLE:
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
+        vnc_flush(vs);
+        break;
+
+    case AUD_CNOTIFY_ENABLE:
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
+        vnc_flush(vs);
+        break;
+    }
+}
+
+static void audio_capture_destroy(void *opaque)
+{
+}
+
+static void audio_capture(void *opaque, void *buf, int size)
+{
+    VncState *vs = opaque;
+
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+    vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
+}
+
+static void audio_add(VncState *vs)
+{
+    struct audio_capture_ops ops;
+
+    if (vs->audio_cap) {
+        monitor_printf(default_mon, "audio already running\n");
+        return;
+    }
+
+    ops.notify = audio_capture_notify;
+    ops.destroy = audio_capture_destroy;
+    ops.capture = audio_capture;
+
+    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
+    if (!vs->audio_cap) {
+        monitor_printf(default_mon, "Failed to add audio capture\n");
+    }
+}
+
+static void audio_del(VncState *vs)
+{
+    if (vs->audio_cap) {
+        AUD_del_capture(vs->audio_cap, vs);
+        vs->audio_cap = NULL;
+    }
+}
+
+static void vnc_disconnect_start(VncState *vs)
+{
+    if (vs->csock == -1)
+        return;
+    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    closesocket(vs->csock);
+    vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
+
+    buffer_free(&vs->input);
+    buffer_free(&vs->output);
+
+    qobject_decref(vs->info);
+
+    vnc_zlib_clear(vs);
+    vnc_tight_clear(vs);
+
+#ifdef CONFIG_VNC_TLS
+    vnc_tls_client_cleanup(vs);
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
+    audio_del(vs);
+
+    QTAILQ_REMOVE(&vs->vd->clients, vs, next);
+
+    if (QTAILQ_EMPTY(&vs->vd->clients)) {
+        dcl->idle = 1;
+    }
+
+    qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
+    vnc_remove_timer(vs->vd);
+    if (vs->vd->lock_key_sync)
+        qemu_remove_led_event_handler(vs->led);
+    qemu_free(vs);
+}
+
+int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+{
+    if (ret == 0 || ret == -1) {
+        if (ret == -1) {
+            switch (last_errno) {
+                case EINTR:
+                case EAGAIN:
+#ifdef _WIN32
+                case WSAEWOULDBLOCK:
+#endif
+                    return 0;
+                default:
+                    break;
+            }
+        }
+
+        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
+                  ret, ret < 0 ? last_errno : 0);
+        vnc_disconnect_start(vs);
+
+        return 0;
+    }
+    return ret;
+}
+
+
+void vnc_client_error(VncState *vs)
+{
+    VNC_DEBUG("Closing down client sock: protocol error\n");
+    vnc_disconnect_start(vs);
+}
+
+
+/*
+ * Called to write a chunk of data to the client socket. The data may
+ * be the raw data, or may have already been encoded by SASL.
+ * The data will be written either straight onto the socket, or
+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes written, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_write(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = send(vs->csock, (const void *)data, datalen, 0);
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to write buffered data to the client socket, when not
+ * using any SASL SSF encryption layers. Will write as much data
+ * as possible without blocking. If all buffered data is written,
+ * will switch the FD poll() handler back to read monitoring.
+ *
+ * Returns the number of bytes written, which may be less than
+ * the buffered output data if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+static long vnc_client_write_plain(VncState *vs)
+{
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.waitWriteSSF);
+
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        vs->sasl.waitWriteSSF) {
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
+        if (ret)
+            vs->sasl.waitWriteSSF -= ret;
+    } else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
+    if (!ret)
+        return 0;
+
+    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
+    vs->output.offset -= ret;
+
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is data to be written to
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring encryption calls)
+ */
+void vnc_client_write(void *opaque)
+{
+    VncState *vs = opaque;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        !vs->sasl.waitWriteSSF) {
+        vnc_client_write_sasl(vs);
+    } else
+#endif /* CONFIG_VNC_SASL */
+        vnc_client_write_plain(vs);
+}
+
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+{
+    vs->read_handler = func;
+    vs->read_handler_expect = expecting;
+}
+
+
+/*
+ * Called to read a chunk of data from the client socket. The data may
+ * be the raw data, or may need to be further decoded by SASL.
+ * The data will be read either straight from to the socket, or
+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes read, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_read(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = recv(vs->csock, (void *)data, datalen, 0);
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to read data from the client socket to the input buffer,
+ * when not using any SASL SSF encryption layers. Will read as much
+ * data as possible without blocking.
+ *
+ * Returns the number of bytes read. Returns -1 on error, and
+ * disconnects the client socket.
+ */
+static long vnc_client_read_plain(VncState *vs)
+{
+    int ret;
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
+              vs->input.buffer, vs->input.capacity, vs->input.offset);
+    buffer_reserve(&vs->input, 4096);
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
+    if (!ret)
+        return 0;
+    vs->input.offset += ret;
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is more data to be read from
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring decryption calls)
+ */
+void vnc_client_read(void *opaque)
+{
+    VncState *vs = opaque;
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn && vs->sasl.runSSF)
+        ret = vnc_client_read_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_read_plain(vs);
+    if (!ret) {
+        if (vs->csock == -1)
+            vnc_disconnect_finish(vs);
+        return;
+    }
+
+    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
+        size_t len = vs->read_handler_expect;
+        int ret;
+
+        ret = vs->read_handler(vs, vs->input.buffer, len);
+        if (vs->csock == -1) {
+            vnc_disconnect_finish(vs);
+            return;
+        }
+
+        if (!ret) {
+            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+            vs->input.offset -= len;
+        } else {
+            vs->read_handler_expect = ret;
+        }
+    }
+}
+
+void vnc_write(VncState *vs, const void *data, size_t len)
+{
+    buffer_reserve(&vs->output, len);
+
+    if (vs->csock != -1 && buffer_empty(&vs->output)) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+    }
+
+    buffer_append(&vs->output, data, len);
+}
+
+void vnc_write_s32(VncState *vs, int32_t value)
+{
+    vnc_write_u32(vs, *(uint32_t *)&value);
+}
+
+void vnc_write_u32(VncState *vs, uint32_t value)
+{
+    uint8_t buf[4];
+
+    buf[0] = (value >> 24) & 0xFF;
+    buf[1] = (value >> 16) & 0xFF;
+    buf[2] = (value >>  8) & 0xFF;
+    buf[3] = value & 0xFF;
+
+    vnc_write(vs, buf, 4);
+}
+
+void vnc_write_u16(VncState *vs, uint16_t value)
+{
+    uint8_t buf[2];
+
+    buf[0] = (value >> 8) & 0xFF;
+    buf[1] = value & 0xFF;
+
+    vnc_write(vs, buf, 2);
+}
+
+void vnc_write_u8(VncState *vs, uint8_t value)
+{
+    vnc_write(vs, (char *)&value, 1);
+}
+
+void vnc_flush(VncState *vs)
+{
+    if (vs->csock != -1 && vs->output.offset)
+        vnc_client_write(vs);
+}
+
+uint8_t read_u8(uint8_t *data, size_t offset)
+{
+    return data[offset];
+}
+
+uint16_t read_u16(uint8_t *data, size_t offset)
+{
+    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
+}
+
+int32_t read_s32(uint8_t *data, size_t offset)
+{
+    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
+                     (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+uint32_t read_u32(uint8_t *data, size_t offset)
+{
+    return ((data[offset] << 24) | (data[offset + 1] << 16) |
+            (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
+{
+}
+
+static void check_pointer_type_change(Notifier *notifier)
+{
+    VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
+    int absolute = kbd_mouse_is_absolute();
+
+    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
+        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1);
+        vnc_framebuffer_update(vs, absolute, 0,
+                               ds_get_width(vs->ds), ds_get_height(vs->ds),
+                               VNC_ENCODING_POINTER_TYPE_CHANGE);
+        vnc_flush(vs);
+    }
+    vs->absolute = absolute;
+}
+
+static void pointer_event(VncState *vs, int button_mask, int x, int y)
+{
+    int buttons = 0;
+    int dz = 0;
+
+    if (button_mask & 0x01)
+        buttons |= MOUSE_EVENT_LBUTTON;
+    if (button_mask & 0x02)
+        buttons |= MOUSE_EVENT_MBUTTON;
+    if (button_mask & 0x04)
+        buttons |= MOUSE_EVENT_RBUTTON;
+    if (button_mask & 0x08)
+        dz = -1;
+    if (button_mask & 0x10)
+        dz = 1;
+
+    if (vs->absolute) {
+        kbd_mouse_event(ds_get_width(vs->ds) > 1 ?
+                          x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000,
+                        ds_get_height(vs->ds) > 1 ?
+                          y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000,
+                        dz, buttons);
+    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
+        x -= 0x7FFF;
+        y -= 0x7FFF;
+
+        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;
+    }
+}
+
+static void reset_keys(VncState *vs)
+{
+    int i;
+    for(i = 0; i < 256; i++) {
+        if (vs->modifiers_state[i]) {
+            if (i & SCANCODE_GREY)
+                kbd_put_keycode(SCANCODE_EMUL0);
+            kbd_put_keycode(i | SCANCODE_UP);
+            vs->modifiers_state[i] = 0;
+        }
+    }
+}
+
+static void press_key(VncState *vs, int keysym)
+{
+    int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    kbd_put_keycode(keycode | SCANCODE_UP);
+}
+
+static void kbd_leds(void *opaque, int ledstate)
+{
+    VncState *vs = opaque;
+    int caps, num;
+
+    caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
+    num  = ledstate & QEMU_NUM_LOCK_LED  ? 1 : 0;
+
+    if (vs->modifiers_state[0x3a] != caps) {
+        vs->modifiers_state[0x3a] = caps;
+    }
+    if (vs->modifiers_state[0x45] != num) {
+        vs->modifiers_state[0x45] = num;
+    }
+}
+
+static void do_key_event(VncState *vs, int down, int keycode, int sym)
+{
+    /* QEMU console switch */
+    switch(keycode) {
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                          /* Right ALT */
+        if (down)
+            vs->modifiers_state[keycode] = 1;
+        else
+            vs->modifiers_state[keycode] = 0;
+        break;
+    case 0x02 ... 0x0a: /* '1' to '9' keys */
+        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+            /* Reset the modifiers sent to the current console */
+            reset_keys(vs);
+            console_select(keycode - 0x02);
+            return;
+        }
+        break;
+    case 0x3a:                        /* CapsLock */
+    case 0x45:                        /* NumLock */
+        if (down)
+            vs->modifiers_state[keycode] ^= 1;
+        break;
+    }
+
+    if (vs->vd->lock_key_sync &&
+        keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
+        /* If the numlock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles numlock away from the VNC window.
+        */
+        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
+            if (!vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 1;
+                press_key(vs, 0xff7f);
+            }
+        } else {
+            if (vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 0;
+                press_key(vs, 0xff7f);
+            }
+        }
+    }
+
+    if (vs->vd->lock_key_sync &&
+        ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
+        /* If the capslock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles capslock away from the VNC window.
+        */
+        int uppercase = !!(sym >= 'A' && sym <= 'Z');
+        int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
+        int capslock = !!(vs->modifiers_state[0x3a]);
+        if (capslock) {
+            if (uppercase == shift) {
+                vs->modifiers_state[0x3a] = 0;
+                press_key(vs, 0xffe5);
+            }
+        } else {
+            if (uppercase != shift) {
+                vs->modifiers_state[0x3a] = 1;
+                press_key(vs, 0xffe5);
+            }
+        }
+    }
+
+    if (is_graphic_console()) {
+        if (keycode & SCANCODE_GREY)
+            kbd_put_keycode(SCANCODE_EMUL0);
+        if (down)
+            kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+        else
+            kbd_put_keycode(keycode | SCANCODE_UP);
+    } else {
+        /* QEMU console emulation */
+        if (down) {
+            int numlock = vs->modifiers_state[0x45];
+            switch (keycode) {
+            case 0x2a:                          /* Left Shift */
+            case 0x36:                          /* Right Shift */
+            case 0x1d:                          /* Left CTRL */
+            case 0x9d:                          /* Right CTRL */
+            case 0x38:                          /* Left ALT */
+            case 0xb8:                          /* Right ALT */
+                break;
+            case 0xc8:
+                kbd_put_keysym(QEMU_KEY_UP);
+                break;
+            case 0xd0:
+                kbd_put_keysym(QEMU_KEY_DOWN);
+                break;
+            case 0xcb:
+                kbd_put_keysym(QEMU_KEY_LEFT);
+                break;
+            case 0xcd:
+                kbd_put_keysym(QEMU_KEY_RIGHT);
+                break;
+            case 0xd3:
+                kbd_put_keysym(QEMU_KEY_DELETE);
+                break;
+            case 0xc7:
+                kbd_put_keysym(QEMU_KEY_HOME);
+                break;
+            case 0xcf:
+                kbd_put_keysym(QEMU_KEY_END);
+                break;
+            case 0xc9:
+                kbd_put_keysym(QEMU_KEY_PAGEUP);
+                break;
+            case 0xd1:
+                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
+                break;
+
+            case 0x47:
+                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                break;
+            case 0x48:
+                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                break;
+            case 0x49:
+                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                break;
+            case 0x4b:
+                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                break;
+            case 0x4c:
+                kbd_put_keysym('5');
+                break;
+            case 0x4d:
+                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                break;
+            case 0x4f:
+                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                break;
+            case 0x50:
+                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                break;
+            case 0x51:
+                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                break;
+            case 0x52:
+                kbd_put_keysym('0');
+                break;
+            case 0x53:
+                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                break;
+
+            case 0xb5:
+                kbd_put_keysym('/');
+                break;
+            case 0x37:
+                kbd_put_keysym('*');
+                break;
+            case 0x4a:
+                kbd_put_keysym('-');
+                break;
+            case 0x4e:
+                kbd_put_keysym('+');
+                break;
+            case 0x9c:
+                kbd_put_keysym('\n');
+                break;
+
+            default:
+                kbd_put_keysym(sym);
+                break;
+            }
+        }
+    }
+}
+
+static void key_event(VncState *vs, int down, uint32_t sym)
+{
+    int keycode;
+    int lsym = sym;
+
+    if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
+        lsym = lsym - 'A' + 'a';
+    }
+
+    keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
+    do_key_event(vs, down, keycode, sym);
+}
+
+static void ext_key_event(VncState *vs, int down,
+                          uint32_t sym, uint16_t keycode)
+{
+    /* if the user specifies a keyboard layout, always use it */
+    if (keyboard_layout)
+        key_event(vs, down, sym);
+    else
+        do_key_event(vs, down, keycode, sym);
+}
+
+static void framebuffer_update_request(VncState *vs, int incremental,
+                                       int x_position, int y_position,
+                                       int w, int h)
+{
+    if (y_position > ds_get_height(vs->ds))
+        y_position = ds_get_height(vs->ds);
+    if (y_position + h >= ds_get_height(vs->ds))
+        h = ds_get_height(vs->ds) - y_position;
+
+    int i;
+    vs->need_update = 1;
+    if (!incremental) {
+        vs->force_update = 1;
+        for (i = 0; i < h; i++) {
+            vnc_set_bits(vs->dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        }
+    }
+}
+
+static void send_ext_key_event_ack(VncState *vs)
+{
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_EXT_KEY_EVENT);
+    vnc_flush(vs);
+}
+
+static void send_ext_audio_ack(VncState *vs)
+{
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_AUDIO);
+    vnc_flush(vs);
+}
+
+static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+{
+    int i;
+    unsigned int enc = 0;
+
+    vs->features = 0;
+    vs->vnc_encoding = 0;
+    vs->tight_compression = 9;
+    vs->tight_quality = -1; /* Lossless by default */
+    vs->absolute = -1;
+
+    /*
+     * Start from the end because the encodings are sent in order of preference.
+     * This way the prefered encoding (first encoding defined in the array)
+     * will be set at the end of the loop.
+     */
+    for (i = n_encodings - 1; i >= 0; i--) {
+        enc = encodings[i];
+        switch (enc) {
+        case VNC_ENCODING_RAW:
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_COPYRECT:
+            vs->features |= VNC_FEATURE_COPYRECT_MASK;
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vs->features |= VNC_FEATURE_HEXTILE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_TIGHT:
+            vs->features |= VNC_FEATURE_TIGHT_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZLIB:
+            vs->features |= VNC_FEATURE_ZLIB_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_DESKTOPRESIZE:
+            vs->features |= VNC_FEATURE_RESIZE_MASK;
+            break;
+        case VNC_ENCODING_POINTER_TYPE_CHANGE:
+            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
+            break;
+        case VNC_ENCODING_RICH_CURSOR:
+            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
+            break;
+        case VNC_ENCODING_EXT_KEY_EVENT:
+            send_ext_key_event_ack(vs);
+            break;
+        case VNC_ENCODING_AUDIO:
+            send_ext_audio_ack(vs);
+            break;
+        case VNC_ENCODING_WMVi:
+            vs->features |= VNC_FEATURE_WMVI_MASK;
+            break;
+        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
+            vs->tight_compression = (enc & 0x0F);
+            break;
+        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
+            vs->tight_quality = (enc & 0x0F);
+            break;
+        default:
+            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
+            break;
+        }
+    }
+    vnc_desktop_resize(vs);
+    check_pointer_type_change(&vs->mouse_mode_notifier);
+}
+
+static void set_pixel_conversion(VncState *vs)
+{
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
+        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
+        vs->write_pixels = vnc_write_pixels_copy;
+        vnc_hextile_set_pixel_conversion(vs, 0);
+    } else {
+        vs->write_pixels = vnc_write_pixels_generic;
+        vnc_hextile_set_pixel_conversion(vs, 1);
+    }
+}
+
+static void set_pixel_format(VncState *vs,
+                             int bits_per_pixel, int depth,
+                             int big_endian_flag, int true_color_flag,
+                             int red_max, int green_max, int blue_max,
+                             int red_shift, int green_shift, int blue_shift)
+{
+    if (!true_color_flag) {
+        vnc_client_error(vs);
+        return;
+    }
+
+    vs->clientds = *(vs->vd->guest.ds);
+    vs->clientds.pf.rmax = red_max;
+    count_bits(vs->clientds.pf.rbits, red_max);
+    vs->clientds.pf.rshift = red_shift;
+    vs->clientds.pf.rmask = red_max << red_shift;
+    vs->clientds.pf.gmax = green_max;
+    count_bits(vs->clientds.pf.gbits, green_max);
+    vs->clientds.pf.gshift = green_shift;
+    vs->clientds.pf.gmask = green_max << green_shift;
+    vs->clientds.pf.bmax = blue_max;
+    count_bits(vs->clientds.pf.bbits, blue_max);
+    vs->clientds.pf.bshift = blue_shift;
+    vs->clientds.pf.bmask = blue_max << blue_shift;
+    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
+    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
+    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
+    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
+
+    set_pixel_conversion(vs);
+
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void pixel_format_message (VncState *vs) {
+    char pad[3] = { 0, 0, 0 };
+
+    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
+    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
+
+#ifdef HOST_WORDS_BIGENDIAN
+    vnc_write_u8(vs, 1);             /* big-endian-flag */
+#else
+    vnc_write_u8(vs, 0);             /* big-endian-flag */
+#endif
+    vnc_write_u8(vs, 1);             /* true-color-flag */
+    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
+    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
+
+    vnc_hextile_set_pixel_conversion(vs, 0);
+
+    vs->clientds = *(vs->ds->surface);
+    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
+    vs->write_pixels = vnc_write_pixels_copy;
+
+    vnc_write(vs, pad, 3);           /* padding */
+}
+
+static void vnc_dpy_setdata(DisplayState *ds)
+{
+    /* We don't have to do anything */
+}
+
+static void vnc_colordepth(VncState *vs)
+{
+    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
+        /* Sending a WMVi message to notify the client*/
+        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1); /* number of rects */
+        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
+                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
+        pixel_format_message(vs);
+        vnc_flush(vs);
+    } else {
+        set_pixel_conversion(vs);
+    }
+}
+
+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 VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
+        if (len == 1)
+            return 20;
+
+        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+                         read_u8(data, 6), read_u8(data, 7),
+                         read_u16(data, 8), read_u16(data, 10),
+                         read_u16(data, 12), read_u8(data, 14),
+                         read_u8(data, 15), read_u8(data, 16));
+        break;
+    case VNC_MSG_CLIENT_SET_ENCODINGS:
+        if (len == 1)
+            return 4;
+
+        if (len == 4) {
+            limit = read_u16(data, 2);
+            if (limit > 0)
+                return 4 + (limit * 4);
+        } else
+            limit = read_u16(data, 2);
+
+        for (i = 0; i < limit; i++) {
+            int32_t val = read_s32(data, 4 + (i * 4));
+            memcpy(data + 4 + (i * 4), &val, sizeof(val));
+        }
+
+        set_encodings(vs, (int32_t *)(data + 4), limit);
+        break;
+    case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
+        if (len == 1)
+            return 10;
+
+        framebuffer_update_request(vs,
+                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+                                   read_u16(data, 6), read_u16(data, 8));
+        break;
+    case VNC_MSG_CLIENT_KEY_EVENT:
+        if (len == 1)
+            return 8;
+
+        key_event(vs, read_u8(data, 1), read_u32(data, 4));
+        break;
+    case VNC_MSG_CLIENT_POINTER_EVENT:
+        if (len == 1)
+            return 6;
+
+        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+        break;
+    case VNC_MSG_CLIENT_CUT_TEXT:
+        if (len == 1)
+            return 8;
+
+        if (len == 8) {
+            uint32_t dlen = read_u32(data, 4);
+            if (dlen > 0)
+                return 8 + dlen;
+        }
+
+        client_cut_text(vs, read_u32(data, 4), data + 8);
+        break;
+    case VNC_MSG_CLIENT_QEMU:
+        if (len == 1)
+            return 2;
+
+        switch (read_u8(data, 1)) {
+        case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
+            if (len == 2)
+                return 12;
+
+            ext_key_event(vs, read_u16(data, 2),
+                          read_u32(data, 4), read_u32(data, 8));
+            break;
+        case VNC_MSG_CLIENT_QEMU_AUDIO:
+            if (len == 2)
+                return 4;
+
+            switch (read_u16 (data, 2)) {
+            case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
+                audio_add(vs);
+                break;
+            case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
+                audio_del(vs);
+                break;
+            case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
+                if (len == 4)
+                    return 10;
+                switch (read_u8(data, 4)) {
+                case 0: vs->as.fmt = AUD_FMT_U8; break;
+                case 1: vs->as.fmt = AUD_FMT_S8; break;
+                case 2: vs->as.fmt = AUD_FMT_U16; break;
+                case 3: vs->as.fmt = AUD_FMT_S16; break;
+                case 4: vs->as.fmt = AUD_FMT_U32; break;
+                case 5: vs->as.fmt = AUD_FMT_S32; break;
+                default:
+                    printf("Invalid audio format %d\n", read_u8(data, 4));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.nchannels = read_u8(data, 5);
+                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
+                    printf("Invalid audio channel coount %d\n",
+                           read_u8(data, 5));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.freq = read_u32(data, 6);
+                break;
+            default:
+                printf ("Invalid audio message %d\n", read_u8(data, 4));
+                vnc_client_error(vs);
+                break;
+            }
+            break;
+
+        default:
+            printf("Msg: %d\n", read_u16(data, 0));
+            vnc_client_error(vs);
+            break;
+        }
+        break;
+    default:
+        printf("Msg: %d\n", data[0]);
+        vnc_client_error(vs);
+        break;
+    }
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+    return 0;
+}
+
+static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
+{
+    char buf[1024];
+    int size;
+
+    vs->client_width = ds_get_width(vs->ds);
+    vs->client_height = ds_get_height(vs->ds);
+    vnc_write_u16(vs, vs->client_width);
+    vnc_write_u16(vs, vs->client_height);
+
+    pixel_format_message(vs);
+
+    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_client_cache_auth(vs);
+    vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+
+    return 0;
+}
+
+void start_client_init(VncState *vs)
+{
+    vnc_read_when(vs, protocol_client_init, 1);
+}
+
+static void make_challenge(VncState *vs)
+{
+    int i;
+
+    srand(time(NULL)+getpid()+getpid()*987654+rand());
+
+    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
+        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
+}
+
+static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
+{
+    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
+    int i, j, pwlen;
+    unsigned char key[8];
+
+    if (!vs->vd->password || !vs->vd->password[0]) {
+        VNC_DEBUG("No password configured on server");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
+    }
+
+    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
+
+    /* Calculate the expected challenge response */
+    pwlen = strlen(vs->vd->password);
+    for (i=0; i<sizeof(key); i++)
+        key[i] = i<pwlen ? vs->vd->password[i] : 0;
+    deskey(key, EN0);
+    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
+        des(response+j, response+j);
+
+    /* Compare expected vs actual challenge response */
+    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
+        VNC_DEBUG("Client challenge reponse did not match\n");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Accepting VNC challenge response\n");
+        vnc_write_u32(vs, 0); /* Accept auth */
+        vnc_flush(vs);
+
+        start_client_init(vs);
+    }
+    return 0;
+}
+
+void start_auth_vnc(VncState *vs)
+{
+    make_challenge(vs);
+    /* Send client a 'random' challenge */
+    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
+    vnc_flush(vs);
+
+    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
+}
+
+
+static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
+{
+    /* We only advertise 1 auth scheme at a time, so client
+     * must pick the one we sent. Verify this */
+    if (data[0] != vs->vd->auth) { /* Reject auth */
+       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
+       vnc_write_u32(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Authentication failed";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    } else { /* Accept requested auth */
+       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
+       switch (vs->vd->auth) {
+       case VNC_AUTH_NONE:
+           VNC_DEBUG("Accept auth none\n");
+           if (vs->minor >= 8) {
+               vnc_write_u32(vs, 0); /* Accept auth completion */
+               vnc_flush(vs);
+           }
+           start_client_init(vs);
+           break;
+
+       case VNC_AUTH_VNC:
+           VNC_DEBUG("Start VNC auth\n");
+           start_auth_vnc(vs);
+           break;
+
+#ifdef CONFIG_VNC_TLS
+       case VNC_AUTH_VENCRYPT:
+           VNC_DEBUG("Accept VeNCrypt auth\n");;
+           start_auth_vencrypt(vs);
+           break;
+#endif /* CONFIG_VNC_TLS */
+
+#ifdef CONFIG_VNC_SASL
+       case VNC_AUTH_SASL:
+           VNC_DEBUG("Accept SASL auth\n");
+           start_auth_sasl(vs);
+           break;
+#endif /* CONFIG_VNC_SASL */
+
+       default: /* Should not be possible, but just in case */
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
+           vnc_write_u8(vs, 1);
+           if (vs->minor >= 8) {
+               static const char err[] = "Authentication failed";
+               vnc_write_u32(vs, sizeof(err));
+               vnc_write(vs, err, sizeof(err));
+           }
+           vnc_client_error(vs);
+       }
+    }
+    return 0;
+}
+
+static int protocol_version(VncState *vs, uint8_t *version, size_t len)
+{
+    char local[13];
+
+    memcpy(local, version, 12);
+    local[12] = 0;
+
+    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
+        VNC_DEBUG("Malformed protocol version %s\n", local);
+        vnc_client_error(vs);
+        return 0;
+    }
+    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
+    if (vs->major != 3 ||
+        (vs->minor != 3 &&
+         vs->minor != 4 &&
+         vs->minor != 5 &&
+         vs->minor != 7 &&
+         vs->minor != 8)) {
+        VNC_DEBUG("Unsupported client version\n");
+        vnc_write_u32(vs, VNC_AUTH_INVALID);
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
+    }
+    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
+     * as equivalent to v3.3 by servers
+     */
+    if (vs->minor == 4 || vs->minor == 5)
+        vs->minor = 3;
+
+    if (vs->minor == 3) {
+        if (vs->vd->auth == VNC_AUTH_NONE) {
+            VNC_DEBUG("Tell client auth none\n");
+            vnc_write_u32(vs, vs->vd->auth);
+            vnc_flush(vs);
+            start_client_init(vs);
+       } else if (vs->vd->auth == VNC_AUTH_VNC) {
+            VNC_DEBUG("Tell client VNC auth\n");
+            vnc_write_u32(vs, vs->vd->auth);
+            vnc_flush(vs);
+            start_auth_vnc(vs);
+       } else {
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
+            vnc_write_u32(vs, VNC_AUTH_INVALID);
+            vnc_flush(vs);
+            vnc_client_error(vs);
+       }
+    } else {
+        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
+        vnc_write_u8(vs, 1); /* num auth */
+        vnc_write_u8(vs, vs->vd->auth);
+        vnc_read_when(vs, protocol_client_auth, 1);
+        vnc_flush(vs);
+    }
+
+    return 0;
+}
+
+static int vnc_refresh_server_surface(VncDisplay *vd)
+{
+    int y;
+    uint8_t *guest_row;
+    uint8_t *server_row;
+    int cmp_bytes;
+    uint32_t width_mask[VNC_DIRTY_WORDS];
+    VncState *vs;
+    int has_dirty = 0;
+
+    /*
+     * Walk through the guest dirty map.
+     * Check and copy modified bits from guest to server surface.
+     * Update server dirty map.
+     */
+    vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
+    cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
+    guest_row  = vd->guest.ds->data;
+    server_row = vd->server->data;
+    for (y = 0; y < vd->guest.ds->height; y++) {
+        if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
+            int x;
+            uint8_t *guest_ptr;
+            uint8_t *server_ptr;
+
+            guest_ptr  = guest_row;
+            server_ptr = server_row;
+
+            for (x = 0; x < vd->guest.ds->width;
+                    x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+                if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
+                    continue;
+                vnc_clear_bit(vd->guest.dirty[y], (x / 16));
+                if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
+                    continue;
+                memcpy(server_ptr, guest_ptr, cmp_bytes);
+                QTAILQ_FOREACH(vs, &vd->clients, next) {
+                    vnc_set_bit(vs->dirty[y], (x / 16));
+                }
+                has_dirty++;
+            }
+        }
+        guest_row  += ds_get_linesize(vd->ds);
+        server_row += ds_get_linesize(vd->ds);
+    }
+    return has_dirty;
+}
+
+static void vnc_refresh(void *opaque)
+{
+    VncDisplay *vd = opaque;
+    VncState *vs, *vn;
+    int has_dirty, rects = 0;
+
+    vga_hw_update();
+
+    has_dirty = vnc_refresh_server_surface(vd);
+
+    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
+        rects += vnc_update_client(vs, has_dirty);
+        /* vs might be free()ed here */
+    }
+    /* vd->timer could be NULL now if the last client disconnected,
+     * in this case don't update the timer */
+    if (vd->timer == NULL)
+        return;
+
+    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 && !QTAILQ_EMPTY(&vd->clients)) {
+        vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
+        vnc_refresh(vd);
+    }
+}
+
+static void vnc_remove_timer(VncDisplay *vd)
+{
+    if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) {
+        qemu_del_timer(vd->timer);
+        qemu_free_timer(vd->timer);
+        vd->timer = NULL;
+    }
+}
+
+static void vnc_connect(VncDisplay *vd, int csock)
+{
+    VncState *vs = qemu_mallocz(sizeof(VncState));
+    vs->csock = csock;
+
+    VNC_DEBUG("New client on socket %d\n", csock);
+    dcl->idle = 0;
+    socket_set_nonblock(vs->csock);
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+
+    vnc_client_cache_addr(vs);
+    vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
+
+    vs->vd = vd;
+    vs->ds = vd->ds;
+    vs->last_x = -1;
+    vs->last_y = -1;
+
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
+
+    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
+
+    vga_hw_update();
+
+    vnc_write(vs, "RFB 003.008\n", 12);
+    vnc_flush(vs);
+    vnc_read_when(vs, protocol_version, 12);
+    reset_keys(vs);
+    if (vs->vd->lock_key_sync)
+        vs->led = qemu_add_led_event_handler(kbd_leds, vs);
+
+    vs->mouse_mode_notifier.notify = check_pointer_type_change;
+    qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
+
+    vnc_init_timer(vd);
+
+    /* vs might be free()ed here */
+}
+
+static void vnc_listen_read(void *opaque)
+{
+    VncDisplay *vs = opaque;
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
+
+    /* Catch-up */
+    vga_hw_update();
+
+    int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+    if (csock != -1) {
+        vnc_connect(vs, csock);
+    }
+}
+
+void vnc_display_init(DisplayState *ds)
+{
+    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+
+    ds->opaque = vs;
+    dcl->idle = 1;
+    vnc_display = vs;
+
+    vs->lsock = -1;
+
+    vs->ds = ds;
+    QTAILQ_INIT(&vs->clients);
+
+    if (keyboard_layout)
+        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+    else
+        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+
+    if (!vs->kbd_layout)
+        exit(1);
+
+    dcl->dpy_copy = vnc_dpy_copy;
+    dcl->dpy_update = vnc_dpy_update;
+    dcl->dpy_resize = vnc_dpy_resize;
+    dcl->dpy_setdata = vnc_dpy_setdata;
+    register_displaychangelistener(ds, dcl);
+    ds->mouse_set = vnc_mouse_set;
+    ds->cursor_define = vnc_dpy_cursor_define;
+}
+
+
+void vnc_display_close(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (!vs)
+        return;
+    if (vs->display) {
+        qemu_free(vs->display);
+        vs->display = NULL;
+    }
+    if (vs->lsock != -1) {
+        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        close(vs->lsock);
+        vs->lsock = -1;
+    }
+    vs->auth = VNC_AUTH_INVALID;
+#ifdef CONFIG_VNC_TLS
+    vs->subauth = VNC_AUTH_INVALID;
+    vs->tls.x509verify = 0;
+#endif
+}
+
+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;
+    }
+    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;
+}
+
+char *vnc_display_local_addr(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    
+    return vnc_socket_local_addr("%s:%s", vs->lsock);
+}
+
+int vnc_display_open(DisplayState *ds, const char *display)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    const char *options;
+    int password = 0;
+    int reverse = 0;
+#ifdef CONFIG_VNC_TLS
+    int tls = 0, x509 = 0;
+#endif
+#ifdef CONFIG_VNC_SASL
+    int sasl = 0;
+    int saslErr;
+#endif
+    int acl = 0;
+    int lock_key_sync = 1;
+
+    if (!vnc_display)
+        return -1;
+    vnc_display_close(ds);
+    if (strcmp(display, "none") == 0)
+        return 0;
+
+    if (!(vs->display = strdup(display)))
+        return -1;
+
+    options = display;
+    while ((options = strchr(options, ','))) {
+        options++;
+        if (strncmp(options, "password", 8) == 0) {
+            password = 1; /* Require password auth */
+        } else if (strncmp(options, "reverse", 7) == 0) {
+            reverse = 1;
+        } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
+            lock_key_sync = 0;
+#ifdef CONFIG_VNC_SASL
+        } else if (strncmp(options, "sasl", 4) == 0) {
+            sasl = 1; /* Require SASL auth */
+#endif
+#ifdef CONFIG_VNC_TLS
+        } else if (strncmp(options, "tls", 3) == 0) {
+            tls = 1; /* Require TLS */
+        } else if (strncmp(options, "x509", 4) == 0) {
+            char *start, *end;
+            x509 = 1; /* Require x509 certificates */
+            if (strncmp(options, "x509verify", 10) == 0)
+                vs->tls.x509verify = 1; /* ...and verify client certs */
+
+            /* Now check for 'x509=/some/path' postfix
+             * and use that to setup x509 certificate/key paths */
+            start = strchr(options, '=');
+            end = strchr(options, ',');
+            if (start && (!end || (start < end))) {
+                int len = end ? end-(start+1) : strlen(start+1);
+                char *path = qemu_strndup(start + 1, len);
+
+                VNC_DEBUG("Trying certificate path '%s'\n", path);
+                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+                    qemu_free(path);
+                    qemu_free(vs->display);
+                    vs->display = NULL;
+                    return -1;
+                }
+                qemu_free(path);
+            } else {
+                fprintf(stderr, "No certificate path provided\n");
+                qemu_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
+#endif
+        } else if (strncmp(options, "acl", 3) == 0) {
+            acl = 1;
+        } else if (strncmp(options, "lossy", 5) == 0) {
+            vs->lossy = true;
+        }
+    }
+
+#ifdef CONFIG_VNC_TLS
+    if (acl && x509 && vs->tls.x509verify) {
+        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+            fprintf(stderr, "Failed to create x509 dname ACL\n");
+            exit(1);
+        }
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (acl && sasl) {
+        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+            fprintf(stderr, "Failed to create username ACL\n");
+            exit(1);
+        }
+    }
+#endif
+
+    /*
+     * Combinations we support here:
+     *
+     *  - no-auth                (clear text, no auth)
+     *  - password               (clear text, weak auth)
+     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
+     *  - tls                    (encrypt, weak anonymous creds, no auth)
+     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
+     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
+     *  - tls + x509             (encrypt, good x509 creds, no auth)
+     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
+     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
+     *
+     * NB1. TLS is a stackable auth scheme.
+     * NB2. the x509 schemes have option to validate a client cert dname
+     */
+    if (password) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with password auth\n");
+            vs->auth = VNC_AUTH_VNC;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    } else if (sasl) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            vs->auth = VNC_AUTH_SASL;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#endif /* CONFIG_VNC_SASL */
+    } else {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+            }
+        } else {
+#endif
+            VNC_DEBUG("Initializing VNC server with no auth\n");
+            vs->auth = VNC_AUTH_NONE;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif
+    }
+
+#ifdef CONFIG_VNC_SASL
+    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
+        fprintf(stderr, "Failed to initialize SASL auth %s",
+                sasl_errstring(saslErr, NULL, NULL));
+        free(vs->display);
+        vs->display = NULL;
+        return -1;
+    }
+#endif
+    vs->lock_key_sync = lock_key_sync;
+
+    if (reverse) {
+        /* connect to viewer */
+        if (strncmp(display, "unix:", 5) == 0)
+            vs->lsock = unix_connect(display+5);
+        else
+            vs->lsock = inet_connect(display, SOCK_STREAM);
+        if (-1 == vs->lsock) {
+            free(vs->display);
+            vs->display = NULL;
+            return -1;
+        } else {
+            int csock = vs->lsock;
+            vs->lsock = -1;
+            vnc_connect(vs, csock);
+        }
+        return 0;
+
+    } else {
+        /* listen for connects */
+        char *dpy;
+        dpy = qemu_malloc(256);
+        if (strncmp(display, "unix:", 5) == 0) {
+            pstrcpy(dpy, 256, "unix:");
+            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+        } else {
+            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
+        }
+        if (-1 == vs->lsock) {
+            free(dpy);
+            return -1;
+        } else {
+            free(vs->display);
+            vs->display = dpy;
+        }
+    }
+    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
+}
diff --git a/ui/vnc.h b/ui/vnc.h
new file mode 100644 (file)
index 0000000..ec90cd3
--- /dev/null
+++ b/ui/vnc.h
@@ -0,0 +1,430 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_VNC_H
+#define __QEMU_VNC_H
+
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "console.h"
+#include "monitor.h"
+#include "audio/audio.h"
+#include <zlib.h>
+#include <stdbool.h>
+
+#include "keymaps.h"
+
+// #define _VNC_DEBUG 1
+
+#ifdef _VNC_DEBUG
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define VNC_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+/*****************************************************************************
+ *
+ * Core data structures
+ *
+ *****************************************************************************/
+
+typedef struct Buffer
+{
+    size_t capacity;
+    size_t offset;
+    uint8_t *buffer;
+} Buffer;
+
+typedef struct VncState VncState;
+
+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
+
+typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
+
+typedef void VncSendHextileTile(VncState *vs,
+                                int x, int y, int w, int h,
+                                void *last_bg,
+                                void *last_fg,
+                                int *has_bg, int *has_fg);
+
+#define VNC_MAX_WIDTH 2560
+#define VNC_MAX_HEIGHT 2048
+#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
+
+#define VNC_AUTH_CHALLENGE_SIZE 16
+
+typedef struct VncDisplay VncDisplay;
+
+#ifdef CONFIG_VNC_TLS
+#include "vnc-tls.h"
+#include "vnc-auth-vencrypt.h"
+#endif
+#ifdef CONFIG_VNC_SASL
+#include "vnc-auth-sasl.h"
+#endif
+
+struct VncSurface
+{
+    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
+    DisplaySurface *ds;
+};
+
+struct VncDisplay
+{
+    QTAILQ_HEAD(, VncState) clients;
+    QEMUTimer *timer;
+    int timer_interval;
+    int lsock;
+    DisplayState *ds;
+    kbd_layout_t *kbd_layout;
+    int lock_key_sync;
+
+    QEMUCursor *cursor;
+    int cursor_msize;
+    uint8_t *cursor_mask;
+
+    struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
+    DisplaySurface *server;  /* vnc server surface */
+
+    char *display;
+    char *password;
+    int auth;
+    bool lossy;
+#ifdef CONFIG_VNC_TLS
+    int subauth; /* Used by VeNCrypt */
+    VncDisplayTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncDisplaySASL sasl;
+#endif
+};
+
+struct VncState
+{
+    int csock;
+
+    DisplayState *ds;
+    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
+
+    VncDisplay *vd;
+    int need_update;
+    int force_update;
+    uint32_t features;
+    int absolute;
+    int last_x;
+    int last_y;
+    int client_width;
+    int client_height;
+
+    uint32_t vnc_encoding;
+
+    int major;
+    int minor;
+
+    char challenge[VNC_AUTH_CHALLENGE_SIZE];
+#ifdef CONFIG_VNC_TLS
+    VncStateTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncStateSASL sasl;
+#endif
+
+    QObject *info;
+
+    Buffer output;
+    Buffer input;
+    /* current output mode information */
+    VncWritePixels *write_pixels;
+    DisplaySurface clientds;
+
+    CaptureVoiceOut *audio_cap;
+    struct audsettings as;
+
+    VncReadEvent *read_handler;
+    size_t read_handler_expect;
+    /* input */
+    uint8_t modifiers_state[256];
+    QEMUPutLEDEntry *led;
+
+    /* Encoding specific */
+
+    /* Tight */
+    uint8_t tight_quality;
+    uint8_t tight_compression;
+    uint8_t tight_pixel24;
+    Buffer tight;
+    Buffer tight_tmp;
+    Buffer tight_zlib;
+    Buffer tight_gradient;
+#ifdef CONFIG_VNC_JPEG
+    Buffer tight_jpeg;
+#endif
+    int tight_levels[4];
+    z_stream tight_stream[4];
+
+    /* Hextile */
+    VncSendHextileTile *send_hextile_tile;
+
+    /* Zlib */
+    Buffer zlib;
+    Buffer zlib_tmp;
+    z_stream zlib_stream;
+    int zlib_level;
+
+    Notifier mouse_mode_notifier;
+
+    QTAILQ_ENTRY(VncState) next;
+};
+
+
+/*****************************************************************************
+ *
+ * Authentication modes
+ *
+ *****************************************************************************/
+
+enum {
+    VNC_AUTH_INVALID = 0,
+    VNC_AUTH_NONE = 1,
+    VNC_AUTH_VNC = 2,
+    VNC_AUTH_RA2 = 5,
+    VNC_AUTH_RA2NE = 6,
+    VNC_AUTH_TIGHT = 16,
+    VNC_AUTH_ULTRA = 17,
+    VNC_AUTH_TLS = 18,      /* Supported in GTK-VNC & VINO */
+    VNC_AUTH_VENCRYPT = 19, /* Supported in GTK-VNC & VeNCrypt */
+    VNC_AUTH_SASL = 20,     /* Supported in GTK-VNC & VINO */
+};
+
+enum {
+    VNC_AUTH_VENCRYPT_PLAIN = 256,
+    VNC_AUTH_VENCRYPT_TLSNONE = 257,
+    VNC_AUTH_VENCRYPT_TLSVNC = 258,
+    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+    VNC_AUTH_VENCRYPT_X509NONE = 260,
+    VNC_AUTH_VENCRYPT_X509VNC = 261,
+    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
+    VNC_AUTH_VENCRYPT_X509SASL = 263,
+    VNC_AUTH_VENCRYPT_TLSSASL = 264,
+};
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define VNC_ENCODING_RAW                  0x00000000
+#define VNC_ENCODING_COPYRECT             0x00000001
+#define VNC_ENCODING_RRE                  0x00000002
+#define VNC_ENCODING_CORRE                0x00000004
+#define VNC_ENCODING_HEXTILE              0x00000005
+#define VNC_ENCODING_ZLIB                 0x00000006
+#define VNC_ENCODING_TIGHT                0x00000007
+#define VNC_ENCODING_ZLIBHEX              0x00000008
+#define VNC_ENCODING_TRLE                 0x0000000f
+#define VNC_ENCODING_ZRLE                 0x00000010
+#define VNC_ENCODING_ZYWRLE               0x00000011
+#define VNC_ENCODING_COMPRESSLEVEL0       0xFFFFFF00 /* -256 */
+#define VNC_ENCODING_QUALITYLEVEL0        0xFFFFFFE0 /* -32  */
+#define VNC_ENCODING_XCURSOR              0xFFFFFF10 /* -240 */
+#define VNC_ENCODING_RICH_CURSOR          0xFFFFFF11 /* -239 */
+#define VNC_ENCODING_POINTER_POS          0xFFFFFF18 /* -232 */
+#define VNC_ENCODING_LASTRECT             0xFFFFFF20 /* -224 */
+#define VNC_ENCODING_DESKTOPRESIZE        0xFFFFFF21 /* -223 */
+#define VNC_ENCODING_POINTER_TYPE_CHANGE  0XFFFFFEFF /* -257 */
+#define VNC_ENCODING_EXT_KEY_EVENT        0XFFFFFEFE /* -258 */
+#define VNC_ENCODING_AUDIO                0XFFFFFEFD /* -259 */
+#define VNC_ENCODING_WMVi                 0x574D5669
+
+/*****************************************************************************
+ *
+ * Other tight constants
+ *
+ *****************************************************************************/
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define VNC_TIGHT_CCB_RESET_MASK   (0x0f)
+#define VNC_TIGHT_CCB_TYPE_MASK    (0x0f << 4)
+#define VNC_TIGHT_CCB_TYPE_FILL    (0x08 << 4)
+#define VNC_TIGHT_CCB_TYPE_JPEG    (0x09 << 4)
+#define VNC_TIGHT_CCB_BASIC_MAX    (0x07 << 4)
+#define VNC_TIGHT_CCB_BASIC_ZLIB   (0x03 << 4)
+#define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
+
+/*****************************************************************************
+ *
+ * Features
+ *
+ *****************************************************************************/
+
+#define VNC_FEATURE_RESIZE                   0
+#define VNC_FEATURE_HEXTILE                  1
+#define VNC_FEATURE_POINTER_TYPE_CHANGE      2
+#define VNC_FEATURE_WMVI                     3
+#define VNC_FEATURE_TIGHT                    4
+#define VNC_FEATURE_ZLIB                     5
+#define VNC_FEATURE_COPYRECT                 6
+#define VNC_FEATURE_RICH_CURSOR              7
+
+#define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
+#define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
+#define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
+#define VNC_FEATURE_WMVI_MASK                (1 << VNC_FEATURE_WMVI)
+#define VNC_FEATURE_TIGHT_MASK               (1 << VNC_FEATURE_TIGHT)
+#define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
+#define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
+#define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
+
+
+/* Client -> Server message IDs */
+#define VNC_MSG_CLIENT_SET_PIXEL_FORMAT           0
+#define VNC_MSG_CLIENT_SET_ENCODINGS              2
+#define VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST 3
+#define VNC_MSG_CLIENT_KEY_EVENT                  4
+#define VNC_MSG_CLIENT_POINTER_EVENT              5
+#define VNC_MSG_CLIENT_CUT_TEXT                   6
+#define VNC_MSG_CLIENT_VMWARE_0                   127
+#define VNC_MSG_CLIENT_CALL_CONTROL               249
+#define VNC_MSG_CLIENT_XVP                        250
+#define VNC_MSG_CLIENT_SET_DESKTOP_SIZE           251
+#define VNC_MSG_CLIENT_TIGHT                      252
+#define VNC_MSG_CLIENT_GII                        253
+#define VNC_MSG_CLIENT_VMWARE_1                   254
+#define VNC_MSG_CLIENT_QEMU                       255
+
+/* Server -> Client message IDs */
+#define VNC_MSG_SERVER_FRAMEBUFFER_UPDATE         0
+#define VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES     1
+#define VNC_MSG_SERVER_BELL                       2
+#define VNC_MSG_SERVER_CUT_TEXT                   3
+#define VNC_MSG_SERVER_VMWARE_0                   127
+#define VNC_MSG_SERVER_CALL_CONTROL               249
+#define VNC_MSG_SERVER_XVP                        250
+#define VNC_MSG_SERVER_TIGHT                      252
+#define VNC_MSG_SERVER_GII                        253
+#define VNC_MSG_SERVER_VMWARE_1                   254
+#define VNC_MSG_SERVER_QEMU                       255
+
+
+
+/* QEMU client -> server message IDs */
+#define VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT         0
+#define VNC_MSG_CLIENT_QEMU_AUDIO                 1
+
+/* QEMU server -> client message IDs */
+#define VNC_MSG_SERVER_QEMU_AUDIO                 1
+
+
+
+/* QEMU client -> server audio message IDs */
+#define VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE          0
+#define VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE         1
+#define VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT      2
+
+/* QEMU server -> client audio message IDs */
+#define VNC_MSG_SERVER_QEMU_AUDIO_END             0
+#define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN           1
+#define VNC_MSG_SERVER_QEMU_AUDIO_DATA            2
+
+
+/*****************************************************************************
+ *
+ * Internal APIs
+ *
+ *****************************************************************************/
+
+/* Event loop functions */
+void vnc_client_read(void *opaque);
+void vnc_client_write(void *opaque);
+
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
+
+/* Protocol I/O functions */
+void vnc_write(VncState *vs, const void *data, size_t len);
+void vnc_write_u32(VncState *vs, uint32_t value);
+void vnc_write_s32(VncState *vs, int32_t value);
+void vnc_write_u16(VncState *vs, uint16_t value);
+void vnc_write_u8(VncState *vs, uint8_t value);
+void vnc_flush(VncState *vs);
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
+
+
+/* Buffer I/O functions */
+uint8_t read_u8(uint8_t *data, size_t offset);
+uint16_t read_u16(uint8_t *data, size_t offset);
+int32_t read_s32(uint8_t *data, size_t offset);
+uint32_t read_u32(uint8_t *data, size_t offset);
+
+/* Protocol stage functions */
+void vnc_client_error(VncState *vs);
+int vnc_client_io_error(VncState *vs, int ret, int last_errno);
+
+void start_client_init(VncState *vs);
+void start_auth_vnc(VncState *vs);
+
+/* Buffer management */
+void buffer_reserve(Buffer *buffer, size_t len);
+int buffer_empty(Buffer *buffer);
+uint8_t *buffer_end(Buffer *buffer);
+void buffer_reset(Buffer *buffer);
+void buffer_free(Buffer *buffer);
+void buffer_append(Buffer *buffer, const void *data, size_t len);
+
+
+/* Misc helpers */
+
+char *vnc_socket_local_addr(const char *format, int fd);
+char *vnc_socket_remote_addr(const char *format, int fd);
+
+/* Framebuffer */
+void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+                            int32_t encoding);
+
+void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
+
+/* Encodings */
+int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+
+int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
+                                         int y, int w, int h);
+void vnc_hextile_set_pixel_conversion(VncState *vs, int generic);
+
+void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size);
+void vnc_zlib_zfree(void *x, void *addr);
+int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+void vnc_zlib_clear(VncState *vs);
+
+
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+void vnc_tight_clear(VncState *vs);
+
+#endif /* __QEMU_VNC_H */
diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h
new file mode 100644 (file)
index 0000000..55cb87e
--- /dev/null
@@ -0,0 +1,324 @@
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                0x020},
+    { "exclam",               0x021},
+    { "quotedbl",             0x022},
+    { "numbersign",           0x023},
+    { "dollar",               0x024},
+    { "percent",              0x025},
+    { "ampersand",            0x026},
+    { "apostrophe",           0x027},
+    { "parenleft",            0x028},
+    { "parenright",           0x029},
+    { "asterisk",             0x02a},
+    { "plus",                 0x02b},
+    { "comma",                0x02c},
+    { "minus",                0x02d},
+    { "period",               0x02e},
+    { "slash",                0x02f},
+    { "0",                    0x030},
+    { "1",                    0x031},
+    { "2",                    0x032},
+    { "3",                    0x033},
+    { "4",                    0x034},
+    { "5",                    0x035},
+    { "6",                    0x036},
+    { "7",                    0x037},
+    { "8",                    0x038},
+    { "9",                    0x039},
+    { "colon",                0x03a},
+    { "semicolon",            0x03b},
+    { "less",                 0x03c},
+    { "equal",                0x03d},
+    { "greater",              0x03e},
+    { "question",             0x03f},
+    { "at",                   0x040},
+    { "A",                    0x041},
+    { "B",                    0x042},
+    { "C",                    0x043},
+    { "D",                    0x044},
+    { "E",                    0x045},
+    { "F",                    0x046},
+    { "G",                    0x047},
+    { "H",                    0x048},
+    { "I",                    0x049},
+    { "J",                    0x04a},
+    { "K",                    0x04b},
+    { "L",                    0x04c},
+    { "M",                    0x04d},
+    { "N",                    0x04e},
+    { "O",                    0x04f},
+    { "P",                    0x050},
+    { "Q",                    0x051},
+    { "R",                    0x052},
+    { "S",                    0x053},
+    { "T",                    0x054},
+    { "U",                    0x055},
+    { "V",                    0x056},
+    { "W",                    0x057},
+    { "X",                    0x058},
+    { "Y",                    0x059},
+    { "Z",                    0x05a},
+    { "bracketleft",          0x05b},
+    { "backslash",            0x05c},
+    { "bracketright",         0x05d},
+    { "asciicircum",          0x05e},
+    { "underscore",           0x05f},
+    { "grave",                0x060},
+    { "a",                    0x061},
+    { "b",                    0x062},
+    { "c",                    0x063},
+    { "d",                    0x064},
+    { "e",                    0x065},
+    { "f",                    0x066},
+    { "g",                    0x067},
+    { "h",                    0x068},
+    { "i",                    0x069},
+    { "j",                    0x06a},
+    { "k",                    0x06b},
+    { "l",                    0x06c},
+    { "m",                    0x06d},
+    { "n",                    0x06e},
+    { "o",                    0x06f},
+    { "p",                    0x070},
+    { "q",                    0x071},
+    { "r",                    0x072},
+    { "s",                    0x073},
+    { "t",                    0x074},
+    { "u",                    0x075},
+    { "v",                    0x076},
+    { "w",                    0x077},
+    { "x",                    0x078},
+    { "y",                    0x079},
+    { "z",                    0x07a},
+    { "braceleft",            0x07b},
+    { "bar",                  0x07c},
+    { "braceright",           0x07d},
+    { "asciitilde",           0x07e},
+
+/* latin 1 extensions */
+{ "nobreakspace",         0x0a0},
+{ "exclamdown",           0x0a1},
+{ "cent",                0x0a2},
+{ "sterling",             0x0a3},
+{ "currency",             0x0a4},
+{ "yen",                  0x0a5},
+{ "brokenbar",            0x0a6},
+{ "section",              0x0a7},
+{ "diaeresis",            0x0a8},
+{ "copyright",            0x0a9},
+{ "ordfeminine",          0x0aa},
+{ "guillemotleft",        0x0ab},
+{ "notsign",              0x0ac},
+{ "hyphen",               0x0ad},
+{ "registered",           0x0ae},
+{ "macron",               0x0af},
+{ "degree",               0x0b0},
+{ "plusminus",            0x0b1},
+{ "twosuperior",          0x0b2},
+{ "threesuperior",        0x0b3},
+{ "acute",                0x0b4},
+{ "mu",                   0x0b5},
+{ "paragraph",            0x0b6},
+{ "periodcentered",       0x0b7},
+{ "cedilla",              0x0b8},
+{ "onesuperior",          0x0b9},
+{ "masculine",            0x0ba},
+{ "guillemotright",       0x0bb},
+{ "onequarter",           0x0bc},
+{ "onehalf",              0x0bd},
+{ "threequarters",        0x0be},
+{ "questiondown",         0x0bf},
+{ "Agrave",               0x0c0},
+{ "Aacute",               0x0c1},
+{ "Acircumflex",          0x0c2},
+{ "Atilde",               0x0c3},
+{ "Adiaeresis",           0x0c4},
+{ "Aring",                0x0c5},
+{ "AE",                   0x0c6},
+{ "Ccedilla",             0x0c7},
+{ "Egrave",               0x0c8},
+{ "Eacute",               0x0c9},
+{ "Ecircumflex",          0x0ca},
+{ "Ediaeresis",           0x0cb},
+{ "Igrave",               0x0cc},
+{ "Iacute",               0x0cd},
+{ "Icircumflex",          0x0ce},
+{ "Idiaeresis",           0x0cf},
+{ "ETH",                  0x0d0},
+{ "Eth",                  0x0d0},
+{ "Ntilde",               0x0d1},
+{ "Ograve",               0x0d2},
+{ "Oacute",               0x0d3},
+{ "Ocircumflex",          0x0d4},
+{ "Otilde",               0x0d5},
+{ "Odiaeresis",           0x0d6},
+{ "multiply",             0x0d7},
+{ "Ooblique",             0x0d8},
+{ "Oslash",               0x0d8},
+{ "Ugrave",               0x0d9},
+{ "Uacute",               0x0da},
+{ "Ucircumflex",          0x0db},
+{ "Udiaeresis",           0x0dc},
+{ "Yacute",               0x0dd},
+{ "THORN",                0x0de},
+{ "Thorn",                0x0de},
+{ "ssharp",               0x0df},
+{ "agrave",               0x0e0},
+{ "aacute",               0x0e1},
+{ "acircumflex",          0x0e2},
+{ "atilde",               0x0e3},
+{ "adiaeresis",           0x0e4},
+{ "aring",                0x0e5},
+{ "ae",                   0x0e6},
+{ "ccedilla",             0x0e7},
+{ "egrave",               0x0e8},
+{ "eacute",               0x0e9},
+{ "ecircumflex",          0x0ea},
+{ "ediaeresis",           0x0eb},
+{ "igrave",               0x0ec},
+{ "iacute",               0x0ed},
+{ "icircumflex",          0x0ee},
+{ "idiaeresis",           0x0ef},
+{ "eth",                  0x0f0},
+{ "ntilde",               0x0f1},
+{ "ograve",               0x0f2},
+{ "oacute",               0x0f3},
+{ "ocircumflex",          0x0f4},
+{ "otilde",               0x0f5},
+{ "odiaeresis",           0x0f6},
+{ "division",             0x0f7},
+{ "oslash",               0x0f8},
+{ "ooblique",             0x0f8},
+{ "ugrave",               0x0f9},
+{ "uacute",               0x0fa},
+{ "ucircumflex",          0x0fb},
+{ "udiaeresis",           0x0fc},
+{ "yacute",               0x0fd},
+{ "thorn",                0x0fe},
+{ "ydiaeresis",           0x0ff},
+{"EuroSign", 0x20ac},  /* XK_EuroSign */
+
+    /* modifiers */
+{"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */
+{"Control_L", 0xffe3}, /* XK_Control_L */
+{"Control_R", 0xffe4}, /* XK_Control_R */
+{"Alt_L", 0xffe9},     /* XK_Alt_L */
+{"Alt_R", 0xffea},     /* XK_Alt_R */
+{"Caps_Lock", 0xffe5}, /* XK_Caps_Lock */
+{"Meta_L", 0xffe7},    /* XK_Meta_L */
+{"Meta_R", 0xffe8},    /* XK_Meta_R */
+{"Shift_L", 0xffe1},   /* XK_Shift_L */
+{"Shift_R", 0xffe2},   /* XK_Shift_R */
+{"Super_L", 0xffeb},   /* XK_Super_L */
+{"Super_R", 0xffec},   /* XK_Super_R */
+
+    /* special keys */
+{"BackSpace", 0xff08}, /* XK_BackSpace */
+{"Tab", 0xff09},       /* XK_Tab */
+{"Return", 0xff0d},    /* XK_Return */
+{"Right", 0xff53},     /* XK_Right */
+{"Left", 0xff51},      /* XK_Left */
+{"Up", 0xff52},        /* XK_Up */
+{"Down", 0xff54},      /* XK_Down */
+{"Page_Down", 0xff56}, /* XK_Page_Down */
+{"Page_Up", 0xff55},   /* XK_Page_Up */
+{"Insert", 0xff63},    /* XK_Insert */
+{"Delete", 0xffff},    /* XK_Delete */
+{"Home", 0xff50},      /* XK_Home */
+{"End", 0xff57},       /* XK_End */
+{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"KP_Home", 0xff95},
+{"KP_Left", 0xff96},
+{"KP_Up", 0xff97},
+{"KP_Right", 0xff98},
+{"KP_Down", 0xff99},
+{"KP_Prior", 0xff9a},
+{"KP_Page_Up", 0xff9a},
+{"KP_Next", 0xff9b},
+{"KP_Page_Down", 0xff9b},
+{"KP_End", 0xff9c},
+{"KP_Begin", 0xff9d},
+{"KP_Insert", 0xff9e},
+{"KP_Delete", 0xff9f},
+{"F1", 0xffbe},        /* XK_F1 */
+{"F2", 0xffbf},        /* XK_F2 */
+{"F3", 0xffc0},        /* XK_F3 */
+{"F4", 0xffc1},        /* XK_F4 */
+{"F5", 0xffc2},        /* XK_F5 */
+{"F6", 0xffc3},        /* XK_F6 */
+{"F7", 0xffc4},        /* XK_F7 */
+{"F8", 0xffc5},        /* XK_F8 */
+{"F9", 0xffc6},        /* XK_F9 */
+{"F10", 0xffc7},       /* XK_F10 */
+{"F11", 0xffc8},       /* XK_F11 */
+{"F12", 0xffc9},       /* XK_F12 */
+{"F13", 0xffca},       /* XK_F13 */
+{"F14", 0xffcb},       /* XK_F14 */
+{"F15", 0xffcc},       /* XK_F15 */
+{"Sys_Req", 0xff15},   /* XK_Sys_Req */
+{"KP_0", 0xffb0},      /* XK_KP_0 */
+{"KP_1", 0xffb1},      /* XK_KP_1 */
+{"KP_2", 0xffb2},      /* XK_KP_2 */
+{"KP_3", 0xffb3},      /* XK_KP_3 */
+{"KP_4", 0xffb4},      /* XK_KP_4 */
+{"KP_5", 0xffb5},      /* XK_KP_5 */
+{"KP_6", 0xffb6},      /* XK_KP_6 */
+{"KP_7", 0xffb7},      /* XK_KP_7 */
+{"KP_8", 0xffb8},      /* XK_KP_8 */
+{"KP_9", 0xffb9},      /* XK_KP_9 */
+{"KP_Add", 0xffab},    /* XK_KP_Add */
+{"KP_Separator", 0xffac},/* XK_KP_Separator */
+{"KP_Decimal", 0xffae},  /* XK_KP_Decimal */
+{"KP_Divide", 0xffaf},   /* XK_KP_Divide */
+{"KP_Enter", 0xff8d},    /* XK_KP_Enter */
+{"KP_Equal", 0xffbd},    /* XK_KP_Equal */
+{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */
+{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */
+{"help", 0xff6a},        /* XK_Help */
+{"Menu", 0xff67},        /* XK_Menu */
+{"Print", 0xff61},       /* XK_Print */
+{"Mode_switch", 0xff7e}, /* XK_Mode_switch */
+{"Num_Lock", 0xff7f},    /* XK_Num_Lock */
+{"Pause", 0xff13},       /* XK_Pause */
+{"Escape", 0xff1b},      /* XK_Escape */
+
+/* dead keys */
+{"dead_grave", 0xfe50}, /* XK_dead_grave */
+{"dead_acute", 0xfe51}, /* XK_dead_acute */
+{"dead_circumflex", 0xfe52}, /* XK_dead_circumflex */
+{"dead_tilde", 0xfe53}, /* XK_dead_tilde */
+{"dead_macron", 0xfe54}, /* XK_dead_macron */
+{"dead_breve", 0xfe55}, /* XK_dead_breve */
+{"dead_abovedot", 0xfe56}, /* XK_dead_abovedot */
+{"dead_diaeresis", 0xfe57}, /* XK_dead_diaeresis */
+{"dead_abovering", 0xfe58}, /* XK_dead_abovering */
+{"dead_doubleacute", 0xfe59}, /* XK_dead_doubleacute */
+{"dead_caron", 0xfe5a}, /* XK_dead_caron */
+{"dead_cedilla", 0xfe5b}, /* XK_dead_cedilla */
+{"dead_ogonek", 0xfe5c}, /* XK_dead_ogonek */
+{"dead_iota", 0xfe5d}, /* XK_dead_iota */
+{"dead_voiced_sound", 0xfe5e}, /* XK_dead_voiced_sound */
+{"dead_semivoiced_sound", 0xfe5f}, /* XK_dead_semivoiced_sound */
+{"dead_belowdot", 0xfe60}, /* XK_dead_belowdot */
+{"dead_hook", 0xfe61}, /* XK_dead_hook */
+{"dead_horn", 0xfe62}, /* XK_dead_horn */
+
+
+    /* localized keys */
+{"BackApostrophe", 0xff21},
+{"Muhenkan", 0xff22},
+{"Katakana", 0xff27},
+{"Hankaku", 0xff29},
+{"Zenkaku_Hankaku", 0xff2a},
+{"Henkan_Mode_Real", 0xff23},
+{"Henkan_Mode_Ultra", 0xff3e},
+{"backslash_ja", 0xffa5},
+{"Katakana_Real", 0xff25},
+{"Eisu_toggle", 0xff30},
+
+{NULL,0},
+};
diff --git a/ui/vnchextile.h b/ui/vnchextile.h
new file mode 100644 (file)
index 0000000..b9f9f5e
--- /dev/null
@@ -0,0 +1,211 @@
+#define CONCAT_I(a, b) a ## b
+#define CONCAT(a, b) CONCAT_I(a, b)
+#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
+#ifdef GENERIC
+#define NAME CONCAT(generic_, BPP)
+#else
+#define NAME BPP
+#endif
+
+static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
+                                             int x, int y, int w, int h,
+                                             void *last_bg_,
+                                             void *last_fg_,
+                                             int *has_bg, int *has_fg)
+{
+    VncDisplay *vd = vs->vd;
+    uint8_t *row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    pixel_t *irow = (pixel_t *)row;
+    int j, i;
+    pixel_t *last_bg = (pixel_t *)last_bg_;
+    pixel_t *last_fg = (pixel_t *)last_fg_;
+    pixel_t bg = 0;
+    pixel_t fg = 0;
+    int n_colors = 0;
+    int bg_count = 0;
+    int fg_count = 0;
+    int flags = 0;
+    uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
+    int n_data = 0;
+    int n_subtiles = 0;
+
+    for (j = 0; j < h; j++) {
+       for (i = 0; i < w; i++) {
+           switch (n_colors) {
+           case 0:
+               bg = irow[i];
+               n_colors = 1;
+               break;
+           case 1:
+               if (irow[i] != bg) {
+                   fg = irow[i];
+                   n_colors = 2;
+               }
+               break;
+           case 2:
+               if (irow[i] != bg && irow[i] != fg) {
+                   n_colors = 3;
+               } else {
+                   if (irow[i] == bg)
+                       bg_count++;
+                   else if (irow[i] == fg)
+                       fg_count++;
+               }
+               break;
+           default:
+               break;
+           }
+       }
+       if (n_colors > 2)
+           break;
+       irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+    }
+
+    if (n_colors > 1 && fg_count > bg_count) {
+       pixel_t tmp = fg;
+       fg = bg;
+       bg = tmp;
+    }
+
+    if (!*has_bg || *last_bg != bg) {
+       flags |= 0x02;
+       *has_bg = 1;
+       *last_bg = bg;
+    }
+
+    if (n_colors < 3 && (!*has_fg || *last_fg != fg)) {
+       flags |= 0x04;
+       *has_fg = 1;
+       *last_fg = fg;
+    }
+
+    switch (n_colors) {
+    case 1:
+       n_data = 0;
+       break;
+    case 2:
+       flags |= 0x08;
+
+       irow = (pixel_t *)row;
+
+       for (j = 0; j < h; j++) {
+           int min_x = -1;
+           for (i = 0; i < w; i++) {
+               if (irow[i] == fg) {
+                   if (min_x == -1)
+                       min_x = i;
+               } else if (min_x != -1) {
+                   hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+                   n_data += 2;
+                   n_subtiles++;
+                   min_x = -1;
+               }
+           }
+           if (min_x != -1) {
+               hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+               n_data += 2;
+               n_subtiles++;
+           }
+           irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+       }
+       break;
+    case 3:
+       flags |= 0x18;
+
+       irow = (pixel_t *)row;
+
+       if (!*has_bg || *last_bg != bg)
+           flags |= 0x02;
+
+       for (j = 0; j < h; j++) {
+           int has_color = 0;
+           int min_x = -1;
+           pixel_t color = 0; /* shut up gcc */
+
+           for (i = 0; i < w; i++) {
+               if (!has_color) {
+                   if (irow[i] == bg)
+                       continue;
+                   color = irow[i];
+                   min_x = i;
+                   has_color = 1;
+               } else if (irow[i] != color) {
+                   has_color = 0;
+#ifdef GENERIC
+                    vnc_convert_pixel(vs, data + n_data, color);
+                    n_data += vs->clientds.pf.bytes_per_pixel;
+#else
+                   memcpy(data + n_data, &color, sizeof(color));
+                    n_data += sizeof(pixel_t);
+#endif
+                   hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+                   n_data += 2;
+                   n_subtiles++;
+
+                   min_x = -1;
+                   if (irow[i] != bg) {
+                       color = irow[i];
+                       min_x = i;
+                       has_color = 1;
+                   }
+               }
+           }
+           if (has_color) {
+#ifdef GENERIC
+                vnc_convert_pixel(vs, data + n_data, color);
+                n_data += vs->clientds.pf.bytes_per_pixel;
+#else
+                memcpy(data + n_data, &color, sizeof(color));
+                n_data += sizeof(pixel_t);
+#endif
+               hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+               n_data += 2;
+               n_subtiles++;
+           }
+           irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+       }
+
+       /* A SubrectsColoured subtile invalidates the foreground color */
+       *has_fg = 0;
+       if (n_data > (w * h * sizeof(pixel_t))) {
+           n_colors = 4;
+           flags = 0x01;
+           *has_bg = 0;
+
+           /* we really don't have to invalidate either the bg or fg
+              but we've lost the old values.  oh well. */
+       }
+    default:
+       break;
+    }
+
+    if (n_colors > 3) {
+       flags = 0x01;
+       *has_fg = 0;
+       *has_bg = 0;
+       n_colors = 4;
+    }
+
+    vnc_write_u8(vs, flags);
+    if (n_colors < 4) {
+       if (flags & 0x02)
+           vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
+       if (flags & 0x04)
+           vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
+       if (n_subtiles) {
+           vnc_write_u8(vs, n_subtiles);
+           vnc_write(vs, data, n_data);
+       }
+    } else {
+       for (j = 0; j < h; j++) {
+           vs->write_pixels(vs, &vd->server->pf, row,
+                             w * ds_get_bytes_per_pixel(vs->ds));
+           row += ds_get_linesize(vs->ds);
+       }
+    }
+}
+
+#undef NAME
+#undef pixel_t
+#undef CONCAT_I
+#undef CONCAT
diff --git a/ui/x_keymap.c b/ui/x_keymap.c
new file mode 100644 (file)
index 0000000..b9b0944
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * QEMU SDL display driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "x_keymap.h"
+
+static const uint8_t x_keycode_to_pc_keycode[115] = {
+   0xc7,      /*  97  Home   */
+   0xc8,      /*  98  Up     */
+   0xc9,      /*  99  PgUp   */
+   0xcb,      /* 100  Left   */
+   0x4c,        /* 101  KP-5   */
+   0xcd,      /* 102  Right  */
+   0xcf,      /* 103  End    */
+   0xd0,      /* 104  Down   */
+   0xd1,      /* 105  PgDn   */
+   0xd2,      /* 106  Ins    */
+   0xd3,      /* 107  Del    */
+   0x9c,      /* 108  Enter  */
+   0x9d,      /* 109  Ctrl-R */
+   0x0,       /* 110  Pause  */
+   0xb7,      /* 111  Print  */
+   0xb5,      /* 112  Divide */
+   0xb8,      /* 113  Alt-R  */
+   0xc6,      /* 114  Break  */
+   0x0,         /* 115 */
+   0x0,         /* 116 */
+   0x0,         /* 117 */
+   0x0,         /* 118 */
+   0x0,         /* 119 */
+   0x0,         /* 120 */
+   0x0,         /* 121 */
+   0x0,         /* 122 */
+   0x0,         /* 123 */
+   0x0,         /* 124 */
+   0x0,         /* 125 */
+   0x0,         /* 126 */
+   0x0,         /* 127 */
+   0x0,         /* 128 */
+   0x79,         /* 129 Henkan */
+   0x0,         /* 130 */
+   0x7b,         /* 131 Muhenkan */
+   0x0,         /* 132 */
+   0x7d,         /* 133 Yen */
+   0x0,         /* 134 */
+   0x0,         /* 135 */
+   0x47,         /* 136 KP_7 */
+   0x48,         /* 137 KP_8 */
+   0x49,         /* 138 KP_9 */
+   0x4b,         /* 139 KP_4 */
+   0x4c,         /* 140 KP_5 */
+   0x4d,         /* 141 KP_6 */
+   0x4f,         /* 142 KP_1 */
+   0x50,         /* 143 KP_2 */
+   0x51,         /* 144 KP_3 */
+   0x52,         /* 145 KP_0 */
+   0x53,         /* 146 KP_. */
+   0x47,         /* 147 KP_HOME */
+   0x48,         /* 148 KP_UP */
+   0x49,         /* 149 KP_PgUp */
+   0x4b,         /* 150 KP_Left */
+   0x4c,         /* 151 KP_ */
+   0x4d,         /* 152 KP_Right */
+   0x4f,         /* 153 KP_End */
+   0x50,         /* 154 KP_Down */
+   0x51,         /* 155 KP_PgDn */
+   0x52,         /* 156 KP_Ins */
+   0x53,         /* 157 KP_Del */
+};
+
+/* This table is generated based off the xfree86 -> scancode mapping above
+ * and the keycode mappings in /usr/share/X11/xkb/keycodes/evdev
+ * and  /usr/share/X11/xkb/keycodes/xfree86
+ */
+
+static const uint8_t evdev_keycode_to_pc_keycode[61] = {
+    0,         /*  97 EVDEV - RO   ("Internet" Keyboards) */
+    0,         /*  98 EVDEV - KATA (Katakana) */
+    0,         /*  99 EVDEV - HIRA (Hiragana) */
+    0x79,      /* 100 EVDEV - HENK (Henkan) */
+    0x70,      /* 101 EVDEV - HKTG (Hiragana/Katakana toggle) */
+    0x7b,      /* 102 EVDEV - MUHE (Muhenkan) */
+    0,         /* 103 EVDEV - JPCM (KPJPComma) */
+    0x9c,      /* 104 KPEN */
+    0x9d,      /* 105 RCTL */
+    0xb5,      /* 106 KPDV */
+    0xb7,      /* 107 PRSC */
+    0xb8,      /* 108 RALT */
+    0,         /* 109 EVDEV - LNFD ("Internet" Keyboards) */
+    0xc7,      /* 110 HOME */
+    0xc8,      /* 111 UP */
+    0xc9,      /* 112 PGUP */
+    0xcb,      /* 113 LEFT */
+    0xcd,      /* 114 RGHT */
+    0xcf,      /* 115 END */
+    0xd0,      /* 116 DOWN */
+    0xd1,      /* 117 PGDN */
+    0xd2,      /* 118 INS */
+    0xd3,      /* 119 DELE */
+    0,         /* 120 EVDEV - I120 ("Internet" Keyboards) */
+    0,         /* 121 EVDEV - MUTE */
+    0,         /* 122 EVDEV - VOL- */
+    0,         /* 123 EVDEV - VOL+ */
+    0,         /* 124 EVDEV - POWR */
+    0,         /* 125 EVDEV - KPEQ */
+    0,         /* 126 EVDEV - I126 ("Internet" Keyboards) */
+    0,         /* 127 EVDEV - PAUS */
+    0,         /* 128 EVDEV - ???? */
+    0,         /* 129 EVDEV - I129 ("Internet" Keyboards) */
+    0xf1,      /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
+    0xf2,      /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
+    0x7d,      /* 132 AE13 (Yen)*/
+    0xdb,      /* 133 EVDEV - LWIN */
+    0xdc,      /* 134 EVDEV - RWIN */
+    0xdd,      /* 135 EVDEV - MENU */
+    0,         /* 136 EVDEV - STOP */
+    0,         /* 137 EVDEV - AGAI */
+    0,         /* 138 EVDEV - PROP */
+    0,         /* 139 EVDEV - UNDO */
+    0,         /* 140 EVDEV - FRNT */
+    0,         /* 141 EVDEV - COPY */
+    0,         /* 142 EVDEV - OPEN */
+    0,         /* 143 EVDEV - PAST */
+    0,         /* 144 EVDEV - FIND */
+    0,         /* 145 EVDEV - CUT  */
+    0,         /* 146 EVDEV - HELP */
+    0,         /* 147 EVDEV - I147 */
+    0,         /* 148 EVDEV - I148 */
+    0,         /* 149 EVDEV - I149 */
+    0,         /* 150 EVDEV - I150 */
+    0,         /* 151 EVDEV - I151 */
+    0,         /* 152 EVDEV - I152 */
+    0,         /* 153 EVDEV - I153 */
+    0,         /* 154 EVDEV - I154 */
+    0,         /* 155 EVDEV - I156 */
+    0,         /* 156 EVDEV - I157 */
+    0,         /* 157 EVDEV - I158 */
+};
+
+uint8_t translate_xfree86_keycode(const int key)
+{
+    return x_keycode_to_pc_keycode[key];
+}
+
+uint8_t translate_evdev_keycode(const int key)
+{
+    return evdev_keycode_to_pc_keycode[key];
+}
diff --git a/ui/x_keymap.h b/ui/x_keymap.h
new file mode 100644 (file)
index 0000000..2042ce0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * QEMU SDL display driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_X_KEYMAP_H
+#define QEMU_X_KEYMAP_H
+
+extern uint8_t translate_xfree86_keycode(const int key);
+
+extern uint8_t translate_evdev_keycode(const int key);
+
+#endif
diff --git a/vnc-auth-sasl.c b/vnc-auth-sasl.c
deleted file mode 100644 (file)
index a51ddc8..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * QEMU VNC display driver: SASL auth protocol
- *
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vnc.h"
-
-/* Max amount of data we send/recv for SASL steps to prevent DOS */
-#define SASL_DATA_MAX_LEN (1024 * 1024)
-
-
-void vnc_sasl_client_cleanup(VncState *vs)
-{
-    if (vs->sasl.conn) {
-        vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0;
-        vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
-        vs->sasl.encoded = NULL;
-        free(vs->sasl.username);
-        free(vs->sasl.mechlist);
-        vs->sasl.username = vs->sasl.mechlist = NULL;
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-    }
-}
-
-
-long vnc_client_write_sasl(VncState *vs)
-{
-    long ret;
-
-    VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
-              "Encoded: %p size %d offset %d\n",
-              vs->output.buffer, vs->output.capacity, vs->output.offset,
-              vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
-
-    if (!vs->sasl.encoded) {
-        int err;
-        err = sasl_encode(vs->sasl.conn,
-                          (char *)vs->output.buffer,
-                          vs->output.offset,
-                          (const char **)&vs->sasl.encoded,
-                          &vs->sasl.encodedLength);
-        if (err != SASL_OK)
-            return vnc_client_io_error(vs, -1, EIO);
-
-        vs->sasl.encodedOffset = 0;
-    }
-
-    ret = vnc_client_write_buf(vs,
-                               vs->sasl.encoded + vs->sasl.encodedOffset,
-                               vs->sasl.encodedLength - vs->sasl.encodedOffset);
-    if (!ret)
-        return 0;
-
-    vs->sasl.encodedOffset += ret;
-    if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
-        vs->output.offset = 0;
-        vs->sasl.encoded = NULL;
-        vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
-    }
-
-    /* Can't merge this block with one above, because
-     * someone might have written more unencrypted
-     * data in vs->output while we were processing
-     * SASL encoded output
-     */
-    if (vs->output.offset == 0) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
-    }
-
-    return ret;
-}
-
-
-long vnc_client_read_sasl(VncState *vs)
-{
-    long ret;
-    uint8_t encoded[4096];
-    const char *decoded;
-    unsigned int decodedLen;
-    int err;
-
-    ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
-    if (!ret)
-        return 0;
-
-    err = sasl_decode(vs->sasl.conn,
-                      (char *)encoded, ret,
-                      &decoded, &decodedLen);
-
-    if (err != SASL_OK)
-        return vnc_client_io_error(vs, -1, -EIO);
-    VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
-              encoded, ret, decoded, decodedLen);
-    buffer_reserve(&vs->input, decodedLen);
-    buffer_append(&vs->input, decoded, decodedLen);
-    return decodedLen;
-}
-
-
-static int vnc_auth_sasl_check_access(VncState *vs)
-{
-    const void *val;
-    int err;
-    int allow;
-
-    err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
-    if (err != SASL_OK) {
-        VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
-                  err, sasl_errstring(err, NULL, NULL));
-        return -1;
-    }
-    if (val == NULL) {
-        VNC_DEBUG("no client username was found, denying access\n");
-        return -1;
-    }
-    VNC_DEBUG("SASL client username %s\n", (const char *)val);
-
-    vs->sasl.username = qemu_strdup((const char*)val);
-
-    if (vs->vd->sasl.acl == NULL) {
-        VNC_DEBUG("no ACL activated, allowing access\n");
-        return 0;
-    }
-
-    allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
-
-    VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
-              allow ? "allowed" : "denied");
-    return allow ? 0 : -1;
-}
-
-static int vnc_auth_sasl_check_ssf(VncState *vs)
-{
-    const void *val;
-    int err, ssf;
-
-    if (!vs->sasl.wantSSF)
-        return 1;
-
-    err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
-    if (err != SASL_OK)
-        return 0;
-
-    ssf = *(const int *)val;
-    VNC_DEBUG("negotiated an SSF of %d\n", ssf);
-    if (ssf < 56)
-        return 0; /* 56 is good for Kerberos */
-
-    /* Only setup for read initially, because we're about to send an RPC
-     * reply which must be in plain text. When the next incoming RPC
-     * arrives, we'll switch on writes too
-     *
-     * cf qemudClientReadSASL  in qemud.c
-     */
-    vs->sasl.runSSF = 1;
-
-    /* We have a SSF that's good enough */
-    return 1;
-}
-
-/*
- * Step Msg
- *
- * Input from client:
- *
- * u32 clientin-length
- * u8-array clientin-string
- *
- * Output to client:
- *
- * u32 serverout-length
- * u8-array serverout-strin
- * u8 continue
- */
-
-static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
-
-static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
-{
-    uint32_t datalen = len;
-    const char *serverout;
-    unsigned int serveroutlen;
-    int err;
-    char *clientdata = NULL;
-
-    /* NB, distinction of NULL vs "" is *critical* in SASL */
-    if (datalen) {
-        clientdata = (char*)data;
-        clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
-        datalen--; /* Don't count NULL byte when passing to _start() */
-    }
-
-    VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
-              clientdata, datalen);
-    err = sasl_server_step(vs->sasl.conn,
-                           clientdata,
-                           datalen,
-                           &serverout,
-                           &serveroutlen);
-    if (err != SASL_OK &&
-        err != SASL_CONTINUE) {
-        VNC_DEBUG("sasl step failed %d (%s)\n",
-                  err, sasl_errdetail(vs->sasl.conn));
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-
-    if (serveroutlen > SASL_DATA_MAX_LEN) {
-        VNC_DEBUG("sasl step reply data too long %d\n",
-                  serveroutlen);
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-
-    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
-              serveroutlen, serverout ? 0 : 1);
-
-    if (serveroutlen) {
-        vnc_write_u32(vs, serveroutlen + 1);
-        vnc_write(vs, serverout, serveroutlen + 1);
-    } else {
-        vnc_write_u32(vs, 0);
-    }
-
-    /* Whether auth is complete */
-    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
-
-    if (err == SASL_CONTINUE) {
-        VNC_DEBUG("%s", "Authentication must continue\n");
-        /* Wait for step length */
-        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
-    } else {
-        if (!vnc_auth_sasl_check_ssf(vs)) {
-            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
-            goto authreject;
-        }
-
-        /* Check username whitelist ACL */
-        if (vnc_auth_sasl_check_access(vs) < 0) {
-            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
-            goto authreject;
-        }
-
-        VNC_DEBUG("Authentication successful %d\n", vs->csock);
-        vnc_write_u32(vs, 0); /* Accept auth */
-        /*
-         * Delay writing in SSF encoded mode until pending output
-         * buffer is written
-         */
-        if (vs->sasl.runSSF)
-            vs->sasl.waitWriteSSF = vs->output.offset;
-        start_client_init(vs);
-    }
-
-    return 0;
-
- authreject:
-    vnc_write_u32(vs, 1); /* Reject auth */
-    vnc_write_u32(vs, sizeof("Authentication failed"));
-    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
-    vnc_flush(vs);
-    vnc_client_error(vs);
-    return -1;
-
- authabort:
-    vnc_client_error(vs);
-    return -1;
-}
-
-static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
-{
-    uint32_t steplen = read_u32(data, 0);
-    VNC_DEBUG("Got client step len %d\n", steplen);
-    if (steplen > SASL_DATA_MAX_LEN) {
-        VNC_DEBUG("Too much SASL data %d\n", steplen);
-        vnc_client_error(vs);
-        return -1;
-    }
-
-    if (steplen == 0)
-        return protocol_client_auth_sasl_step(vs, NULL, 0);
-    else
-        vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
-    return 0;
-}
-
-/*
- * Start Msg
- *
- * Input from client:
- *
- * u32 clientin-length
- * u8-array clientin-string
- *
- * Output to client:
- *
- * u32 serverout-length
- * u8-array serverout-strin
- * u8 continue
- */
-
-#define SASL_DATA_MAX_LEN (1024 * 1024)
-
-static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
-{
-    uint32_t datalen = len;
-    const char *serverout;
-    unsigned int serveroutlen;
-    int err;
-    char *clientdata = NULL;
-
-    /* NB, distinction of NULL vs "" is *critical* in SASL */
-    if (datalen) {
-        clientdata = (char*)data;
-        clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
-        datalen--; /* Don't count NULL byte when passing to _start() */
-    }
-
-    VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
-              vs->sasl.mechlist, clientdata, datalen);
-    err = sasl_server_start(vs->sasl.conn,
-                            vs->sasl.mechlist,
-                            clientdata,
-                            datalen,
-                            &serverout,
-                            &serveroutlen);
-    if (err != SASL_OK &&
-        err != SASL_CONTINUE) {
-        VNC_DEBUG("sasl start failed %d (%s)\n",
-                  err, sasl_errdetail(vs->sasl.conn));
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-    if (serveroutlen > SASL_DATA_MAX_LEN) {
-        VNC_DEBUG("sasl start reply data too long %d\n",
-                  serveroutlen);
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-
-    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
-              serveroutlen, serverout ? 0 : 1);
-
-    if (serveroutlen) {
-        vnc_write_u32(vs, serveroutlen + 1);
-        vnc_write(vs, serverout, serveroutlen + 1);
-    } else {
-        vnc_write_u32(vs, 0);
-    }
-
-    /* Whether auth is complete */
-    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
-
-    if (err == SASL_CONTINUE) {
-        VNC_DEBUG("%s", "Authentication must continue\n");
-        /* Wait for step length */
-        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
-    } else {
-        if (!vnc_auth_sasl_check_ssf(vs)) {
-            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
-            goto authreject;
-        }
-
-        /* Check username whitelist ACL */
-        if (vnc_auth_sasl_check_access(vs) < 0) {
-            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
-            goto authreject;
-        }
-
-        VNC_DEBUG("Authentication successful %d\n", vs->csock);
-        vnc_write_u32(vs, 0); /* Accept auth */
-        start_client_init(vs);
-    }
-
-    return 0;
-
- authreject:
-    vnc_write_u32(vs, 1); /* Reject auth */
-    vnc_write_u32(vs, sizeof("Authentication failed"));
-    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
-    vnc_flush(vs);
-    vnc_client_error(vs);
-    return -1;
-
- authabort:
-    vnc_client_error(vs);
-    return -1;
-}
-
-static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
-{
-    uint32_t startlen = read_u32(data, 0);
-    VNC_DEBUG("Got client start len %d\n", startlen);
-    if (startlen > SASL_DATA_MAX_LEN) {
-        VNC_DEBUG("Too much SASL data %d\n", startlen);
-        vnc_client_error(vs);
-        return -1;
-    }
-
-    if (startlen == 0)
-        return protocol_client_auth_sasl_start(vs, NULL, 0);
-
-    vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
-    return 0;
-}
-
-static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
-{
-    char *mechname = malloc(len + 1);
-    if (!mechname) {
-        VNC_DEBUG("Out of memory reading mechname\n");
-        vnc_client_error(vs);
-    }
-    strncpy(mechname, (char*)data, len);
-    mechname[len] = '\0';
-    VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
-              mechname, vs->sasl.mechlist);
-
-    if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
-        if (vs->sasl.mechlist[len] != '\0' &&
-            vs->sasl.mechlist[len] != ',') {
-            VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
-            vnc_client_error(vs);
-            return -1;
-        }
-    } else {
-        char *offset = strstr(vs->sasl.mechlist, mechname);
-        VNC_DEBUG("Two %p\n", offset);
-        if (!offset) {
-            vnc_client_error(vs);
-            return -1;
-        }
-        VNC_DEBUG("Two '%s'\n", offset);
-        if (offset[-1] != ',' ||
-            (offset[len] != '\0'&&
-             offset[len] != ',')) {
-            vnc_client_error(vs);
-            return -1;
-        }
-    }
-
-    free(vs->sasl.mechlist);
-    vs->sasl.mechlist = mechname;
-
-    VNC_DEBUG("Validated mechname '%s'\n", mechname);
-    vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
-    return 0;
-}
-
-static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
-{
-    uint32_t mechlen = read_u32(data, 0);
-    VNC_DEBUG("Got client mechname len %d\n", mechlen);
-    if (mechlen > 100) {
-        VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
-        vnc_client_error(vs);
-        return -1;
-    }
-    if (mechlen < 1) {
-        VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
-        vnc_client_error(vs);
-        return -1;
-    }
-    vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
-    return 0;
-}
-
-#define USES_X509_AUTH(vs)                              \
-    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
-
-
-void start_auth_sasl(VncState *vs)
-{
-    const char *mechlist = NULL;
-    sasl_security_properties_t secprops;
-    int err;
-    char *localAddr, *remoteAddr;
-    int mechlistlen;
-
-    VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
-
-    /* Get local & remote client addresses in form  IPADDR;PORT */
-    if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
-        goto authabort;
-
-    if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
-        free(localAddr);
-        goto authabort;
-    }
-
-    err = sasl_server_new("vnc",
-                          NULL, /* FQDN - just delegates to gethostname */
-                          NULL, /* User realm */
-                          localAddr,
-                          remoteAddr,
-                          NULL, /* Callbacks, not needed */
-                          SASL_SUCCESS_DATA,
-                          &vs->sasl.conn);
-    free(localAddr);
-    free(remoteAddr);
-    localAddr = remoteAddr = NULL;
-
-    if (err != SASL_OK) {
-        VNC_DEBUG("sasl context setup failed %d (%s)",
-                  err, sasl_errstring(err, NULL, NULL));
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-
-#ifdef CONFIG_VNC_TLS
-    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
-    if (vs->vd->auth == VNC_AUTH_VENCRYPT &&
-        vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
-        gnutls_cipher_algorithm_t cipher;
-        sasl_ssf_t ssf;
-
-        cipher = gnutls_cipher_get(vs->tls.session);
-        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
-            VNC_DEBUG("%s", "cannot TLS get cipher size\n");
-            sasl_dispose(&vs->sasl.conn);
-            vs->sasl.conn = NULL;
-            goto authabort;
-        }
-        ssf *= 8; /* tls key size is bytes, sasl wants bits */
-
-        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
-        if (err != SASL_OK) {
-            VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
-                      err, sasl_errstring(err, NULL, NULL));
-            sasl_dispose(&vs->sasl.conn);
-            vs->sasl.conn = NULL;
-            goto authabort;
-        }
-    } else
-#endif /* CONFIG_VNC_TLS */
-        vs->sasl.wantSSF = 1;
-
-    memset (&secprops, 0, sizeof secprops);
-    /* Inform SASL that we've got an external SSF layer from TLS */
-    if (strncmp(vs->vd->display, "unix:", 5) == 0
-#ifdef CONFIG_VNC_TLS
-        /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
-           is not sufficiently strong */
-        || (vs->vd->auth == VNC_AUTH_VENCRYPT &&
-            vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
-#endif /* CONFIG_VNC_TLS */
-        ) {
-        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
-        secprops.min_ssf = 0;
-        secprops.max_ssf = 0;
-        secprops.maxbufsize = 8192;
-        secprops.security_flags = 0;
-    } else {
-        /* Plain TCP, better get an SSF layer */
-        secprops.min_ssf = 56; /* Good enough to require kerberos */
-        secprops.max_ssf = 100000; /* Arbitrary big number */
-        secprops.maxbufsize = 8192;
-        /* Forbid any anonymous or trivially crackable auth */
-        secprops.security_flags =
-            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
-    }
-
-    err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
-    if (err != SASL_OK) {
-        VNC_DEBUG("cannot set SASL security props %d (%s)\n",
-                  err, sasl_errstring(err, NULL, NULL));
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-
-    err = sasl_listmech(vs->sasl.conn,
-                        NULL, /* Don't need to set user */
-                        "", /* Prefix */
-                        ",", /* Separator */
-                        "", /* Suffix */
-                        &mechlist,
-                        NULL,
-                        NULL);
-    if (err != SASL_OK) {
-        VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
-                  err, sasl_errdetail(vs->sasl.conn));
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-    VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
-
-    if (!(vs->sasl.mechlist = strdup(mechlist))) {
-        VNC_DEBUG("Out of memory");
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
-    mechlistlen = strlen(mechlist);
-    vnc_write_u32(vs, mechlistlen);
-    vnc_write(vs, mechlist, mechlistlen);
-    vnc_flush(vs);
-
-    VNC_DEBUG("Wait for client mechname length\n");
-    vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
-
-    return;
-
- authabort:
-    vnc_client_error(vs);
-    return;
-}
-
-
diff --git a/vnc-auth-sasl.h b/vnc-auth-sasl.h
deleted file mode 100644 (file)
index fd9b18a..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * QEMU VNC display driver: SASL auth protocol
- *
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-#ifndef __QEMU_VNC_AUTH_SASL_H__
-#define __QEMU_VNC_AUTH_SASL_H__
-
-
-#include <sasl/sasl.h>
-
-typedef struct VncStateSASL VncStateSASL;
-typedef struct VncDisplaySASL VncDisplaySASL;
-
-#include "acl.h"
-
-struct VncStateSASL {
-    sasl_conn_t *conn;
-    /* If we want to negotiate an SSF layer with client */
-    int wantSSF :1;
-    /* If we are now running the SSF layer */
-    int runSSF :1;
-    /*
-     * If this is non-zero, then wait for that many bytes
-     * to be written plain, before switching to SSF encoding
-     * This allows the VNC auth result to finish being
-     * written in plain.
-     */
-    unsigned int waitWriteSSF;
-
-    /*
-     * Buffering encoded data to allow more clear data
-     * to be stuffed onto the output buffer
-     */
-    const uint8_t *encoded;
-    unsigned int encodedLength;
-    unsigned int encodedOffset;
-    char *username;
-    char *mechlist;
-};
-
-struct VncDisplaySASL {
-    qemu_acl *acl;
-};
-
-void vnc_sasl_client_cleanup(VncState *vs);
-
-long vnc_client_read_sasl(VncState *vs);
-long vnc_client_write_sasl(VncState *vs);
-
-void start_auth_sasl(VncState *vs);
-
-#endif /* __QEMU_VNC_AUTH_SASL_H__ */
-
diff --git a/vnc-auth-vencrypt.c b/vnc-auth-vencrypt.c
deleted file mode 100644 (file)
index 07c1691..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * QEMU VNC display driver: VeNCrypt authentication setup
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vnc.h"
-
-
-static void start_auth_vencrypt_subauth(VncState *vs)
-{
-    switch (vs->vd->subauth) {
-    case VNC_AUTH_VENCRYPT_TLSNONE:
-    case VNC_AUTH_VENCRYPT_X509NONE:
-       VNC_DEBUG("Accept TLS auth none\n");
-       vnc_write_u32(vs, 0); /* Accept auth completion */
-       start_client_init(vs);
-       break;
-
-    case VNC_AUTH_VENCRYPT_TLSVNC:
-    case VNC_AUTH_VENCRYPT_X509VNC:
-       VNC_DEBUG("Start TLS auth VNC\n");
-       start_auth_vnc(vs);
-       break;
-
-#ifdef CONFIG_VNC_SASL
-    case VNC_AUTH_VENCRYPT_TLSSASL:
-    case VNC_AUTH_VENCRYPT_X509SASL:
-      VNC_DEBUG("Start TLS auth SASL\n");
-      return start_auth_sasl(vs);
-#endif /* CONFIG_VNC_SASL */
-
-    default: /* Should not be possible, but just in case */
-       VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth);
-       vnc_write_u8(vs, 1);
-       if (vs->minor >= 8) {
-           static const char err[] = "Unsupported authentication type";
-           vnc_write_u32(vs, sizeof(err));
-           vnc_write(vs, err, sizeof(err));
-       }
-       vnc_client_error(vs);
-    }
-}
-
-static void vnc_tls_handshake_io(void *opaque);
-
-static int vnc_start_vencrypt_handshake(struct VncState *vs) {
-    int ret;
-
-    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
-       if (!gnutls_error_is_fatal(ret)) {
-           VNC_DEBUG("Handshake interrupted (blocking)\n");
-           if (!gnutls_record_get_direction(vs->tls.session))
-               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
-           else
-               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
-           return 0;
-       }
-       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
-       vnc_client_error(vs);
-       return -1;
-    }
-
-    if (vs->vd->tls.x509verify) {
-        if (vnc_tls_validate_certificate(vs) < 0) {
-            VNC_DEBUG("Client verification failed\n");
-            vnc_client_error(vs);
-            return -1;
-        } else {
-            VNC_DEBUG("Client verification passed\n");
-        }
-    }
-
-    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
-    vs->tls.wiremode = VNC_WIREMODE_TLS;
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
-
-    start_auth_vencrypt_subauth(vs);
-
-    return 0;
-}
-
-static void vnc_tls_handshake_io(void *opaque) {
-    struct VncState *vs = (struct VncState *)opaque;
-
-    VNC_DEBUG("Handshake IO continue\n");
-    vnc_start_vencrypt_handshake(vs);
-}
-
-
-
-#define NEED_X509_AUTH(vs)                              \
-    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
-
-
-static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
-{
-    int auth = read_u32(data, 0);
-
-    if (auth != vs->vd->subauth) {
-        VNC_DEBUG("Rejecting auth %d\n", auth);
-        vnc_write_u8(vs, 0); /* Reject auth */
-        vnc_flush(vs);
-        vnc_client_error(vs);
-    } else {
-        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
-        vnc_write_u8(vs, 1); /* Accept auth */
-        vnc_flush(vs);
-
-        if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
-            VNC_DEBUG("Failed to setup TLS\n");
-            return 0;
-        }
-
-        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
-        if (vnc_start_vencrypt_handshake(vs) < 0) {
-            VNC_DEBUG("Failed to start TLS handshake\n");
-            return 0;
-        }
-    }
-    return 0;
-}
-
-static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
-{
-    if (data[0] != 0 ||
-        data[1] != 2) {
-        VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
-        vnc_write_u8(vs, 1); /* Reject version */
-        vnc_flush(vs);
-        vnc_client_error(vs);
-    } else {
-        VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
-        vnc_write_u8(vs, 0); /* Accept version */
-        vnc_write_u8(vs, 1); /* Number of sub-auths */
-        vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
-        vnc_flush(vs);
-        vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
-    }
-    return 0;
-}
-
-
-void start_auth_vencrypt(VncState *vs)
-{
-    /* Send VeNCrypt version 0.2 */
-    vnc_write_u8(vs, 0);
-    vnc_write_u8(vs, 2);
-
-    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
-}
-
diff --git a/vnc-auth-vencrypt.h b/vnc-auth-vencrypt.h
deleted file mode 100644 (file)
index 9f674c5..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * QEMU VNC display driver
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__
-#define __QEMU_VNC_AUTH_VENCRYPT_H__
-
-void start_auth_vencrypt(VncState *vs);
-
-#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
diff --git a/vnc-encoding-hextile.c b/vnc-encoding-hextile.c
deleted file mode 100644 (file)
index 728f25e..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * QEMU VNC display driver: hextile encoding
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vnc.h"
-
-static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
-{
-    ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
-    ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
-}
-
-#define BPP 8
-#include "vnchextile.h"
-#undef BPP
-
-#define BPP 16
-#include "vnchextile.h"
-#undef BPP
-
-#define BPP 32
-#include "vnchextile.h"
-#undef BPP
-
-#define GENERIC
-#define BPP 8
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
-#define BPP 16
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
-#define BPP 32
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
-                                        int y, int w, int h)
-{
-    int i, j;
-    int has_fg, has_bg;
-    uint8_t *last_fg, *last_bg;
-    VncDisplay *vd = vs->vd;
-
-    last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
-    last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
-    has_fg = has_bg = 0;
-    for (j = y; j < (y + h); j += 16) {
-        for (i = x; i < (x + w); i += 16) {
-            vs->send_hextile_tile(vs, i, j,
-                                  MIN(16, x + w - i), MIN(16, y + h - j),
-                                  last_bg, last_fg, &has_bg, &has_fg);
-        }
-    }
-    free(last_fg);
-    free(last_bg);
-
-    return 1;
-}
-
-void vnc_hextile_set_pixel_conversion(VncState *vs, int generic)
-{
-    if (!generic) {
-        switch (vs->ds->surface->pf.bits_per_pixel) {
-            case 8:
-                vs->send_hextile_tile = send_hextile_tile_8;
-                break;
-            case 16:
-                vs->send_hextile_tile = send_hextile_tile_16;
-                break;
-            case 32:
-                vs->send_hextile_tile = send_hextile_tile_32;
-                break;
-        }
-    } else {
-        switch (vs->ds->surface->pf.bits_per_pixel) {
-            case 8:
-                vs->send_hextile_tile = send_hextile_tile_generic_8;
-                break;
-            case 16:
-                vs->send_hextile_tile = send_hextile_tile_generic_16;
-                break;
-            case 32:
-                vs->send_hextile_tile = send_hextile_tile_generic_32;
-                break;
-        }
-    }
-}
diff --git a/vnc-encoding-tight.c b/vnc-encoding-tight.c
deleted file mode 100644 (file)
index c1a292b..0000000
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- * QEMU VNC display driver: tight encoding
- *
- * From libvncserver/libvncserver/tight.c
- * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
- * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-common.h"
-
-#ifdef CONFIG_VNC_JPEG
-#include <stdio.h>
-#include <jpeglib.h>
-#endif
-
-#include "bswap.h"
-#include "qdict.h"
-#include "qint.h"
-#include "vnc.h"
-#include "vnc-encoding-tight.h"
-
-/* Compression level stuff. The following array contains various
-   encoder parameters for each of 10 compression levels (0..9).
-   Last three parameters correspond to JPEG quality levels (0..9). */
-
-static const struct {
-    int max_rect_size, max_rect_width;
-    int mono_min_rect_size, gradient_min_rect_size;
-    int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level;
-    int gradient_threshold, gradient_threshold24;
-    int idx_max_colors_divisor;
-    int jpeg_quality, jpeg_threshold, jpeg_threshold24;
-} tight_conf[] = {
-    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
-    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
-    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
-    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
-    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
-    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
-    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
-    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
-    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
-    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
-};
-
-/*
- * Code to guess if given rectangle is suitable for smooth image
- * compression (by applying "gradient" filter or JPEG coder).
- */
-
-static uint
-tight_detect_smooth_image24(VncState *vs, int w, int h)
-{
-    int off;
-    int x, y, d, dx;
-    uint c;
-    uint stats[256];
-    int pixels = 0;
-    int pix, left[3];
-    uint errors;
-    unsigned char *buf = vs->tight.buffer;
-
-    /*
-     * If client is big-endian, color samples begin from the second
-     * byte (offset 1) of a 32-bit pixel value.
-     */
-    off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
-
-    memset(stats, 0, sizeof (stats));
-
-    for (y = 0, x = 0; y < h && x < w;) {
-        for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH;
-             d++) {
-            for (c = 0; c < 3; c++) {
-                left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF;
-            }
-            for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) {
-                for (c = 0; c < 3; c++) {
-                    pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
-                    stats[abs(pix - left[c])]++;
-                    left[c] = pix;
-                }
-                pixels++;
-            }
-        }
-        if (w > h) {
-            x += h;
-            y = 0;
-        } else {
-            x = 0;
-            y += w;
-        }
-    }
-
-    /* 95% smooth or more ... */
-    if (stats[0] * 33 / pixels >= 95) {
-        return 0;
-    }
-
-    errors = 0;
-    for (c = 1; c < 8; c++) {
-        errors += stats[c] * (c * c);
-        if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
-            return 0;
-        }
-    }
-    for (; c < 256; c++) {
-        errors += stats[c] * (c * c);
-    }
-    errors /= (pixels * 3 - stats[0]);
-
-    return errors;
-}
-
-#define DEFINE_DETECT_FUNCTION(bpp)                                     \
-                                                                        \
-    static uint                                                         \
-    tight_detect_smooth_image##bpp(VncState *vs, int w, int h) {        \
-        bool endian;                                                    \
-        uint##bpp##_t pix;                                              \
-        int max[3], shift[3];                                           \
-        int x, y, d, dx;                                                \
-        uint c;                                                         \
-        uint stats[256];                                                \
-        int pixels = 0;                                                 \
-        int sample, sum, left[3];                                       \
-        uint errors;                                                    \
-        unsigned char *buf = vs->tight.buffer;                          \
-                                                                        \
-        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
-                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
-                                                                        \
-                                                                        \
-        max[0] = vs->clientds.pf.rmax;                                  \
-        max[1] = vs->clientds.pf.gmax;                                  \
-        max[2] = vs->clientds.pf.bmax;                                  \
-        shift[0] = vs->clientds.pf.rshift;                              \
-        shift[1] = vs->clientds.pf.gshift;                              \
-        shift[2] = vs->clientds.pf.bshift;                              \
-                                                                        \
-        memset(stats, 0, sizeof(stats));                                \
-                                                                        \
-        y = 0, x = 0;                                                   \
-        while (y < h && x < w) {                                        \
-            for (d = 0; d < h - y &&                                    \
-                     d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) {  \
-                pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d];              \
-                if (endian) {                                           \
-                    pix = bswap_##bpp(pix);                             \
-                }                                                       \
-                for (c = 0; c < 3; c++) {                               \
-                    left[c] = (int)(pix >> shift[c] & max[c]);          \
-                }                                                       \
-                for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH;       \
-                     dx++) {                                            \
-                    pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx];       \
-                    if (endian) {                                       \
-                        pix = bswap_##bpp(pix);                         \
-                    }                                                   \
-                    sum = 0;                                            \
-                    for (c = 0; c < 3; c++) {                           \
-                        sample = (int)(pix >> shift[c] & max[c]);       \
-                        sum += abs(sample - left[c]);                   \
-                        left[c] = sample;                               \
-                    }                                                   \
-                    if (sum > 255) {                                    \
-                        sum = 255;                                      \
-                    }                                                   \
-                    stats[sum]++;                                       \
-                    pixels++;                                           \
-                }                                                       \
-            }                                                           \
-            if (w > h) {                                                \
-                x += h;                                                 \
-                y = 0;                                                  \
-            } else {                                                    \
-                x = 0;                                                  \
-                y += w;                                                 \
-            }                                                           \
-        }                                                               \
-                                                                        \
-        if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
-            return 0;                                                   \
-        }                                                               \
-                                                                        \
-        errors = 0;                                                     \
-        for (c = 1; c < 8; c++) {                                       \
-            errors += stats[c] * (c * c);                               \
-            if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {           \
-                return 0;                                               \
-            }                                                           \
-        }                                                               \
-        for (; c < 256; c++) {                                          \
-            errors += stats[c] * (c * c);                               \
-        }                                                               \
-        errors /= (pixels - stats[0]);                                  \
-                                                                        \
-        return errors;                                                  \
-    }
-
-DEFINE_DETECT_FUNCTION(16)
-DEFINE_DETECT_FUNCTION(32)
-
-static int
-tight_detect_smooth_image(VncState *vs, int w, int h)
-{
-    uint errors;
-    int compression = vs->tight_compression;
-    int quality = vs->tight_quality;
-
-    if (!vs->vd->lossy) {
-        return 0;
-    }
-
-    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
-        vs->clientds.pf.bytes_per_pixel == 1 ||
-        w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
-        return 0;
-    }
-
-    if (vs->tight_quality != -1) {
-        if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
-            return 0;
-        }
-    } else {
-        if (w * h < tight_conf[compression].gradient_min_rect_size) {
-            return 0;
-        }
-    }
-
-    if (vs->clientds.pf.bytes_per_pixel == 4) {
-        if (vs->tight_pixel24) {
-            errors = tight_detect_smooth_image24(vs, w, h);
-            if (vs->tight_quality != -1) {
-                return (errors < tight_conf[quality].jpeg_threshold24);
-            }
-            return (errors < tight_conf[compression].gradient_threshold24);
-        } else {
-            errors = tight_detect_smooth_image32(vs, w, h);
-        }
-    } else {
-        errors = tight_detect_smooth_image16(vs, w, h);
-    }
-    if (quality != -1) {
-        return (errors < tight_conf[quality].jpeg_threshold);
-    }
-    return (errors < tight_conf[compression].gradient_threshold);
-}
-
-/*
- * Code to determine how many different colors used in rectangle.
- */
-
-static void tight_palette_rgb2buf(uint32_t rgb, int bpp, uint8_t buf[6])
-{
-    memset(buf, 0, 6);
-
-    if (bpp == 32) {
-        buf[0] = ((rgb >> 24) & 0xFF);
-        buf[1] = ((rgb >> 16) & 0xFF);
-        buf[2] = ((rgb >>  8) & 0xFF);
-        buf[3] = ((rgb >>  0) & 0xFF);
-        buf[4] = ((buf[0] & 1) == 0) << 3 | ((buf[1] & 1) == 0) << 2;
-        buf[4]|= ((buf[2] & 1) == 0) << 1 | ((buf[3] & 1) == 0) << 0;
-        buf[0] |= 1;
-        buf[1] |= 1;
-        buf[2] |= 1;
-        buf[3] |= 1;
-    }
-    if (bpp == 16) {
-        buf[0] = ((rgb >> 8) & 0xFF);
-        buf[1] = ((rgb >> 0) & 0xFF);
-        buf[2] = ((buf[0] & 1) == 0) << 1 | ((buf[1] & 1) == 0) << 0;
-        buf[0] |= 1;
-        buf[1] |= 1;
-    }
-}
-
-static uint32_t tight_palette_buf2rgb(int bpp, const uint8_t *buf)
-{
-    uint32_t rgb = 0;
-
-    if (bpp == 32) {
-        rgb |= ((buf[0] & ~1) | !((buf[4] >> 3) & 1)) << 24;
-        rgb |= ((buf[1] & ~1) | !((buf[4] >> 2) & 1)) << 16;
-        rgb |= ((buf[2] & ~1) | !((buf[4] >> 1) & 1)) <<  8;
-        rgb |= ((buf[3] & ~1) | !((buf[4] >> 0) & 1)) <<  0;
-    }
-    if (bpp == 16) {
-        rgb |= ((buf[0] & ~1) | !((buf[2] >> 1) & 1)) << 8;
-        rgb |= ((buf[1] & ~1) | !((buf[2] >> 0) & 1)) << 0;
-    }
-    return rgb;
-}
-
-
-static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
-{
-    uint8_t key[6];
-    int idx = qdict_size(palette);
-    bool present;
-
-    tight_palette_rgb2buf(rgb, bpp, key);
-    present = qdict_haskey(palette, (char *)key);
-    if (idx >= max && !present) {
-        return 0;
-    }
-    if (!present) {
-        qdict_put(palette, (char *)key, qint_from_int(idx));
-    }
-    return qdict_size(palette);
-}
-
-#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
-                                                                        \
-    static int                                                          \
-    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
-                            int max, size_t count,                      \
-                            uint32_t *bg, uint32_t *fg,                 \
-                            struct QDict **palette) {                   \
-        uint##bpp##_t *data;                                            \
-        uint##bpp##_t c0, c1, ci;                                       \
-        int i, n0, n1;                                                  \
-                                                                        \
-        data = (uint##bpp##_t *)vs->tight.buffer;                       \
-                                                                        \
-        c0 = data[0];                                                   \
-        i = 1;                                                          \
-        while (i < count && data[i] == c0)                              \
-            i++;                                                        \
-        if (i >= count) {                                               \
-            *bg = *fg = c0;                                             \
-            return 1;                                                   \
-        }                                                               \
-                                                                        \
-        if (max < 2) {                                                  \
-            return 0;                                                   \
-        }                                                               \
-                                                                        \
-        n0 = i;                                                         \
-        c1 = data[i];                                                   \
-        n1 = 0;                                                         \
-        for (i++; i < count; i++) {                                     \
-            ci = data[i];                                               \
-            if (ci == c0) {                                             \
-                n0++;                                                   \
-            } else if (ci == c1) {                                      \
-                n1++;                                                   \
-            } else                                                      \
-                break;                                                  \
-        }                                                               \
-        if (i >= count) {                                               \
-            if (n0 > n1) {                                              \
-                *bg = (uint32_t)c0;                                     \
-                *fg = (uint32_t)c1;                                     \
-            } else {                                                    \
-                *bg = (uint32_t)c1;                                     \
-                *fg = (uint32_t)c0;                                     \
-            }                                                           \
-            return 2;                                                   \
-        }                                                               \
-                                                                        \
-        if (max == 2) {                                                 \
-            return 0;                                                   \
-        }                                                               \
-                                                                        \
-        *palette = qdict_new();                                         \
-        tight_palette_insert(*palette, c0, bpp, max);                   \
-        tight_palette_insert(*palette, c1, bpp, max);                   \
-        tight_palette_insert(*palette, ci, bpp, max);                   \
-                                                                        \
-        for (i++; i < count; i++) {                                     \
-            if (data[i] == ci) {                                        \
-                continue;                                               \
-            } else {                                                    \
-                if (!tight_palette_insert(*palette, (uint32_t)ci,       \
-                                          bpp, max)) {                  \
-                    return 0;                                           \
-                }                                                       \
-                ci = data[i];                                           \
-            }                                                           \
-        }                                                               \
-                                                                        \
-        return qdict_size(*palette);                                    \
-    }
-
-DEFINE_FILL_PALETTE_FUNCTION(8)
-DEFINE_FILL_PALETTE_FUNCTION(16)
-DEFINE_FILL_PALETTE_FUNCTION(32)
-
-static int tight_fill_palette(VncState *vs, int x, int y,
-                              size_t count, uint32_t *bg, uint32_t *fg,
-                              struct QDict **palette)
-{
-    int max;
-
-    max = count / tight_conf[vs->tight_compression].idx_max_colors_divisor;
-    if (max < 2 &&
-        count >= tight_conf[vs->tight_compression].mono_min_rect_size) {
-        max = 2;
-    }
-    if (max >= 256) {
-        max = 256;
-    }
-
-    switch(vs->clientds.pf.bytes_per_pixel) {
-    case 4:
-        return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
-    case 2:
-        return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
-    default:
-        max = 2;
-        return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
-    }
-    return 0;
-}
-
-/* Callback to dump a palette with qdict_iter
-static void print_palette(const char *key, QObject *obj, void *opaque)
-{
-    uint8_t idx = qint_get_int(qobject_to_qint(obj));
-    uint32_t rgb = tight_palette_buf2rgb(32, (uint8_t *)key);
-
-    fprintf(stderr, "%.2x ", (unsigned char)*key);
-    while (*key++)
-        fprintf(stderr, "%.2x ", (unsigned char)*key);
-
-    fprintf(stderr, ": idx: %x rgb: %x\n", idx, rgb);
-}
-*/
-
-/*
- * Converting truecolor samples into palette indices.
- */
-#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
-                                                                        \
-    static void                                                         \
-    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
-                                   struct QDict *palette) {             \
-        uint##bpp##_t *src;                                             \
-        uint##bpp##_t rgb;                                              \
-        uint8_t key[6];                                                 \
-        int i, rep;                                                     \
-        uint8_t idx;                                                    \
-                                                                        \
-        src = (uint##bpp##_t *) buf;                                    \
-                                                                        \
-        for (i = 0; i < count; i++) {                                   \
-            rgb = *src++;                                               \
-            rep = 0;                                                    \
-            while (i < count && *src == rgb) {                          \
-                rep++, src++, i++;                                      \
-            }                                                           \
-            tight_palette_rgb2buf(rgb, bpp, key);                       \
-            if (!qdict_haskey(palette, (char *)key)) {                  \
-                /*                                                      \
-                 * Should never happen, but don't break everything      \
-                 * if it does, use the first color instead              \
-                 */                                                     \
-                idx = 0;                                                \
-            } else {                                                    \
-                idx = qdict_get_int(palette, (char *)key);              \
-            }                                                           \
-            while (rep >= 0) {                                          \
-                *buf++ = idx;                                           \
-                rep--;                                                  \
-            }                                                           \
-        }                                                               \
-    }
-
-DEFINE_IDX_ENCODE_FUNCTION(16)
-DEFINE_IDX_ENCODE_FUNCTION(32)
-
-#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
-                                                                        \
-    static void                                                         \
-    tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h,             \
-                                uint##bpp##_t bg, uint##bpp##_t fg) {   \
-        uint##bpp##_t *ptr;                                             \
-        unsigned int value, mask;                                       \
-        int aligned_width;                                              \
-        int x, y, bg_bits;                                              \
-                                                                        \
-        ptr = (uint##bpp##_t *) buf;                                    \
-        aligned_width = w - w % 8;                                      \
-                                                                        \
-        for (y = 0; y < h; y++) {                                       \
-            for (x = 0; x < aligned_width; x += 8) {                    \
-                for (bg_bits = 0; bg_bits < 8; bg_bits++) {             \
-                    if (*ptr++ != bg) {                                 \
-                        break;                                          \
-                    }                                                   \
-                }                                                       \
-                if (bg_bits == 8) {                                     \
-                    *buf++ = 0;                                         \
-                    continue;                                           \
-                }                                                       \
-                mask = 0x80 >> bg_bits;                                 \
-                value = mask;                                           \
-                for (bg_bits++; bg_bits < 8; bg_bits++) {               \
-                    mask >>= 1;                                         \
-                    if (*ptr++ != bg) {                                 \
-                        value |= mask;                                  \
-                    }                                                   \
-                }                                                       \
-                *buf++ = (uint8_t)value;                                \
-            }                                                           \
-                                                                        \
-            mask = 0x80;                                                \
-            value = 0;                                                  \
-            if (x >= w) {                                               \
-                continue;                                               \
-            }                                                           \
-                                                                        \
-            for (; x < w; x++) {                                        \
-                if (*ptr++ != bg) {                                     \
-                    value |= mask;                                      \
-                }                                                       \
-                mask >>= 1;                                             \
-            }                                                           \
-            *buf++ = (uint8_t)value;                                    \
-        }                                                               \
-    }
-
-DEFINE_MONO_ENCODE_FUNCTION(8)
-DEFINE_MONO_ENCODE_FUNCTION(16)
-DEFINE_MONO_ENCODE_FUNCTION(32)
-
-/*
- * ``Gradient'' filter for 24-bit color samples.
- * Should be called only when redMax, greenMax and blueMax are 255.
- * Color components assumed to be byte-aligned.
- */
-
-static void
-tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
-{
-    uint32_t *buf32;
-    uint32_t pix32;
-    int shift[3];
-    int *prev;
-    int here[3], upper[3], left[3], upperleft[3];
-    int prediction;
-    int x, y, c;
-
-    buf32 = (uint32_t *)buf;
-    memset(vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));
-
-    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
-        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
-        shift[0] = vs->clientds.pf.rshift;
-        shift[1] = vs->clientds.pf.gshift;
-        shift[2] = vs->clientds.pf.bshift;
-    } else {
-        shift[0] = 24 - vs->clientds.pf.rshift;
-        shift[1] = 24 - vs->clientds.pf.gshift;
-        shift[2] = 24 - vs->clientds.pf.bshift;
-    }
-
-    for (y = 0; y < h; y++) {
-        for (c = 0; c < 3; c++) {
-            upper[c] = 0;
-            here[c] = 0;
-        }
-        prev = (int *)vs->tight_gradient.buffer;
-        for (x = 0; x < w; x++) {
-            pix32 = *buf32++;
-            for (c = 0; c < 3; c++) {
-                upperleft[c] = upper[c];
-                left[c] = here[c];
-                upper[c] = *prev;
-                here[c] = (int)(pix32 >> shift[c] & 0xFF);
-                *prev++ = here[c];
-
-                prediction = left[c] + upper[c] - upperleft[c];
-                if (prediction < 0) {
-                    prediction = 0;
-                } else if (prediction > 0xFF) {
-                    prediction = 0xFF;
-                }
-                *buf++ = (char)(here[c] - prediction);
-            }
-        }
-    }
-}
-
-
-/*
- * ``Gradient'' filter for other color depths.
- */
-
-#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                            \
-                                                                        \
-    static void                                                         \
-    tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf,        \
-                               int w, int h) {                          \
-        uint##bpp##_t pix, diff;                                        \
-        bool endian;                                                    \
-        int *prev;                                                      \
-        int max[3], shift[3];                                           \
-        int here[3], upper[3], left[3], upperleft[3];                   \
-        int prediction;                                                 \
-        int x, y, c;                                                    \
-                                                                        \
-        memset (vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));     \
-                                                                        \
-        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
-                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
-                                                                        \
-        max[0] = vs->clientds.pf.rmax;                                  \
-        max[1] = vs->clientds.pf.gmax;                                  \
-        max[2] = vs->clientds.pf.bmax;                                  \
-        shift[0] = vs->clientds.pf.rshift;                              \
-        shift[1] = vs->clientds.pf.gshift;                              \
-        shift[2] = vs->clientds.pf.bshift;                              \
-                                                                        \
-        for (y = 0; y < h; y++) {                                       \
-            for (c = 0; c < 3; c++) {                                   \
-                upper[c] = 0;                                           \
-                here[c] = 0;                                            \
-            }                                                           \
-            prev = (int *)vs->tight_gradient.buffer;                    \
-            for (x = 0; x < w; x++) {                                   \
-                pix = *buf;                                             \
-                if (endian) {                                           \
-                    pix = bswap_##bpp(pix);                             \
-                }                                                       \
-                diff = 0;                                               \
-                for (c = 0; c < 3; c++) {                               \
-                    upperleft[c] = upper[c];                            \
-                    left[c] = here[c];                                  \
-                    upper[c] = *prev;                                   \
-                    here[c] = (int)(pix >> shift[c] & max[c]);          \
-                    *prev++ = here[c];                                  \
-                                                                        \
-                    prediction = left[c] + upper[c] - upperleft[c];     \
-                    if (prediction < 0) {                               \
-                        prediction = 0;                                 \
-                    } else if (prediction > max[c]) {                   \
-                        prediction = max[c];                            \
-                    }                                                   \
-                    diff |= ((here[c] - prediction) & max[c])           \
-                        << shift[c];                                    \
-                }                                                       \
-                if (endian) {                                           \
-                    diff = bswap_##bpp(diff);                           \
-                }                                                       \
-                *buf++ = diff;                                          \
-            }                                                           \
-        }                                                               \
-    }
-
-DEFINE_GRADIENT_FILTER_FUNCTION(16)
-DEFINE_GRADIENT_FILTER_FUNCTION(32)
-
-/*
- * Check if a rectangle is all of the same color. If needSameColor is
- * set to non-zero, then also check that its color equals to the
- * *colorPtr value. The result is 1 if the test is successfull, and in
- * that case new color will be stored in *colorPtr.
- */
-
-#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                \
-                                                                        \
-    static bool                                                         \
-    check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h,     \
-                          uint32_t* color, bool samecolor)              \
-    {                                                                   \
-        VncDisplay *vd = vs->vd;                                        \
-        uint##bpp##_t *fbptr;                                           \
-        uint##bpp##_t c;                                                \
-        int dx, dy;                                                     \
-                                                                        \
-        fbptr = (uint##bpp##_t *)                                       \
-            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
-             x * ds_get_bytes_per_pixel(vs->ds));                       \
-                                                                        \
-        c = *fbptr;                                                     \
-        if (samecolor && (uint32_t)c != *color) {                       \
-            return false;                                               \
-        }                                                               \
-                                                                        \
-        for (dy = 0; dy < h; dy++) {                                    \
-            for (dx = 0; dx < w; dx++) {                                \
-                if (c != fbptr[dx]) {                                   \
-                    return false;                                       \
-                }                                                       \
-            }                                                           \
-            fbptr = (uint##bpp##_t *)                                   \
-                ((uint8_t *)fbptr + ds_get_linesize(vs->ds));           \
-        }                                                               \
-                                                                        \
-        *color = (uint32_t)c;                                           \
-        return true;                                                    \
-    }
-
-DEFINE_CHECK_SOLID_FUNCTION(32)
-DEFINE_CHECK_SOLID_FUNCTION(16)
-DEFINE_CHECK_SOLID_FUNCTION(8)
-
-static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
-                             uint32_t* color, bool samecolor)
-{
-    VncDisplay *vd = vs->vd;
-
-    switch(vd->server->pf.bytes_per_pixel) {
-    case 4:
-        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
-    case 2:
-        return check_solid_tile16(vs, x, y, w, h, color, samecolor);
-    default:
-        return check_solid_tile8(vs, x, y, w, h, color, samecolor);
-    }
-}
-
-static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
-                                 uint32_t color, int *w_ptr, int *h_ptr)
-{
-    int dx, dy, dw, dh;
-    int w_prev;
-    int w_best = 0, h_best = 0;
-
-    w_prev = w;
-
-    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
-
-        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
-        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
-
-        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
-            break;
-        }
-
-        for (dx = x + dw; dx < x + w_prev;) {
-            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
-
-            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
-                break;
-            }
-            dx += dw;
-        }
-
-        w_prev = dx - x;
-        if (w_prev * (dy + dh - y) > w_best * h_best) {
-            w_best = w_prev;
-            h_best = dy + dh - y;
-        }
-    }
-
-    *w_ptr = w_best;
-    *h_ptr = h_best;
-}
-
-static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
-                              uint32_t color, int *x_ptr, int *y_ptr,
-                              int *w_ptr, int *h_ptr)
-{
-    int cx, cy;
-
-    /* Try to extend the area upwards. */
-    for ( cy = *y_ptr - 1;
-          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
-          cy-- );
-    *h_ptr += *y_ptr - (cy + 1);
-    *y_ptr = cy + 1;
-
-    /* ... downwards. */
-    for ( cy = *y_ptr + *h_ptr;
-          cy < y + h &&
-              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
-          cy++ );
-    *h_ptr += cy - (*y_ptr + *h_ptr);
-
-    /* ... to the left. */
-    for ( cx = *x_ptr - 1;
-          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
-          cx-- );
-    *w_ptr += *x_ptr - (cx + 1);
-    *x_ptr = cx + 1;
-
-    /* ... to the right. */
-    for ( cx = *x_ptr + *w_ptr;
-          cx < x + w &&
-              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
-          cx++ );
-    *w_ptr += cx - (*x_ptr + *w_ptr);
-}
-
-static int tight_init_stream(VncState *vs, int stream_id,
-                             int level, int strategy)
-{
-    z_streamp zstream = &vs->tight_stream[stream_id];
-
-    if (zstream->opaque == NULL) {
-        int err;
-
-        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
-        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
-        zstream->zalloc = vnc_zlib_zalloc;
-        zstream->zfree = vnc_zlib_zfree;
-
-        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
-                           MAX_MEM_LEVEL, strategy);
-
-        if (err != Z_OK) {
-            fprintf(stderr, "VNC: error initializing zlib\n");
-            return -1;
-        }
-
-        vs->tight_levels[stream_id] = level;
-        zstream->opaque = vs;
-    }
-
-    if (vs->tight_levels[stream_id] != level) {
-        if (deflateParams(zstream, level, strategy) != Z_OK) {
-            return -1;
-        }
-        vs->tight_levels[stream_id] = level;
-    }
-    return 0;
-}
-
-static void tight_send_compact_size(VncState *vs, size_t len)
-{
-    int lpc = 0;
-    int bytes = 0;
-    char buf[3] = {0, 0, 0};
-
-    buf[bytes++] = len & 0x7F;
-    if (len > 0x7F) {
-        buf[bytes-1] |= 0x80;
-        buf[bytes++] = (len >> 7) & 0x7F;
-        if (len > 0x3FFF) {
-            buf[bytes-1] |= 0x80;
-            buf[bytes++] = (len >> 14) & 0xFF;
-        }
-    }
-    for (lpc = 0; lpc < bytes; lpc++) {
-        vnc_write_u8(vs, buf[lpc]);
-    }
-}
-
-static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
-                               int level, int strategy)
-{
-    z_streamp zstream = &vs->tight_stream[stream_id];
-    int previous_out;
-
-    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
-        vnc_write(vs, vs->tight.buffer, vs->tight.offset);
-        return bytes;
-    }
-
-    if (tight_init_stream(vs, stream_id, level, strategy)) {
-        return -1;
-    }
-
-    /* reserve memory in output buffer */
-    buffer_reserve(&vs->tight_zlib, bytes + 64);
-
-    /* set pointers */
-    zstream->next_in = vs->tight.buffer;
-    zstream->avail_in = vs->tight.offset;
-    zstream->next_out = vs->tight_zlib.buffer + vs->tight_zlib.offset;
-    zstream->avail_out = vs->tight_zlib.capacity - vs->tight_zlib.offset;
-    zstream->data_type = Z_BINARY;
-    previous_out = zstream->total_out;
-
-    /* start encoding */
-    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
-        fprintf(stderr, "VNC: error during tight compression\n");
-        return -1;
-    }
-
-    vs->tight_zlib.offset = vs->tight_zlib.capacity - zstream->avail_out;
-    bytes = zstream->total_out - previous_out;
-
-    tight_send_compact_size(vs, bytes);
-    vnc_write(vs, vs->tight_zlib.buffer, bytes);
-
-    buffer_reset(&vs->tight_zlib);
-
-    return bytes;
-}
-
-/*
- * Subencoding implementations.
- */
-static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
-{
-    uint32_t *buf32;
-    uint32_t pix;
-    int rshift, gshift, bshift;
-
-    buf32 = (uint32_t *)buf;
-
-    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
-        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
-        rshift = vs->clientds.pf.rshift;
-        gshift = vs->clientds.pf.gshift;
-        bshift = vs->clientds.pf.bshift;
-    } else {
-        rshift = 24 - vs->clientds.pf.rshift;
-        gshift = 24 - vs->clientds.pf.gshift;
-        bshift = 24 - vs->clientds.pf.bshift;
-    }
-
-    if (ret) {
-        *ret = count * 3;
-    }
-
-    while (count--) {
-        pix = *buf32++;
-        *buf++ = (char)(pix >> rshift);
-        *buf++ = (char)(pix >> gshift);
-        *buf++ = (char)(pix >> bshift);
-    }
-}
-
-static int send_full_color_rect(VncState *vs, int w, int h)
-{
-    int stream = 0;
-    size_t bytes;
-
-    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
-
-    if (vs->tight_pixel24) {
-        tight_pack24(vs, vs->tight.buffer, w * h, &vs->tight.offset);
-        bytes = 3;
-    } else {
-        bytes = vs->clientds.pf.bytes_per_pixel;
-    }
-
-    bytes = tight_compress_data(vs, stream, w * h * bytes,
-                                tight_conf[vs->tight_compression].raw_zlib_level,
-                                Z_DEFAULT_STRATEGY);
-
-    return (bytes >= 0);
-}
-
-static int send_solid_rect(VncState *vs)
-{
-    size_t bytes;
-
-    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
-
-    if (vs->tight_pixel24) {
-        tight_pack24(vs, vs->tight.buffer, 1, &vs->tight.offset);
-        bytes = 3;
-    } else {
-        bytes = vs->clientds.pf.bytes_per_pixel;
-    }
-
-    vnc_write(vs, vs->tight.buffer, bytes);
-    return 1;
-}
-
-static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
-{
-    size_t bytes;
-    int stream = 1;
-    int level = tight_conf[vs->tight_compression].mono_zlib_level;
-
-    bytes = ((w + 7) / 8) * h;
-
-    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
-    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
-    vnc_write_u8(vs, 1);
-
-    switch(vs->clientds.pf.bytes_per_pixel) {
-    case 4:
-    {
-        uint32_t buf[2] = {bg, fg};
-        size_t ret = sizeof (buf);
-
-        if (vs->tight_pixel24) {
-            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
-        }
-        vnc_write(vs, buf, ret);
-
-        tight_encode_mono_rect32(vs->tight.buffer, w, h, bg, fg);
-        break;
-    }
-    case 2:
-        vnc_write(vs, &bg, 2);
-        vnc_write(vs, &fg, 2);
-        tight_encode_mono_rect16(vs->tight.buffer, w, h, bg, fg);
-        break;
-    default:
-        vnc_write_u8(vs, bg);
-        vnc_write_u8(vs, fg);
-        tight_encode_mono_rect8(vs->tight.buffer, w, h, bg, fg);
-        break;
-    }
-    vs->tight.offset = bytes;
-
-    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
-    return (bytes >= 0);
-}
-
-struct palette_cb_priv {
-    VncState *vs;
-    uint8_t *header;
-};
-
-static void write_palette(const char *key, QObject *obj, void *opaque)
-{
-    struct palette_cb_priv *priv = opaque;
-    VncState *vs = priv->vs;
-    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
-    uint8_t idx = qint_get_int(qobject_to_qint(obj));
-
-    if (bytes == 4) {
-        uint32_t color = tight_palette_buf2rgb(32, (uint8_t *)key);
-
-        ((uint32_t*)priv->header)[idx] = color;
-    } else {
-        uint16_t color = tight_palette_buf2rgb(16, (uint8_t *)key);
-
-        ((uint16_t*)priv->header)[idx] = color;
-    }
-}
-
-static bool send_gradient_rect(VncState *vs, int w, int h)
-{
-    int stream = 3;
-    int level = tight_conf[vs->tight_compression].gradient_zlib_level;
-    size_t bytes;
-
-    if (vs->clientds.pf.bytes_per_pixel == 1)
-        return send_full_color_rect(vs, w, h);
-
-    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
-    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
-
-    buffer_reserve(&vs->tight_gradient, w * 3 * sizeof (int));
-
-    if (vs->tight_pixel24) {
-        tight_filter_gradient24(vs, vs->tight.buffer, w, h);
-        bytes = 3;
-    } else if (vs->clientds.pf.bytes_per_pixel == 4) {
-        tight_filter_gradient32(vs, (uint32_t *)vs->tight.buffer, w, h);
-        bytes = 4;
-    } else {
-        tight_filter_gradient16(vs, (uint16_t *)vs->tight.buffer, w, h);
-        bytes = 2;
-    }
-
-    buffer_reset(&vs->tight_gradient);
-
-    bytes = w * h * bytes;
-    vs->tight.offset = bytes;
-
-    bytes = tight_compress_data(vs, stream, bytes,
-                                level, Z_FILTERED);
-    return (bytes >= 0);
-}
-
-static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
-{
-    int stream = 2;
-    int level = tight_conf[vs->tight_compression].idx_zlib_level;
-    int colors;
-    size_t bytes;
-
-    colors = qdict_size(palette);
-
-    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
-    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
-    vnc_write_u8(vs, colors - 1);
-
-    switch(vs->clientds.pf.bytes_per_pixel) {
-    case 4:
-    {
-        size_t old_offset, offset;
-        uint32_t header[qdict_size(palette)];
-        struct palette_cb_priv priv = { vs, (uint8_t *)header };
-
-        old_offset = vs->output.offset;
-        qdict_iter(palette, write_palette, &priv);
-        vnc_write(vs, header, sizeof(header));
-
-        if (vs->tight_pixel24) {
-            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
-            vs->output.offset = old_offset + offset;
-        }
-
-        tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
-        break;
-    }
-    case 2:
-    {
-        uint16_t header[qdict_size(palette)];
-        struct palette_cb_priv priv = { vs, (uint8_t *)header };
-
-        qdict_iter(palette, write_palette, &priv);
-        vnc_write(vs, header, sizeof(header));
-        tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
-        break;
-    }
-    default:
-        return -1; /* No palette for 8bits colors */
-        break;
-    }
-    bytes = w * h;
-    vs->tight.offset = bytes;
-
-    bytes = tight_compress_data(vs, stream, bytes,
-                                level, Z_DEFAULT_STRATEGY);
-    return (bytes >= 0);
-}
-
-/*
- * JPEG compression stuff.
- */
-#ifdef CONFIG_VNC_JPEG
-static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
-                                     int count)
-{
-    VncDisplay *vd = vs->vd;
-    uint32_t *fbptr;
-    uint32_t pix;
-
-    fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) +
-                         x * ds_get_bytes_per_pixel(vs->ds));
-
-    while (count--) {
-        pix = *fbptr++;
-        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift);
-        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift);
-        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift);
-    }
-}
-
-#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                               \
-                                                                        \
-    static void                                                         \
-    jpeg_prepare_row##bpp(VncState *vs, uint8_t *dst,                   \
-                                int x, int y, int count)                \
-    {                                                                   \
-        VncDisplay *vd = vs->vd;                                        \
-        uint##bpp##_t *fbptr;                                           \
-        uint##bpp##_t pix;                                              \
-        int r, g, b;                                                    \
-                                                                        \
-        fbptr = (uint##bpp##_t *)                                       \
-            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
-             x * ds_get_bytes_per_pixel(vs->ds));                       \
-                                                                        \
-        while (count--) {                                               \
-            pix = *fbptr++;                                             \
-                                                                        \
-            r = (int)((pix >> vs->ds->surface->pf.rshift)               \
-                      & vs->ds->surface->pf.rmax);                      \
-            g = (int)((pix >> vs->ds->surface->pf.gshift)               \
-                      & vs->ds->surface->pf.gmax);                      \
-            b = (int)((pix >> vs->ds->surface->pf.bshift)               \
-                      & vs->ds->surface->pf.bmax);                      \
-                                                                        \
-            *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \
-                               / vs->ds->surface->pf.rmax);             \
-            *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \
-                               / vs->ds->surface->pf.gmax);             \
-            *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \
-                               / vs->ds->surface->pf.bmax);             \
-        }                                                               \
-    }
-
-DEFINE_JPEG_GET_ROW_FUNCTION(16)
-DEFINE_JPEG_GET_ROW_FUNCTION(32)
-
-static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
-                                       int count)
-{
-    if (vs->tight_pixel24)
-        jpeg_prepare_row24(vs, dst, x, y, count);
-    else if (ds_get_bytes_per_pixel(vs->ds) == 4)
-        jpeg_prepare_row32(vs, dst, x, y, count);
-    else
-        jpeg_prepare_row16(vs, dst, x, y, count);
-}
-
-/*
- * Destination manager implementation for JPEG library.
- */
-
-/* This is called once per encoding */
-static void jpeg_init_destination(j_compress_ptr cinfo)
-{
-    VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
-
-    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
-    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
-}
-
-/* This is called when we ran out of buffer (shouldn't happen!) */
-static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
-{
-    VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
-
-    buffer->offset = buffer->capacity;
-    buffer_reserve(buffer, 2048);
-    jpeg_init_destination(cinfo);
-    return TRUE;
-}
-
-/* This is called when we are done processing data */
-static void jpeg_term_destination(j_compress_ptr cinfo)
-{
-    VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
-
-    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
-}
-
-static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
-{
-    struct jpeg_compress_struct cinfo;
-    struct jpeg_error_mgr jerr;
-    struct jpeg_destination_mgr manager;
-    JSAMPROW row[1];
-    uint8_t *buf;
-    int dy;
-
-    if (ds_get_bytes_per_pixel(vs->ds) == 1)
-        return send_full_color_rect(vs, w, h);
-
-    buf = qemu_malloc(w * 3);
-    row[0] = buf;
-    buffer_reserve(&vs->tight_jpeg, 2048);
-
-    cinfo.err = jpeg_std_error(&jerr);
-    jpeg_create_compress(&cinfo);
-
-    cinfo.client_data = vs;
-    cinfo.image_width = w;
-    cinfo.image_height = h;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_RGB;
-
-    jpeg_set_defaults(&cinfo);
-    jpeg_set_quality(&cinfo, quality, true);
-
-    manager.init_destination = jpeg_init_destination;
-    manager.empty_output_buffer = jpeg_empty_output_buffer;
-    manager.term_destination = jpeg_term_destination;
-    cinfo.dest = &manager;
-
-    jpeg_start_compress(&cinfo, true);
-
-    for (dy = 0; dy < h; dy++) {
-        jpeg_prepare_row(vs, buf, x, y + dy, w);
-        jpeg_write_scanlines(&cinfo, row, 1);
-    }
-
-    jpeg_finish_compress(&cinfo);
-    jpeg_destroy_compress(&cinfo);
-
-    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
-
-    tight_send_compact_size(vs, vs->tight_jpeg.offset);
-    vnc_write(vs, vs->tight_jpeg.buffer, vs->tight_jpeg.offset);
-    buffer_reset(&vs->tight_jpeg);
-
-    return 1;
-}
-#endif /* CONFIG_VNC_JPEG */
-
-static void vnc_tight_start(VncState *vs)
-{
-    buffer_reset(&vs->tight);
-
-    // make the output buffer be the zlib buffer, so we can compress it later
-    vs->tight_tmp = vs->output;
-    vs->output = vs->tight;
-}
-
-static void vnc_tight_stop(VncState *vs)
-{
-    // switch back to normal output/zlib buffers
-    vs->tight = vs->output;
-    vs->output = vs->tight_tmp;
-}
-
-static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
-{
-    struct QDict *palette = NULL;
-    uint32_t bg = 0, fg = 0;
-    int colors;
-    int ret = 0;
-
-    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
-
-    vnc_tight_start(vs);
-    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
-    vnc_tight_stop(vs);
-
-    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
-
-    if (colors == 0) {
-        if (tight_detect_smooth_image(vs, w, h)) {
-            if (vs->tight_quality == -1) {
-                ret = send_gradient_rect(vs, w, h);
-            } else {
-#ifdef CONFIG_VNC_JPEG
-                int quality = tight_conf[vs->tight_quality].jpeg_quality;
-
-                ret = send_jpeg_rect(vs, x, y, w, h, quality);
-#else
-                ret = send_full_color_rect(vs, w, h);
-#endif
-            }
-        } else {
-            ret = send_full_color_rect(vs, w, h);
-        }
-    } else if (colors == 1) {
-        ret = send_solid_rect(vs);
-    } else if (colors == 2) {
-        ret = send_mono_rect(vs, w, h, bg, fg);
-    } else if (colors <= 256) {
-#ifdef CONFIG_VNC_JPEG
-        if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
-            tight_detect_smooth_image(vs, w, h)) {
-            int quality = tight_conf[vs->tight_quality].jpeg_quality;
-
-            ret = send_jpeg_rect(vs, x, y, w, h, quality);
-        } else {
-            ret = send_palette_rect(vs, w, h, palette);
-        }
-#else
-        ret = send_palette_rect(vs, w, h, palette);
-#endif
-    }
-    QDECREF(palette);
-    return ret;
-}
-
-static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
-{
-    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
-
-    vnc_tight_start(vs);
-    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
-    vnc_tight_stop(vs);
-
-    return send_solid_rect(vs);
-}
-
-static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
-{
-    int max_size, max_width;
-    int max_sub_width, max_sub_height;
-    int dx, dy;
-    int rw, rh;
-    int n = 0;
-
-    max_size = tight_conf[vs->tight_compression].max_rect_size;
-    max_width = tight_conf[vs->tight_compression].max_rect_width;
-
-    if (w > max_width || w * h > max_size) {
-        max_sub_width = (w > max_width) ? max_width : w;
-        max_sub_height = max_size / max_sub_width;
-
-        for (dy = 0; dy < h; dy += max_sub_height) {
-            for (dx = 0; dx < w; dx += max_width) {
-                rw = MIN(max_sub_width, w - dx);
-                rh = MIN(max_sub_height, h - dy);
-                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
-            }
-        }
-    } else {
-        n += send_sub_rect(vs, x, y, w, h);
-    }
-
-    return n;
-}
-
-static int find_large_solid_color_rect(VncState *vs, int x, int y,
-                                       int w, int h, int max_rows)
-{
-    int dx, dy, dw, dh;
-    int n = 0;
-
-    /* Try to find large solid-color areas and send them separately. */
-
-    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
-
-        /* If a rectangle becomes too large, send its upper part now. */
-
-        if (dy - y >= max_rows) {
-            n += send_rect_simple(vs, x, y, w, max_rows);
-            y += max_rows;
-            h -= max_rows;
-        }
-
-        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
-
-        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
-            uint32_t color_value;
-            int x_best, y_best, w_best, h_best;
-
-            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
-
-            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
-                continue ;
-            }
-
-            /* Get dimensions of solid-color area. */
-
-            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
-                                 color_value, &w_best, &h_best);
-
-            /* Make sure a solid rectangle is large enough
-               (or the whole rectangle is of the same color). */
-
-            if (w_best * h_best != w * h &&
-                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
-                continue;
-            }
-
-            /* Try to extend solid rectangle to maximum size. */
-
-            x_best = dx; y_best = dy;
-            extend_solid_area(vs, x, y, w, h, color_value,
-                              &x_best, &y_best, &w_best, &h_best);
-
-            /* Send rectangles at top and left to solid-color area. */
-
-            if (y_best != y) {
-                n += send_rect_simple(vs, x, y, w, y_best-y);
-            }
-            if (x_best != x) {
-                n += vnc_tight_send_framebuffer_update(vs, x, y_best,
-                                                       x_best-x, h_best);
-            }
-
-            /* Send solid-color rectangle. */
-            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
-
-            /* Send remaining rectangles (at right and bottom). */
-
-            if (x_best + w_best != x + w) {
-                n += vnc_tight_send_framebuffer_update(vs, x_best+w_best,
-                                                       y_best,
-                                                       w-(x_best-x)-w_best,
-                                                       h_best);
-            }
-            if (y_best + h_best != y + h) {
-                n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best,
-                                                       w, h-(y_best-y)-h_best);
-            }
-
-            /* Return after all recursive calls are done. */
-            return n;
-        }
-    }
-    return n + send_rect_simple(vs, x, y, w, h);
-}
-
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
-                                      int w, int h)
-{
-    int max_rows;
-
-    if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
-        vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
-        vs->tight_pixel24 = true;
-    } else {
-        vs->tight_pixel24 = false;
-    }
-
-    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE)
-        return send_rect_simple(vs, x, y, w, h);
-
-    /* Calculate maximum number of rows in one non-solid rectangle. */
-
-    max_rows = tight_conf[vs->tight_compression].max_rect_size;
-    max_rows /= MIN(tight_conf[vs->tight_compression].max_rect_width, w);
-
-    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
-}
-
-void vnc_tight_clear(VncState *vs)
-{
-    int i;
-    for (i=0; i<ARRAY_SIZE(vs->tight_stream); i++) {
-        if (vs->tight_stream[i].opaque) {
-            deflateEnd(&vs->tight_stream[i]);
-        }
-    }
-
-    buffer_free(&vs->tight);
-    buffer_free(&vs->tight_zlib);
-    buffer_free(&vs->tight_gradient);
-#ifdef CONFIG_VNC_JPEG
-    buffer_free(&vs->tight_jpeg);
-#endif
-}
diff --git a/vnc-encoding-tight.h b/vnc-encoding-tight.h
deleted file mode 100644 (file)
index 9b0910c..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * QEMU VNC display driver: tight encoding
- *
- * From libvncserver/rfb/rfbproto.h
- * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
- * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
- * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
- * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef VNC_ENCODING_TIGHT_H
-#define VNC_ENCODING_TIGHT_H
-
-/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * Tight Encoding.
- *
- *-- The first byte of each Tight-encoded rectangle is a "compression control
- *   byte". Its format is as follows (bit 0 is the least significant one):
- *
- *   bit 0:    if 1, then compression stream 0 should be reset;
- *   bit 1:    if 1, then compression stream 1 should be reset;
- *   bit 2:    if 1, then compression stream 2 should be reset;
- *   bit 3:    if 1, then compression stream 3 should be reset;
- *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
- *             if 1001 (0x09), then the compression type is "jpeg",
- *             if 0xxx, then the compression type is "basic",
- *             values greater than 1001 are not valid.
- *
- * If the compression type is "basic", then bits 6..4 of the
- * compression control byte (those xxx in 0xxx) specify the following:
- *
- *   bits 5-4:  decimal representation is the index of a particular zlib
- *              stream which should be used for decompressing the data;
- *   bit 6:     if 1, then a "filter id" byte is following this byte.
- *
- *-- The data that follows after the compression control byte described
- * above depends on the compression type ("fill", "jpeg" or "basic").
- *
- *-- If the compression type is "fill", then the only pixel value follows, in
- * client pixel format (see NOTE 1). This value applies to all pixels of the
- * rectangle.
- *
- *-- If the compression type is "jpeg", the following data stream looks like
- * this:
- *
- *   1..3 bytes:  data size (N) in compact representation;
- *   N bytes:     JPEG image.
- *
- * Data size is compactly represented in one, two or three bytes, according
- * to the following scheme:
- *
- *  0xxxxxxx                    (for values 0..127)
- *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
- *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
- *
- * Here each character denotes one bit, xxxxxxx are the least significant 7
- * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
- * most significant 8 bits (bits 14-21). For example, decimal value 10000
- * should be represented as two bytes: binary 10010000 01001110, or
- * hexadecimal 90 4E.
- *
- *-- If the compression type is "basic" and bit 6 of the compression control
- * byte was set to 1, then the next (second) byte specifies "filter id" which
- * tells the decoder what filter type was used by the encoder to pre-process
- * pixel data before the compression. The "filter id" byte can be one of the
- * following:
- *
- *   0:  no filter ("copy" filter);
- *   1:  "palette" filter;
- *   2:  "gradient" filter.
- *
- *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
- * byte), or if the filter id is 0, then raw pixel values in the client
- * format (see NOTE 1) will be compressed. See below details on the
- * compression.
- *
- *-- The "gradient" filter pre-processes pixel data with a simple algorithm
- * which converts each color component to a difference between a "predicted"
- * intensity and the actual intensity. Such a technique does not affect
- * uncompressed data size, but helps to compress photo-like images better.
- * Pseudo-code for converting intensities to differences is the following:
- *
- *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
- *   if (P[i,j] < 0) then P[i,j] := 0;
- *   if (P[i,j] > MAX) then P[i,j] := MAX;
- *   D[i,j] := V[i,j] - P[i,j];
- *
- * Here V[i,j] is the intensity of a color component for a pixel at
- * coordinates (i,j). MAX is the maximum value of intensity for a color
- * component.
- *
- *-- The "palette" filter converts true-color pixel data to indexed colors
- * and a palette which can consist of 2..256 colors. If the number of colors
- * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
- * encode one pixel. 1-bit encoding is performed such way that the most
- * significant bits correspond to the leftmost pixels, and each raw of pixels
- * is aligned to the byte boundary. When "palette" filter is used, the
- * palette is sent before the pixel data. The palette begins with an unsigned
- * byte which value is the number of colors in the palette minus 1 (i.e. 1
- * means 2 colors, 255 means 256 colors in the palette). Then follows the
- * palette itself which consist of pixel values in client pixel format (see
- * NOTE 1).
- *
- *-- The pixel data is compressed using the zlib library. But if the data
- * size after applying the filter but before the compression is less then 12,
- * then the data is sent as is, uncompressed. Four separate zlib streams
- * (0..3) can be used and the decoder should read the actual stream id from
- * the compression control byte (see NOTE 2).
- *
- * If the compression is not used, then the pixel data is sent as is,
- * otherwise the data stream looks like this:
- *
- *   1..3 bytes:  data size (N) in compact representation;
- *   N bytes:     zlib-compressed data.
- *
- * Data size is compactly represented in one, two or three bytes, just like
- * in the "jpeg" compression method (see above).
- *
- *-- NOTE 1. If the color depth is 24, and all three color components are
- * 8-bit wide, then one pixel in Tight encoding is always represented by
- * three bytes, where the first byte is red component, the second byte is
- * green component, and the third byte is blue component of the pixel color
- * value. This applies to colors in palettes as well.
- *
- *-- NOTE 2. The decoder must reset compression streams' states before
- * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
- * byte are set to 1. Note that the decoder must reset zlib streams even if
- * the compression type is "fill" or "jpeg".
- *
- *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
- * when bits-per-pixel value is either 16 or 32, not 8.
- *
- *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
- * pixels. If a rectangle is wider, it must be split into several rectangles
- * and each one should be encoded separately.
- *
- */
-
-#define VNC_TIGHT_EXPLICIT_FILTER       0x04
-#define VNC_TIGHT_FILL                  0x08
-#define VNC_TIGHT_JPEG                  0x09
-#define VNC_TIGHT_MAX_SUBENCODING       0x09
-
-/* Filters to improve compression efficiency */
-#define VNC_TIGHT_FILTER_COPY             0x00
-#define VNC_TIGHT_FILTER_PALETTE          0x01
-#define VNC_TIGHT_FILTER_GRADIENT         0x02
-
-/* Note: The following constant should not be changed. */
-#define VNC_TIGHT_MIN_TO_COMPRESS 12
-
-/* The parameters below may be adjusted. */
-#define VNC_TIGHT_MIN_SPLIT_RECT_SIZE     4096
-#define VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE  2048
-#define VNC_TIGHT_MAX_SPLIT_TILE_SIZE       16
-
-#define VNC_TIGHT_JPEG_MIN_RECT_SIZE      4096
-#define VNC_TIGHT_DETECT_SUBROW_WIDTH        7
-#define VNC_TIGHT_DETECT_MIN_WIDTH           8
-#define VNC_TIGHT_DETECT_MIN_HEIGHT          8
-
-#endif /* VNC_ENCODING_TIGHT_H */
diff --git a/vnc-encoding-zlib.c b/vnc-encoding-zlib.c
deleted file mode 100644 (file)
index a99bc38..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * QEMU VNC display driver: zlib encoding
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vnc.h"
-
-#define ZALLOC_ALIGNMENT 16
-
-void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size)
-{
-    void *p;
-
-    size *= items;
-    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
-
-    p = qemu_mallocz(size);
-
-    return (p);
-}
-
-void vnc_zlib_zfree(void *x, void *addr)
-{
-    qemu_free(addr);
-}
-
-static void vnc_zlib_start(VncState *vs)
-{
-    buffer_reset(&vs->zlib);
-
-    // make the output buffer be the zlib buffer, so we can compress it later
-    vs->zlib_tmp = vs->output;
-    vs->output = vs->zlib;
-}
-
-static int vnc_zlib_stop(VncState *vs)
-{
-    z_streamp zstream = &vs->zlib_stream;
-    int previous_out;
-
-    // switch back to normal output/zlib buffers
-    vs->zlib = vs->output;
-    vs->output = vs->zlib_tmp;
-
-    // compress the zlib buffer
-
-    // initialize the stream
-    // XXX need one stream per session
-    if (zstream->opaque != vs) {
-        int err;
-
-        VNC_DEBUG("VNC: initializing zlib stream\n");
-        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
-        zstream->zalloc = vnc_zlib_zalloc;
-        zstream->zfree = vnc_zlib_zfree;
-
-        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
-                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-
-        if (err != Z_OK) {
-            fprintf(stderr, "VNC: error initializing zlib\n");
-            return -1;
-        }
-
-        vs->zlib_level = vs->tight_compression;
-        zstream->opaque = vs;
-    }
-
-    if (vs->tight_compression != vs->zlib_level) {
-        if (deflateParams(zstream, vs->tight_compression,
-                          Z_DEFAULT_STRATEGY) != Z_OK) {
-            return -1;
-        }
-        vs->zlib_level = vs->tight_compression;
-    }
-
-    // reserve memory in output buffer
-    buffer_reserve(&vs->output, vs->zlib.offset + 64);
-
-    // set pointers
-    zstream->next_in = vs->zlib.buffer;
-    zstream->avail_in = vs->zlib.offset;
-    zstream->next_out = vs->output.buffer + vs->output.offset;
-    zstream->avail_out = vs->output.capacity - vs->output.offset;
-    zstream->data_type = Z_BINARY;
-    previous_out = zstream->total_out;
-
-    // start encoding
-    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
-        fprintf(stderr, "VNC: error during zlib compression\n");
-        return -1;
-    }
-
-    vs->output.offset = vs->output.capacity - zstream->avail_out;
-    return zstream->total_out - previous_out;
-}
-
-int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
-{
-    int old_offset, new_offset, bytes_written;
-
-    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
-
-    // remember where we put in the follow-up size
-    old_offset = vs->output.offset;
-    vnc_write_s32(vs, 0);
-
-    // compress the stream
-    vnc_zlib_start(vs);
-    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
-    bytes_written = vnc_zlib_stop(vs);
-
-    if (bytes_written == -1)
-        return 0;
-
-    // hack in the size
-    new_offset = vs->output.offset;
-    vs->output.offset = old_offset;
-    vnc_write_u32(vs, bytes_written);
-    vs->output.offset = new_offset;
-
-    return 1;
-}
-
-void vnc_zlib_clear(VncState *vs)
-{
-    if (vs->zlib_stream.opaque) {
-        deflateEnd(&vs->zlib_stream);
-    }
-    buffer_free(&vs->zlib);
-}
diff --git a/vnc-tls.c b/vnc-tls.c
deleted file mode 100644 (file)
index dec626c..0000000
--- a/vnc-tls.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * QEMU VNC display driver: TLS helpers
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-x509.h"
-#include "vnc.h"
-#include "qemu_socket.h"
-
-#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
-/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
-static void vnc_debug_gnutls_log(int level, const char* str) {
-    VNC_DEBUG("%d %s", level, str);
-}
-#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
-
-
-#define DH_BITS 1024
-static gnutls_dh_params_t dh_params;
-
-static int vnc_tls_initialize(void)
-{
-    static int tlsinitialized = 0;
-
-    if (tlsinitialized)
-        return 1;
-
-    if (gnutls_global_init () < 0)
-        return 0;
-
-    /* XXX ought to re-generate diffie-hellmen params periodically */
-    if (gnutls_dh_params_init (&dh_params) < 0)
-        return 0;
-    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
-        return 0;
-
-#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
-    gnutls_global_set_log_level(10);
-    gnutls_global_set_log_function(vnc_debug_gnutls_log);
-#endif
-
-    tlsinitialized = 1;
-
-    return 1;
-}
-
-static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
-                            const void *data,
-                            size_t len) {
-    struct VncState *vs = (struct VncState *)transport;
-    int ret;
-
- retry:
-    ret = send(vs->csock, data, len, 0);
-    if (ret < 0) {
-        if (errno == EINTR)
-            goto retry;
-        return -1;
-    }
-    return ret;
-}
-
-
-static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
-                            void *data,
-                            size_t len) {
-    struct VncState *vs = (struct VncState *)transport;
-    int ret;
-
- retry:
-    ret = recv(vs->csock, data, len, 0);
-    if (ret < 0) {
-        if (errno == EINTR)
-            goto retry;
-        return -1;
-    }
-    return ret;
-}
-
-
-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
-{
-    gnutls_anon_server_credentials anon_cred;
-    int ret;
-
-    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
-        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
-        return NULL;
-    }
-
-    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
-
-    return anon_cred;
-}
-
-
-static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
-{
-    gnutls_certificate_credentials_t x509_cred;
-    int ret;
-
-    if (!vd->tls.x509cacert) {
-        VNC_DEBUG("No CA x509 certificate specified\n");
-        return NULL;
-    }
-    if (!vd->tls.x509cert) {
-        VNC_DEBUG("No server x509 certificate specified\n");
-        return NULL;
-    }
-    if (!vd->tls.x509key) {
-        VNC_DEBUG("No server private key specified\n");
-        return NULL;
-    }
-
-    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
-        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
-        return NULL;
-    }
-    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
-                                                      vd->tls.x509cacert,
-                                                      GNUTLS_X509_FMT_PEM)) < 0) {
-        VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
-        gnutls_certificate_free_credentials(x509_cred);
-        return NULL;
-    }
-
-    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
-                                                     vd->tls.x509cert,
-                                                     vd->tls.x509key,
-                                                     GNUTLS_X509_FMT_PEM)) < 0) {
-        VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
-        gnutls_certificate_free_credentials(x509_cred);
-        return NULL;
-    }
-
-    if (vd->tls.x509cacrl) {
-        if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
-                                                        vd->tls.x509cacrl,
-                                                        GNUTLS_X509_FMT_PEM)) < 0) {
-            VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
-            gnutls_certificate_free_credentials(x509_cred);
-            return NULL;
-        }
-    }
-
-    gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
-    return x509_cred;
-}
-
-
-int vnc_tls_validate_certificate(struct VncState *vs)
-{
-    int ret;
-    unsigned int status;
-    const gnutls_datum_t *certs;
-    unsigned int nCerts, i;
-    time_t now;
-
-    VNC_DEBUG("Validating client certificate\n");
-    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
-        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
-        return -1;
-    }
-
-    if ((now = time(NULL)) == ((time_t)-1)) {
-        return -1;
-    }
-
-    if (status != 0) {
-        if (status & GNUTLS_CERT_INVALID)
-            VNC_DEBUG("The certificate is not trusted.\n");
-
-        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-            VNC_DEBUG("The certificate hasn't got a known issuer.\n");
-
-        if (status & GNUTLS_CERT_REVOKED)
-            VNC_DEBUG("The certificate has been revoked.\n");
-
-        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-            VNC_DEBUG("The certificate uses an insecure algorithm\n");
-
-        return -1;
-    } else {
-        VNC_DEBUG("Certificate is valid!\n");
-    }
-
-    /* Only support x509 for now */
-    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
-        return -1;
-
-    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
-        return -1;
-
-    for (i = 0 ; i < nCerts ; i++) {
-        gnutls_x509_crt_t cert;
-        VNC_DEBUG ("Checking certificate chain %d\n", i);
-        if (gnutls_x509_crt_init (&cert) < 0)
-            return -1;
-
-        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-            VNC_DEBUG("The certificate has expired\n");
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_activation_time (cert) > now) {
-            VNC_DEBUG("The certificate is not yet activated\n");
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_activation_time (cert) > now) {
-            VNC_DEBUG("The certificate is not yet activated\n");
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (i == 0) {
-            size_t dnameSize = 1024;
-            vs->tls.dname = qemu_malloc(dnameSize);
-        requery:
-            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
-                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
-                    vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
-                    goto requery;
-                }
-                gnutls_x509_crt_deinit (cert);
-                VNC_DEBUG("Cannot get client distinguished name: %s",
-                          gnutls_strerror (ret));
-                return -1;
-            }
-
-            if (vs->vd->tls.x509verify) {
-                int allow;
-                if (!vs->vd->tls.acl) {
-                    VNC_DEBUG("no ACL activated, allowing access");
-                    gnutls_x509_crt_deinit (cert);
-                    continue;
-                }
-
-                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
-                                                  vs->tls.dname);
-
-                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
-                          vs->tls.dname, allow ? "allowed" : "denied");
-                if (!allow) {
-                    gnutls_x509_crt_deinit (cert);
-                    return -1;
-                }
-            }
-        }
-
-        gnutls_x509_crt_deinit (cert);
-    }
-
-    return 0;
-}
-
-
-int vnc_tls_client_setup(struct VncState *vs,
-                         int needX509Creds) {
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
-
-    VNC_DEBUG("Do TLS setup\n");
-    if (vnc_tls_initialize() < 0) {
-        VNC_DEBUG("Failed to init TLS\n");
-        vnc_client_error(vs);
-        return -1;
-    }
-    if (vs->tls.session == NULL) {
-        if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_set_default_priority(vs->tls.session) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (needX509Creds) {
-            gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
-            if (!x509_cred) {
-                gnutls_deinit(vs->tls.session);
-                vs->tls.session = NULL;
-                vnc_client_error(vs);
-                return -1;
-            }
-            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
-                gnutls_deinit(vs->tls.session);
-                vs->tls.session = NULL;
-                gnutls_certificate_free_credentials(x509_cred);
-                vnc_client_error(vs);
-                return -1;
-            }
-            if (vs->vd->tls.x509verify) {
-                VNC_DEBUG("Requesting a client certificate\n");
-                gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
-            }
-
-        } else {
-            gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
-            if (!anon_cred) {
-                gnutls_deinit(vs->tls.session);
-                vs->tls.session = NULL;
-                vnc_client_error(vs);
-                return -1;
-            }
-            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
-                gnutls_deinit(vs->tls.session);
-                vs->tls.session = NULL;
-                gnutls_anon_free_server_credentials(anon_cred);
-                vnc_client_error(vs);
-                return -1;
-            }
-        }
-
-        gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
-        gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
-        gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
-    }
-    return 0;
-}
-
-
-void vnc_tls_client_cleanup(struct VncState *vs)
-{
-    if (vs->tls.session) {
-        gnutls_deinit(vs->tls.session);
-        vs->tls.session = NULL;
-    }
-    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
-    free(vs->tls.dname);
-}
-
-
-
-static int vnc_set_x509_credential(VncDisplay *vd,
-                                   const char *certdir,
-                                   const char *filename,
-                                   char **cred,
-                                   int ignoreMissing)
-{
-    struct stat sb;
-
-    if (*cred) {
-        qemu_free(*cred);
-        *cred = NULL;
-    }
-
-    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
-
-    strcpy(*cred, certdir);
-    strcat(*cred, "/");
-    strcat(*cred, filename);
-
-    VNC_DEBUG("Check %s\n", *cred);
-    if (stat(*cred, &sb) < 0) {
-        qemu_free(*cred);
-        *cred = NULL;
-        if (ignoreMissing && errno == ENOENT)
-            return 0;
-        return -1;
-    }
-
-    return 0;
-}
-
-
-int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
-                               const char *certdir)
-{
-    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
-        goto cleanup;
-    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
-        goto cleanup;
-    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
-        goto cleanup;
-    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
-        goto cleanup;
-
-    return 0;
-
- cleanup:
-    qemu_free(vd->tls.x509cacert);
-    qemu_free(vd->tls.x509cacrl);
-    qemu_free(vd->tls.x509cert);
-    qemu_free(vd->tls.x509key);
-    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
-    return -1;
-}
-
diff --git a/vnc-tls.h b/vnc-tls.h
deleted file mode 100644 (file)
index 2b93633..0000000
--- a/vnc-tls.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * QEMU VNC display driver. TLS helpers
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-#ifndef __QEMU_VNC_TLS_H__
-#define __QEMU_VNC_TLS_H__
-
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include "acl.h"
-
-enum {
-    VNC_WIREMODE_CLEAR,
-    VNC_WIREMODE_TLS,
-};
-
-typedef struct VncDisplayTLS VncDisplayTLS;
-typedef struct VncStateTLS VncStateTLS;
-
-/* Server state */
-struct VncDisplayTLS {
-    int x509verify; /* Non-zero if server requests & validates client cert */
-    qemu_acl *acl;
-
-    /* Paths to x509 certs/keys */
-    char *x509cacert;
-    char *x509cacrl;
-    char *x509cert;
-    char *x509key;
-};
-
-/* Per client state */
-struct VncStateTLS {
-    /* Whether data is being TLS encrypted yet */
-    int wiremode;
-    gnutls_session_t session;
-
-    /* Client's Distinguished Name from the x509 cert */
-    char *dname;
-};
-
-int vnc_tls_client_setup(VncState *vs, int x509Creds);
-void vnc_tls_client_cleanup(VncState *vs);
-
-int vnc_tls_validate_certificate(VncState *vs);
-
-int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
-                              const char *path);
-
-
-#endif /* __QEMU_VNC_TLS_H__ */
-
diff --git a/vnc.c b/vnc.c
deleted file mode 100644 (file)
index ccd7aad..0000000
--- a/vnc.c
+++ /dev/null
@@ -1,2631 +0,0 @@
-/*
- * QEMU VNC display driver
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vnc.h"
-#include "sysemu.h"
-#include "qemu_socket.h"
-#include "qemu-timer.h"
-#include "acl.h"
-#include "qemu-objects.h"
-
-#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"
-
-#define count_bits(c, v) { \
-    for (c = 0; v; v >>= 1) \
-    { \
-        c += v & 1; \
-    } \
-}
-
-
-static VncDisplay *vnc_display; /* needed for info vnc */
-static DisplayChangeListener *dcl;
-
-static int vnc_cursor_define(VncState *vs);
-
-static char *addr_to_string(const char *format,
-                            struct sockaddr_storage *sa,
-                            socklen_t salen) {
-    char *addr;
-    char host[NI_MAXHOST];
-    char serv[NI_MAXSERV];
-    int err;
-    size_t addrlen;
-
-    if ((err = getnameinfo((struct sockaddr *)sa, salen,
-                           host, sizeof(host),
-                           serv, sizeof(serv),
-                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
-        VNC_DEBUG("Cannot resolve address %d: %s\n",
-                  err, gai_strerror(err));
-        return NULL;
-    }
-
-    /* Enough for the existing format + the 2 vars we're
-     * substituting in. */
-    addrlen = strlen(format) + strlen(host) + strlen(serv);
-    addr = qemu_malloc(addrlen + 1);
-    snprintf(addr, addrlen, format, host, serv);
-    addr[addrlen] = '\0';
-
-    return addr;
-}
-
-
-char *vnc_socket_local_addr(const char *format, int fd) {
-    struct sockaddr_storage sa;
-    socklen_t salen;
-
-    salen = sizeof(sa);
-    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
-        return NULL;
-
-    return addr_to_string(format, &sa, salen);
-}
-
-char *vnc_socket_remote_addr(const char *format, int fd) {
-    struct sockaddr_storage sa;
-    socklen_t salen;
-
-    salen = sizeof(sa);
-    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
-        return NULL;
-
-    return addr_to_string(format, &sa, salen);
-}
-
-static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
-                          socklen_t salen)
-{
-    char host[NI_MAXHOST];
-    char serv[NI_MAXSERV];
-    int err;
-
-    if ((err = getnameinfo((struct sockaddr *)sa, salen,
-                           host, sizeof(host),
-                           serv, sizeof(serv),
-                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
-        VNC_DEBUG("Cannot resolve address %d: %s\n",
-                  err, gai_strerror(err));
-        return -1;
-    }
-
-    qdict_put(qdict, "host", qstring_from_str(host));
-    qdict_put(qdict, "service", qstring_from_str(serv));
-    qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
-
-    return 0;
-}
-
-static int vnc_server_addr_put(QDict *qdict, int fd)
-{
-    struct sockaddr_storage sa;
-    socklen_t salen;
-
-    salen = sizeof(sa);
-    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
-        return -1;
-    }
-
-    return put_addr_qdict(qdict, &sa, salen);
-}
-
-static int vnc_qdict_remote_addr(QDict *qdict, int fd)
-{
-    struct sockaddr_storage sa;
-    socklen_t salen;
-
-    salen = sizeof(sa);
-    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
-        return -1;
-    }
-
-    return put_addr_qdict(qdict, &sa, salen);
-}
-
-static const char *vnc_auth_name(VncDisplay *vd) {
-    switch (vd->auth) {
-    case VNC_AUTH_INVALID:
-        return "invalid";
-    case VNC_AUTH_NONE:
-        return "none";
-    case VNC_AUTH_VNC:
-        return "vnc";
-    case VNC_AUTH_RA2:
-        return "ra2";
-    case VNC_AUTH_RA2NE:
-        return "ra2ne";
-    case VNC_AUTH_TIGHT:
-        return "tight";
-    case VNC_AUTH_ULTRA:
-        return "ultra";
-    case VNC_AUTH_TLS:
-        return "tls";
-    case VNC_AUTH_VENCRYPT:
-#ifdef CONFIG_VNC_TLS
-        switch (vd->subauth) {
-        case VNC_AUTH_VENCRYPT_PLAIN:
-            return "vencrypt+plain";
-        case VNC_AUTH_VENCRYPT_TLSNONE:
-            return "vencrypt+tls+none";
-        case VNC_AUTH_VENCRYPT_TLSVNC:
-            return "vencrypt+tls+vnc";
-        case VNC_AUTH_VENCRYPT_TLSPLAIN:
-            return "vencrypt+tls+plain";
-        case VNC_AUTH_VENCRYPT_X509NONE:
-            return "vencrypt+x509+none";
-        case VNC_AUTH_VENCRYPT_X509VNC:
-            return "vencrypt+x509+vnc";
-        case VNC_AUTH_VENCRYPT_X509PLAIN:
-            return "vencrypt+x509+plain";
-        case VNC_AUTH_VENCRYPT_TLSSASL:
-            return "vencrypt+tls+sasl";
-        case VNC_AUTH_VENCRYPT_X509SASL:
-            return "vencrypt+x509+sasl";
-        default:
-            return "vencrypt";
-        }
-#else
-        return "vencrypt";
-#endif
-    case VNC_AUTH_SASL:
-        return "sasl";
-    }
-    return "unknown";
-}
-
-static int vnc_server_info_put(QDict *qdict)
-{
-    if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
-        return -1;
-    }
-
-    qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
-    return 0;
-}
-
-static void vnc_client_cache_auth(VncState *client)
-{
-    QDict *qdict;
-
-    if (!client->info) {
-        return;
-    }
-
-    qdict = qobject_to_qdict(client->info);
-
-#ifdef CONFIG_VNC_TLS
-    if (client->tls.session &&
-        client->tls.dname) {
-        qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
-    }
-#endif
-#ifdef CONFIG_VNC_SASL
-    if (client->sasl.conn &&
-        client->sasl.username) {
-        qdict_put(qdict, "sasl_username",
-                  qstring_from_str(client->sasl.username));
-    }
-#endif
-}
-
-static void vnc_client_cache_addr(VncState *client)
-{
-    QDict *qdict;
-
-    qdict = qdict_new();
-    if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
-        QDECREF(qdict);
-        /* XXX: how to report the error? */
-        return;
-    }
-
-    client->info = QOBJECT(qdict);
-}
-
-static void vnc_qmp_event(VncState *vs, MonitorEvent event)
-{
-    QDict *server;
-    QObject *data;
-
-    if (!vs->info) {
-        return;
-    }
-
-    server = qdict_new();
-    if (vnc_server_info_put(server) < 0) {
-        QDECREF(server);
-        return;
-    }
-
-    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
-                              vs->info, QOBJECT(server));
-
-    monitor_protocol_event(event, data);
-
-    qobject_incref(vs->info);
-    qobject_decref(data);
-}
-
-static void info_vnc_iter(QObject *obj, void *opaque)
-{
-    QDict *client;
-    Monitor *mon = opaque;
-
-    client = qobject_to_qdict(obj);
-    monitor_printf(mon, "Client:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(client, "host"),
-                   qdict_get_str(client, "service"));
-
-#ifdef CONFIG_VNC_TLS
-    monitor_printf(mon, "  x509_dname: %s\n",
-        qdict_haskey(client, "x509_dname") ?
-        qdict_get_str(client, "x509_dname") : "none");
-#endif
-#ifdef CONFIG_VNC_SASL
-    monitor_printf(mon, "    username: %s\n",
-        qdict_haskey(client, "sasl_username") ?
-        qdict_get_str(client, "sasl_username") : "none");
-#endif
-}
-
-void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
-    QDict *server;
-    QList *clients;
-
-    server = qobject_to_qdict(data);
-    if (qdict_get_bool(server, "enabled") == 0) {
-        monitor_printf(mon, "Server: disabled\n");
-        return;
-    }
-
-    monitor_printf(mon, "Server:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(server, "host"),
-                   qdict_get_str(server, "service"));
-    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
-
-    clients = qdict_get_qlist(server, "clients");
-    if (qlist_empty(clients)) {
-        monitor_printf(mon, "Client: none\n");
-    } else {
-        qlist_iter(clients, info_vnc_iter, mon);
-    }
-}
-
-void do_info_vnc(Monitor *mon, QObject **ret_data)
-{
-    if (vnc_display == NULL || vnc_display->display == NULL) {
-        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
-    } else {
-        QList *clist;
-        VncState *client;
-
-        clist = qlist_new();
-        QTAILQ_FOREACH(client, &vnc_display->clients, next) {
-            if (client->info) {
-                /* incref so that it's not freed by upper layers */
-                qobject_incref(client->info);
-                qlist_append_obj(clist, client->info);
-            }
-        }
-
-        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
-                                       QOBJECT(clist));
-        assert(*ret_data != NULL);
-
-        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
-            qobject_decref(*ret_data);
-            *ret_data = NULL;
-        }
-    }
-}
-
-static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
-    return (vs->features & (1 << feature));
-}
-
-/* TODO
-   1) Get the queue working for IO.
-   2) there is some weirdness when using the -S option (the screen is grey
-      and not totally invalidated
-   3) resolutions > 1024
-*/
-
-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);
-static void vnc_remove_timer(VncDisplay *vd);
-
-static void vnc_colordepth(VncState *vs);
-static void framebuffer_update_request(VncState *vs, int incremental,
-                                       int x_position, int y_position,
-                                       int w, int h);
-static void vnc_refresh(void *opaque);
-static int vnc_refresh_server_surface(VncDisplay *vd);
-
-static inline void vnc_set_bit(uint32_t *d, int k)
-{
-    d[k >> 5] |= 1 << (k & 0x1f);
-}
-
-static inline void vnc_clear_bit(uint32_t *d, int k)
-{
-    d[k >> 5] &= ~(1 << (k & 0x1f));
-}
-
-static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
-{
-    int j;
-
-    j = 0;
-    while (n >= 32) {
-        d[j++] = -1;
-        n -= 32;
-    }
-    if (n > 0)
-        d[j++] = (1 << n) - 1;
-    while (j < nb_words)
-        d[j++] = 0;
-}
-
-static inline int vnc_get_bit(const uint32_t *d, int k)
-{
-    return (d[k >> 5] >> (k & 0x1f)) & 1;
-}
-
-static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
-                               int nb_words)
-{
-    int i;
-    for(i = 0; i < nb_words; i++) {
-        if ((d1[i] & d2[i]) != 0)
-            return 1;
-    }
-    return 0;
-}
-
-static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    int i;
-    VncDisplay *vd = ds->opaque;
-    struct VncSurface *s = &vd->guest;
-
-    h += y;
-
-    /* round x down to ensure the loop only spans one 16-pixel block per,
-       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
-       two 16-pixel blocks but we only mark the first as dirty
-    */
-    w += (x % 16);
-    x -= (x % 16);
-
-    x = MIN(x, s->ds->width);
-    y = MIN(y, s->ds->height);
-    w = MIN(x + w, s->ds->width) - x;
-    h = MIN(h, s->ds->height);
-
-    for (; y < h; y++)
-        for (i = 0; i < w; i += 16)
-            vnc_set_bit(s->dirty[y], (x + i) / 16);
-}
-
-void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
-                            int32_t encoding)
-{
-    vnc_write_u16(vs, x);
-    vnc_write_u16(vs, y);
-    vnc_write_u16(vs, w);
-    vnc_write_u16(vs, h);
-
-    vnc_write_s32(vs, encoding);
-}
-
-void buffer_reserve(Buffer *buffer, size_t len)
-{
-    if ((buffer->capacity - buffer->offset) < len) {
-        buffer->capacity += (len + 1024);
-        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
-        if (buffer->buffer == NULL) {
-            fprintf(stderr, "vnc: out of memory\n");
-            exit(1);
-        }
-    }
-}
-
-int buffer_empty(Buffer *buffer)
-{
-    return buffer->offset == 0;
-}
-
-uint8_t *buffer_end(Buffer *buffer)
-{
-    return buffer->buffer + buffer->offset;
-}
-
-void buffer_reset(Buffer *buffer)
-{
-        buffer->offset = 0;
-}
-
-void buffer_free(Buffer *buffer)
-{
-    qemu_free(buffer->buffer);
-    buffer->offset = 0;
-    buffer->capacity = 0;
-    buffer->buffer = NULL;
-}
-
-void buffer_append(Buffer *buffer, const void *data, size_t len)
-{
-    memcpy(buffer->buffer + buffer->offset, data, len);
-    buffer->offset += len;
-}
-
-static void vnc_desktop_resize(VncState *vs)
-{
-    DisplayState *ds = vs->ds;
-
-    if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
-        return;
-    }
-    if (vs->client_width == ds_get_width(ds) &&
-        vs->client_height == ds_get_height(ds)) {
-        return;
-    }
-    vs->client_width = ds_get_width(ds);
-    vs->client_height = ds_get_height(ds);
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-    vnc_write_u8(vs, 0);
-    vnc_write_u16(vs, 1); /* number of rects */
-    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
-                           VNC_ENCODING_DESKTOPRESIZE);
-    vnc_flush(vs);
-}
-
-static void vnc_dpy_resize(DisplayState *ds)
-{
-    VncDisplay *vd = ds->opaque;
-    VncState *vs;
-
-    /* server surface */
-    if (!vd->server)
-        vd->server = qemu_mallocz(sizeof(*vd->server));
-    if (vd->server->data)
-        qemu_free(vd->server->data);
-    *(vd->server) = *(ds->surface);
-    vd->server->data = qemu_mallocz(vd->server->linesize *
-                                    vd->server->height);
-
-    /* guest surface */
-    if (!vd->guest.ds)
-        vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
-    if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
-        console_color_init(ds);
-    *(vd->guest.ds) = *(ds->surface);
-    memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
-
-    QTAILQ_FOREACH(vs, &vd->clients, next) {
-        vnc_colordepth(vs);
-        vnc_desktop_resize(vs);
-        if (vs->vd->cursor) {
-            vnc_cursor_define(vs);
-        }
-        memset(vs->dirty, 0xFF, sizeof(vs->dirty));
-    }
-}
-
-/* fastest code */
-static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
-                                  void *pixels, int size)
-{
-    vnc_write(vs, pixels, size);
-}
-
-/* slowest but generic code. */
-void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
-{
-    uint8_t r, g, b;
-    VncDisplay *vd = vs->vd;
-
-    r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
-        vd->server->pf.rbits);
-    g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
-        vd->server->pf.gbits);
-    b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
-        vd->server->pf.bbits);
-    v = (r << vs->clientds.pf.rshift) |
-        (g << vs->clientds.pf.gshift) |
-        (b << vs->clientds.pf.bshift);
-    switch(vs->clientds.pf.bytes_per_pixel) {
-    case 1:
-        buf[0] = v;
-        break;
-    case 2:
-        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
-            buf[0] = v >> 8;
-            buf[1] = v;
-        } else {
-            buf[1] = v >> 8;
-            buf[0] = v;
-        }
-        break;
-    default:
-    case 4:
-        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
-            buf[0] = v >> 24;
-            buf[1] = v >> 16;
-            buf[2] = v >> 8;
-            buf[3] = v;
-        } else {
-            buf[3] = v >> 24;
-            buf[2] = v >> 16;
-            buf[1] = v >> 8;
-            buf[0] = v;
-        }
-        break;
-    }
-}
-
-static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
-                                     void *pixels1, int size)
-{
-    uint8_t buf[4];
-
-    if (pf->bytes_per_pixel == 4) {
-        uint32_t *pixels = pixels1;
-        int n, i;
-        n = size >> 2;
-        for(i = 0; i < n; i++) {
-            vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
-        }
-    } else if (pf->bytes_per_pixel == 2) {
-        uint16_t *pixels = pixels1;
-        int n, i;
-        n = size >> 1;
-        for(i = 0; i < n; i++) {
-            vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
-        }
-    } else if (pf->bytes_per_pixel == 1) {
-        uint8_t *pixels = pixels1;
-        int n, i;
-        n = size;
-        for(i = 0; i < n; i++) {
-            vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
-        }
-    } else {
-        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
-    }
-}
-
-int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
-{
-    int i;
-    uint8_t *row;
-    VncDisplay *vd = vs->vd;
-
-    row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
-    for (i = 0; i < h; i++) {
-        vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
-        row += ds_get_linesize(vs->ds);
-    }
-    return 1;
-}
-
-static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
-{
-    int n = 0;
-
-    switch(vs->vnc_encoding) {
-        case VNC_ENCODING_ZLIB:
-            n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
-            break;
-        case VNC_ENCODING_HEXTILE:
-            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
-            n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
-            break;
-        case VNC_ENCODING_TIGHT:
-            n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
-            break;
-        default:
-            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
-            n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
-            break;
-    }
-    return n;
-}
-
-static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
-{
-    /* send bitblit op to the vnc client */
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-    vnc_write_u8(vs, 0);
-    vnc_write_u16(vs, 1); /* number of rects */
-    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
-    vnc_write_u16(vs, src_x);
-    vnc_write_u16(vs, src_y);
-    vnc_flush(vs);
-}
-
-static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
-{
-    VncDisplay *vd = ds->opaque;
-    VncState *vs, *vn;
-    uint8_t *src_row;
-    uint8_t *dst_row;
-    int i,x,y,pitch,depth,inc,w_lim,s;
-    int cmp_bytes;
-
-    vnc_refresh_server_surface(vd);
-    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-            vs->force_update = 1;
-            vnc_update_client(vs, 1);
-            /* vs might be free()ed here */
-        }
-    }
-
-    /* do bitblit op on the local surface too */
-    pitch = ds_get_linesize(vd->ds);
-    depth = ds_get_bytes_per_pixel(vd->ds);
-    src_row = vd->server->data + pitch * src_y + depth * src_x;
-    dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
-    y = dst_y;
-    inc = 1;
-    if (dst_y > src_y) {
-        /* copy backwards */
-        src_row += pitch * (h-1);
-        dst_row += pitch * (h-1);
-        pitch = -pitch;
-        y = dst_y + h - 1;
-        inc = -1;
-    }
-    w_lim = w - (16 - (dst_x % 16));
-    if (w_lim < 0)
-        w_lim = w;
-    else
-        w_lim = w - (w_lim % 16);
-    for (i = 0; i < h; i++) {
-        for (x = 0; x <= w_lim;
-                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
-            if (x == w_lim) {
-                if ((s = w - w_lim) == 0)
-                    break;
-            } else if (!x) {
-                s = (16 - (dst_x % 16));
-                s = MIN(s, w_lim);
-            } else {
-                s = 16;
-            }
-            cmp_bytes = s * depth;
-            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
-                continue;
-            memmove(dst_row, src_row, cmp_bytes);
-            QTAILQ_FOREACH(vs, &vd->clients, next) {
-                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-                    vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
-                }
-            }
-        }
-        src_row += pitch - w * depth;
-        dst_row += pitch - w * depth;
-        y += inc;
-    }
-
-    QTAILQ_FOREACH(vs, &vd->clients, next) {
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
-        }
-    }
-}
-
-static void vnc_mouse_set(int x, int y, int visible)
-{
-    /* can we ask the client(s) to move the pointer ??? */
-}
-
-static int vnc_cursor_define(VncState *vs)
-{
-    QEMUCursor *c = vs->vd->cursor;
-    PixelFormat pf = qemu_default_pixelformat(32);
-    int isize;
-
-    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
-        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-        vnc_write_u8(vs,  0);  /*  padding     */
-        vnc_write_u16(vs, 1);  /*  # of rects  */
-        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
-                               VNC_ENCODING_RICH_CURSOR);
-        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
-        vnc_write_pixels_generic(vs, &pf, c->data, isize);
-        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
-        return 0;
-    }
-    return -1;
-}
-
-static void vnc_dpy_cursor_define(QEMUCursor *c)
-{
-    VncDisplay *vd = vnc_display;
-    VncState *vs;
-
-    cursor_put(vd->cursor);
-    qemu_free(vd->cursor_mask);
-
-    vd->cursor = c;
-    cursor_get(vd->cursor);
-    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
-    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
-    cursor_get_mono_mask(c, 0, vd->cursor_mask);
-
-    QTAILQ_FOREACH(vs, &vd->clients, next) {
-        vnc_cursor_define(vs);
-    }
-}
-
-static int find_and_clear_dirty_height(struct VncState *vs,
-                                       int y, int last_x, int x)
-{
-    int h;
-    VncDisplay *vd = vs->vd;
-
-    for (h = 1; h < (vd->server->height - y); h++) {
-        int tmp_x;
-        if (!vnc_get_bit(vs->dirty[y + h], last_x))
-            break;
-        for (tmp_x = last_x; tmp_x < x; tmp_x++)
-            vnc_clear_bit(vs->dirty[y + h], tmp_x);
-    }
-
-    return h;
-}
-
-static int vnc_update_client(VncState *vs, int has_dirty)
-{
-    if (vs->need_update && vs->csock != -1) {
-        VncDisplay *vd = vs->vd;
-        int y;
-        int n_rectangles;
-        int saved_offset;
-        int width, height;
-        int n;
-
-        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
-            /* kernel send buffers are full -> drop frames to throttle */
-            return 0;
-
-        if (!has_dirty && !vs->audio_cap && !vs->force_update)
-            return 0;
-
-        /*
-         * Send screen updates to the vnc client using the server
-         * surface and server dirty map.  guest surface updates
-         * happening in parallel don't disturb us, the next pass will
-         * send them to the client.
-         */
-        n_rectangles = 0;
-        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-        vnc_write_u8(vs, 0);
-        saved_offset = vs->output.offset;
-        vnc_write_u16(vs, 0);
-
-        width = MIN(vd->server->width, vs->client_width);
-        height = MIN(vd->server->height, vs->client_height);
-
-        for (y = 0; y < height; y++) {
-            int x;
-            int last_x = -1;
-            for (x = 0; x < width / 16; x++) {
-                if (vnc_get_bit(vs->dirty[y], x)) {
-                    if (last_x == -1) {
-                        last_x = x;
-                    }
-                    vnc_clear_bit(vs->dirty[y], x);
-                } else {
-                    if (last_x != -1) {
-                        int h = find_and_clear_dirty_height(vs, y, last_x, x);
-                        n = send_framebuffer_update(vs, last_x * 16, y,
-                                                    (x - last_x) * 16, h);
-                        n_rectangles += n;
-                    }
-                    last_x = -1;
-                }
-            }
-            if (last_x != -1) {
-                int h = find_and_clear_dirty_height(vs, y, last_x, x);
-                n = send_framebuffer_update(vs, last_x * 16, y,
-                                            (x - last_x) * 16, h);
-                n_rectangles += n;
-            }
-        }
-        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
-        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 */
-static void audio_capture_notify(void *opaque, audcnotification_e cmd)
-{
-    VncState *vs = opaque;
-
-    switch (cmd) {
-    case AUD_CNOTIFY_DISABLE:
-        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
-        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
-        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
-        vnc_flush(vs);
-        break;
-
-    case AUD_CNOTIFY_ENABLE:
-        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
-        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
-        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
-        vnc_flush(vs);
-        break;
-    }
-}
-
-static void audio_capture_destroy(void *opaque)
-{
-}
-
-static void audio_capture(void *opaque, void *buf, int size)
-{
-    VncState *vs = opaque;
-
-    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
-    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
-    vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
-    vnc_write_u32(vs, size);
-    vnc_write(vs, buf, size);
-    vnc_flush(vs);
-}
-
-static void audio_add(VncState *vs)
-{
-    struct audio_capture_ops ops;
-
-    if (vs->audio_cap) {
-        monitor_printf(default_mon, "audio already running\n");
-        return;
-    }
-
-    ops.notify = audio_capture_notify;
-    ops.destroy = audio_capture_destroy;
-    ops.capture = audio_capture;
-
-    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
-    if (!vs->audio_cap) {
-        monitor_printf(default_mon, "Failed to add audio capture\n");
-    }
-}
-
-static void audio_del(VncState *vs)
-{
-    if (vs->audio_cap) {
-        AUD_del_capture(vs->audio_cap, vs);
-        vs->audio_cap = NULL;
-    }
-}
-
-static void vnc_disconnect_start(VncState *vs)
-{
-    if (vs->csock == -1)
-        return;
-    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
-    closesocket(vs->csock);
-    vs->csock = -1;
-}
-
-static void vnc_disconnect_finish(VncState *vs)
-{
-    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
-
-    buffer_free(&vs->input);
-    buffer_free(&vs->output);
-
-    qobject_decref(vs->info);
-
-    vnc_zlib_clear(vs);
-    vnc_tight_clear(vs);
-
-#ifdef CONFIG_VNC_TLS
-    vnc_tls_client_cleanup(vs);
-#endif /* CONFIG_VNC_TLS */
-#ifdef CONFIG_VNC_SASL
-    vnc_sasl_client_cleanup(vs);
-#endif /* CONFIG_VNC_SASL */
-    audio_del(vs);
-
-    QTAILQ_REMOVE(&vs->vd->clients, vs, next);
-
-    if (QTAILQ_EMPTY(&vs->vd->clients)) {
-        dcl->idle = 1;
-    }
-
-    qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
-    vnc_remove_timer(vs->vd);
-    if (vs->vd->lock_key_sync)
-        qemu_remove_led_event_handler(vs->led);
-    qemu_free(vs);
-}
-
-int vnc_client_io_error(VncState *vs, int ret, int last_errno)
-{
-    if (ret == 0 || ret == -1) {
-        if (ret == -1) {
-            switch (last_errno) {
-                case EINTR:
-                case EAGAIN:
-#ifdef _WIN32
-                case WSAEWOULDBLOCK:
-#endif
-                    return 0;
-                default:
-                    break;
-            }
-        }
-
-        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
-                  ret, ret < 0 ? last_errno : 0);
-        vnc_disconnect_start(vs);
-
-        return 0;
-    }
-    return ret;
-}
-
-
-void vnc_client_error(VncState *vs)
-{
-    VNC_DEBUG("Closing down client sock: protocol error\n");
-    vnc_disconnect_start(vs);
-}
-
-
-/*
- * Called to write a chunk of data to the client socket. The data may
- * be the raw data, or may have already been encoded by SASL.
- * The data will be written either straight onto the socket, or
- * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
- *
- * NB, it is theoretically possible to have 2 layers of encryption,
- * both SASL, and this TLS layer. It is highly unlikely in practice
- * though, since SASL encryption will typically be a no-op if TLS
- * is active
- *
- * Returns the number of bytes written, which may be less than
- * the requested 'datalen' if the socket would block. Returns
- * -1 on error, and disconnects the client socket.
- */
-long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
-{
-    long ret;
-#ifdef CONFIG_VNC_TLS
-    if (vs->tls.session) {
-        ret = gnutls_write(vs->tls.session, data, datalen);
-        if (ret < 0) {
-            if (ret == GNUTLS_E_AGAIN)
-                errno = EAGAIN;
-            else
-                errno = EIO;
-            ret = -1;
-        }
-    } else
-#endif /* CONFIG_VNC_TLS */
-        ret = send(vs->csock, (const void *)data, datalen, 0);
-    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
-    return vnc_client_io_error(vs, ret, socket_error());
-}
-
-
-/*
- * Called to write buffered data to the client socket, when not
- * using any SASL SSF encryption layers. Will write as much data
- * as possible without blocking. If all buffered data is written,
- * will switch the FD poll() handler back to read monitoring.
- *
- * Returns the number of bytes written, which may be less than
- * the buffered output data if the socket would block. Returns
- * -1 on error, and disconnects the client socket.
- */
-static long vnc_client_write_plain(VncState *vs)
-{
-    long ret;
-
-#ifdef CONFIG_VNC_SASL
-    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
-              vs->output.buffer, vs->output.capacity, vs->output.offset,
-              vs->sasl.waitWriteSSF);
-
-    if (vs->sasl.conn &&
-        vs->sasl.runSSF &&
-        vs->sasl.waitWriteSSF) {
-        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
-        if (ret)
-            vs->sasl.waitWriteSSF -= ret;
-    } else
-#endif /* CONFIG_VNC_SASL */
-        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
-    if (!ret)
-        return 0;
-
-    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
-    vs->output.offset -= ret;
-
-    if (vs->output.offset == 0) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
-    }
-
-    return ret;
-}
-
-
-/*
- * First function called whenever there is data to be written to
- * the client socket. Will delegate actual work according to whether
- * SASL SSF layers are enabled (thus requiring encryption calls)
- */
-void vnc_client_write(void *opaque)
-{
-    VncState *vs = opaque;
-
-#ifdef CONFIG_VNC_SASL
-    if (vs->sasl.conn &&
-        vs->sasl.runSSF &&
-        !vs->sasl.waitWriteSSF) {
-        vnc_client_write_sasl(vs);
-    } else
-#endif /* CONFIG_VNC_SASL */
-        vnc_client_write_plain(vs);
-}
-
-void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
-{
-    vs->read_handler = func;
-    vs->read_handler_expect = expecting;
-}
-
-
-/*
- * Called to read a chunk of data from the client socket. The data may
- * be the raw data, or may need to be further decoded by SASL.
- * The data will be read either straight from to the socket, or
- * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
- *
- * NB, it is theoretically possible to have 2 layers of encryption,
- * both SASL, and this TLS layer. It is highly unlikely in practice
- * though, since SASL encryption will typically be a no-op if TLS
- * is active
- *
- * Returns the number of bytes read, which may be less than
- * the requested 'datalen' if the socket would block. Returns
- * -1 on error, and disconnects the client socket.
- */
-long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
-{
-    long ret;
-#ifdef CONFIG_VNC_TLS
-    if (vs->tls.session) {
-        ret = gnutls_read(vs->tls.session, data, datalen);
-        if (ret < 0) {
-            if (ret == GNUTLS_E_AGAIN)
-                errno = EAGAIN;
-            else
-                errno = EIO;
-            ret = -1;
-        }
-    } else
-#endif /* CONFIG_VNC_TLS */
-        ret = recv(vs->csock, (void *)data, datalen, 0);
-    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
-    return vnc_client_io_error(vs, ret, socket_error());
-}
-
-
-/*
- * Called to read data from the client socket to the input buffer,
- * when not using any SASL SSF encryption layers. Will read as much
- * data as possible without blocking.
- *
- * Returns the number of bytes read. Returns -1 on error, and
- * disconnects the client socket.
- */
-static long vnc_client_read_plain(VncState *vs)
-{
-    int ret;
-    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
-              vs->input.buffer, vs->input.capacity, vs->input.offset);
-    buffer_reserve(&vs->input, 4096);
-    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
-    if (!ret)
-        return 0;
-    vs->input.offset += ret;
-    return ret;
-}
-
-
-/*
- * First function called whenever there is more data to be read from
- * the client socket. Will delegate actual work according to whether
- * SASL SSF layers are enabled (thus requiring decryption calls)
- */
-void vnc_client_read(void *opaque)
-{
-    VncState *vs = opaque;
-    long ret;
-
-#ifdef CONFIG_VNC_SASL
-    if (vs->sasl.conn && vs->sasl.runSSF)
-        ret = vnc_client_read_sasl(vs);
-    else
-#endif /* CONFIG_VNC_SASL */
-        ret = vnc_client_read_plain(vs);
-    if (!ret) {
-        if (vs->csock == -1)
-            vnc_disconnect_finish(vs);
-        return;
-    }
-
-    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
-        size_t len = vs->read_handler_expect;
-        int ret;
-
-        ret = vs->read_handler(vs, vs->input.buffer, len);
-        if (vs->csock == -1) {
-            vnc_disconnect_finish(vs);
-            return;
-        }
-
-        if (!ret) {
-            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
-            vs->input.offset -= len;
-        } else {
-            vs->read_handler_expect = ret;
-        }
-    }
-}
-
-void vnc_write(VncState *vs, const void *data, size_t len)
-{
-    buffer_reserve(&vs->output, len);
-
-    if (vs->csock != -1 && buffer_empty(&vs->output)) {
-        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
-    }
-
-    buffer_append(&vs->output, data, len);
-}
-
-void vnc_write_s32(VncState *vs, int32_t value)
-{
-    vnc_write_u32(vs, *(uint32_t *)&value);
-}
-
-void vnc_write_u32(VncState *vs, uint32_t value)
-{
-    uint8_t buf[4];
-
-    buf[0] = (value >> 24) & 0xFF;
-    buf[1] = (value >> 16) & 0xFF;
-    buf[2] = (value >>  8) & 0xFF;
-    buf[3] = value & 0xFF;
-
-    vnc_write(vs, buf, 4);
-}
-
-void vnc_write_u16(VncState *vs, uint16_t value)
-{
-    uint8_t buf[2];
-
-    buf[0] = (value >> 8) & 0xFF;
-    buf[1] = value & 0xFF;
-
-    vnc_write(vs, buf, 2);
-}
-
-void vnc_write_u8(VncState *vs, uint8_t value)
-{
-    vnc_write(vs, (char *)&value, 1);
-}
-
-void vnc_flush(VncState *vs)
-{
-    if (vs->csock != -1 && vs->output.offset)
-        vnc_client_write(vs);
-}
-
-uint8_t read_u8(uint8_t *data, size_t offset)
-{
-    return data[offset];
-}
-
-uint16_t read_u16(uint8_t *data, size_t offset)
-{
-    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
-}
-
-int32_t read_s32(uint8_t *data, size_t offset)
-{
-    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
-                     (data[offset + 2] << 8) | data[offset + 3]);
-}
-
-uint32_t read_u32(uint8_t *data, size_t offset)
-{
-    return ((data[offset] << 24) | (data[offset + 1] << 16) |
-            (data[offset + 2] << 8) | data[offset + 3]);
-}
-
-static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
-{
-}
-
-static void check_pointer_type_change(Notifier *notifier)
-{
-    VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
-    int absolute = kbd_mouse_is_absolute();
-
-    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
-        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-        vnc_write_u8(vs, 0);
-        vnc_write_u16(vs, 1);
-        vnc_framebuffer_update(vs, absolute, 0,
-                               ds_get_width(vs->ds), ds_get_height(vs->ds),
-                               VNC_ENCODING_POINTER_TYPE_CHANGE);
-        vnc_flush(vs);
-    }
-    vs->absolute = absolute;
-}
-
-static void pointer_event(VncState *vs, int button_mask, int x, int y)
-{
-    int buttons = 0;
-    int dz = 0;
-
-    if (button_mask & 0x01)
-        buttons |= MOUSE_EVENT_LBUTTON;
-    if (button_mask & 0x02)
-        buttons |= MOUSE_EVENT_MBUTTON;
-    if (button_mask & 0x04)
-        buttons |= MOUSE_EVENT_RBUTTON;
-    if (button_mask & 0x08)
-        dz = -1;
-    if (button_mask & 0x10)
-        dz = 1;
-
-    if (vs->absolute) {
-        kbd_mouse_event(ds_get_width(vs->ds) > 1 ?
-                          x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000,
-                        ds_get_height(vs->ds) > 1 ?
-                          y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000,
-                        dz, buttons);
-    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
-        x -= 0x7FFF;
-        y -= 0x7FFF;
-
-        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;
-    }
-}
-
-static void reset_keys(VncState *vs)
-{
-    int i;
-    for(i = 0; i < 256; i++) {
-        if (vs->modifiers_state[i]) {
-            if (i & SCANCODE_GREY)
-                kbd_put_keycode(SCANCODE_EMUL0);
-            kbd_put_keycode(i | SCANCODE_UP);
-            vs->modifiers_state[i] = 0;
-        }
-    }
-}
-
-static void press_key(VncState *vs, int keysym)
-{
-    int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
-    if (keycode & SCANCODE_GREY)
-        kbd_put_keycode(SCANCODE_EMUL0);
-    kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
-    if (keycode & SCANCODE_GREY)
-        kbd_put_keycode(SCANCODE_EMUL0);
-    kbd_put_keycode(keycode | SCANCODE_UP);
-}
-
-static void kbd_leds(void *opaque, int ledstate)
-{
-    VncState *vs = opaque;
-    int caps, num;
-
-    caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
-    num  = ledstate & QEMU_NUM_LOCK_LED  ? 1 : 0;
-
-    if (vs->modifiers_state[0x3a] != caps) {
-        vs->modifiers_state[0x3a] = caps;
-    }
-    if (vs->modifiers_state[0x45] != num) {
-        vs->modifiers_state[0x45] = num;
-    }
-}
-
-static void do_key_event(VncState *vs, int down, int keycode, int sym)
-{
-    /* QEMU console switch */
-    switch(keycode) {
-    case 0x2a:                          /* Left Shift */
-    case 0x36:                          /* Right Shift */
-    case 0x1d:                          /* Left CTRL */
-    case 0x9d:                          /* Right CTRL */
-    case 0x38:                          /* Left ALT */
-    case 0xb8:                          /* Right ALT */
-        if (down)
-            vs->modifiers_state[keycode] = 1;
-        else
-            vs->modifiers_state[keycode] = 0;
-        break;
-    case 0x02 ... 0x0a: /* '1' to '9' keys */
-        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
-            /* Reset the modifiers sent to the current console */
-            reset_keys(vs);
-            console_select(keycode - 0x02);
-            return;
-        }
-        break;
-    case 0x3a:                        /* CapsLock */
-    case 0x45:                        /* NumLock */
-        if (down)
-            vs->modifiers_state[keycode] ^= 1;
-        break;
-    }
-
-    if (vs->vd->lock_key_sync &&
-        keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
-        /* If the numlock state needs to change then simulate an additional
-           keypress before sending this one.  This will happen if the user
-           toggles numlock away from the VNC window.
-        */
-        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
-            if (!vs->modifiers_state[0x45]) {
-                vs->modifiers_state[0x45] = 1;
-                press_key(vs, 0xff7f);
-            }
-        } else {
-            if (vs->modifiers_state[0x45]) {
-                vs->modifiers_state[0x45] = 0;
-                press_key(vs, 0xff7f);
-            }
-        }
-    }
-
-    if (vs->vd->lock_key_sync &&
-        ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
-        /* If the capslock state needs to change then simulate an additional
-           keypress before sending this one.  This will happen if the user
-           toggles capslock away from the VNC window.
-        */
-        int uppercase = !!(sym >= 'A' && sym <= 'Z');
-        int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
-        int capslock = !!(vs->modifiers_state[0x3a]);
-        if (capslock) {
-            if (uppercase == shift) {
-                vs->modifiers_state[0x3a] = 0;
-                press_key(vs, 0xffe5);
-            }
-        } else {
-            if (uppercase != shift) {
-                vs->modifiers_state[0x3a] = 1;
-                press_key(vs, 0xffe5);
-            }
-        }
-    }
-
-    if (is_graphic_console()) {
-        if (keycode & SCANCODE_GREY)
-            kbd_put_keycode(SCANCODE_EMUL0);
-        if (down)
-            kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
-        else
-            kbd_put_keycode(keycode | SCANCODE_UP);
-    } else {
-        /* QEMU console emulation */
-        if (down) {
-            int numlock = vs->modifiers_state[0x45];
-            switch (keycode) {
-            case 0x2a:                          /* Left Shift */
-            case 0x36:                          /* Right Shift */
-            case 0x1d:                          /* Left CTRL */
-            case 0x9d:                          /* Right CTRL */
-            case 0x38:                          /* Left ALT */
-            case 0xb8:                          /* Right ALT */
-                break;
-            case 0xc8:
-                kbd_put_keysym(QEMU_KEY_UP);
-                break;
-            case 0xd0:
-                kbd_put_keysym(QEMU_KEY_DOWN);
-                break;
-            case 0xcb:
-                kbd_put_keysym(QEMU_KEY_LEFT);
-                break;
-            case 0xcd:
-                kbd_put_keysym(QEMU_KEY_RIGHT);
-                break;
-            case 0xd3:
-                kbd_put_keysym(QEMU_KEY_DELETE);
-                break;
-            case 0xc7:
-                kbd_put_keysym(QEMU_KEY_HOME);
-                break;
-            case 0xcf:
-                kbd_put_keysym(QEMU_KEY_END);
-                break;
-            case 0xc9:
-                kbd_put_keysym(QEMU_KEY_PAGEUP);
-                break;
-            case 0xd1:
-                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
-                break;
-
-            case 0x47:
-                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
-                break;
-            case 0x48:
-                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
-                break;
-            case 0x49:
-                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
-                break;
-            case 0x4b:
-                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
-                break;
-            case 0x4c:
-                kbd_put_keysym('5');
-                break;
-            case 0x4d:
-                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
-                break;
-            case 0x4f:
-                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
-                break;
-            case 0x50:
-                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
-                break;
-            case 0x51:
-                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
-                break;
-            case 0x52:
-                kbd_put_keysym('0');
-                break;
-            case 0x53:
-                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
-                break;
-
-            case 0xb5:
-                kbd_put_keysym('/');
-                break;
-            case 0x37:
-                kbd_put_keysym('*');
-                break;
-            case 0x4a:
-                kbd_put_keysym('-');
-                break;
-            case 0x4e:
-                kbd_put_keysym('+');
-                break;
-            case 0x9c:
-                kbd_put_keysym('\n');
-                break;
-
-            default:
-                kbd_put_keysym(sym);
-                break;
-            }
-        }
-    }
-}
-
-static void key_event(VncState *vs, int down, uint32_t sym)
-{
-    int keycode;
-    int lsym = sym;
-
-    if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
-        lsym = lsym - 'A' + 'a';
-    }
-
-    keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
-    do_key_event(vs, down, keycode, sym);
-}
-
-static void ext_key_event(VncState *vs, int down,
-                          uint32_t sym, uint16_t keycode)
-{
-    /* if the user specifies a keyboard layout, always use it */
-    if (keyboard_layout)
-        key_event(vs, down, sym);
-    else
-        do_key_event(vs, down, keycode, sym);
-}
-
-static void framebuffer_update_request(VncState *vs, int incremental,
-                                       int x_position, int y_position,
-                                       int w, int h)
-{
-    if (y_position > ds_get_height(vs->ds))
-        y_position = ds_get_height(vs->ds);
-    if (y_position + h >= ds_get_height(vs->ds))
-        h = ds_get_height(vs->ds) - y_position;
-
-    int i;
-    vs->need_update = 1;
-    if (!incremental) {
-        vs->force_update = 1;
-        for (i = 0; i < h; i++) {
-            vnc_set_bits(vs->dirty[y_position + i],
-                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
-        }
-    }
-}
-
-static void send_ext_key_event_ack(VncState *vs)
-{
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-    vnc_write_u8(vs, 0);
-    vnc_write_u16(vs, 1);
-    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
-                           VNC_ENCODING_EXT_KEY_EVENT);
-    vnc_flush(vs);
-}
-
-static void send_ext_audio_ack(VncState *vs)
-{
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-    vnc_write_u8(vs, 0);
-    vnc_write_u16(vs, 1);
-    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
-                           VNC_ENCODING_AUDIO);
-    vnc_flush(vs);
-}
-
-static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
-{
-    int i;
-    unsigned int enc = 0;
-
-    vs->features = 0;
-    vs->vnc_encoding = 0;
-    vs->tight_compression = 9;
-    vs->tight_quality = -1; /* Lossless by default */
-    vs->absolute = -1;
-
-    /*
-     * Start from the end because the encodings are sent in order of preference.
-     * This way the prefered encoding (first encoding defined in the array)
-     * will be set at the end of the loop.
-     */
-    for (i = n_encodings - 1; i >= 0; i--) {
-        enc = encodings[i];
-        switch (enc) {
-        case VNC_ENCODING_RAW:
-            vs->vnc_encoding = enc;
-            break;
-        case VNC_ENCODING_COPYRECT:
-            vs->features |= VNC_FEATURE_COPYRECT_MASK;
-            break;
-        case VNC_ENCODING_HEXTILE:
-            vs->features |= VNC_FEATURE_HEXTILE_MASK;
-            vs->vnc_encoding = enc;
-            break;
-        case VNC_ENCODING_TIGHT:
-            vs->features |= VNC_FEATURE_TIGHT_MASK;
-            vs->vnc_encoding = enc;
-            break;
-        case VNC_ENCODING_ZLIB:
-            vs->features |= VNC_FEATURE_ZLIB_MASK;
-            vs->vnc_encoding = enc;
-            break;
-        case VNC_ENCODING_DESKTOPRESIZE:
-            vs->features |= VNC_FEATURE_RESIZE_MASK;
-            break;
-        case VNC_ENCODING_POINTER_TYPE_CHANGE:
-            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
-            break;
-        case VNC_ENCODING_RICH_CURSOR:
-            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
-            break;
-        case VNC_ENCODING_EXT_KEY_EVENT:
-            send_ext_key_event_ack(vs);
-            break;
-        case VNC_ENCODING_AUDIO:
-            send_ext_audio_ack(vs);
-            break;
-        case VNC_ENCODING_WMVi:
-            vs->features |= VNC_FEATURE_WMVI_MASK;
-            break;
-        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
-            vs->tight_compression = (enc & 0x0F);
-            break;
-        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
-            vs->tight_quality = (enc & 0x0F);
-            break;
-        default:
-            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
-            break;
-        }
-    }
-    vnc_desktop_resize(vs);
-    check_pointer_type_change(&vs->mouse_mode_notifier);
-}
-
-static void set_pixel_conversion(VncState *vs)
-{
-    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
-        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
-        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
-        vs->write_pixels = vnc_write_pixels_copy;
-        vnc_hextile_set_pixel_conversion(vs, 0);
-    } else {
-        vs->write_pixels = vnc_write_pixels_generic;
-        vnc_hextile_set_pixel_conversion(vs, 1);
-    }
-}
-
-static void set_pixel_format(VncState *vs,
-                             int bits_per_pixel, int depth,
-                             int big_endian_flag, int true_color_flag,
-                             int red_max, int green_max, int blue_max,
-                             int red_shift, int green_shift, int blue_shift)
-{
-    if (!true_color_flag) {
-        vnc_client_error(vs);
-        return;
-    }
-
-    vs->clientds = *(vs->vd->guest.ds);
-    vs->clientds.pf.rmax = red_max;
-    count_bits(vs->clientds.pf.rbits, red_max);
-    vs->clientds.pf.rshift = red_shift;
-    vs->clientds.pf.rmask = red_max << red_shift;
-    vs->clientds.pf.gmax = green_max;
-    count_bits(vs->clientds.pf.gbits, green_max);
-    vs->clientds.pf.gshift = green_shift;
-    vs->clientds.pf.gmask = green_max << green_shift;
-    vs->clientds.pf.bmax = blue_max;
-    count_bits(vs->clientds.pf.bbits, blue_max);
-    vs->clientds.pf.bshift = blue_shift;
-    vs->clientds.pf.bmask = blue_max << blue_shift;
-    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
-    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
-    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
-    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
-
-    set_pixel_conversion(vs);
-
-    vga_hw_invalidate();
-    vga_hw_update();
-}
-
-static void pixel_format_message (VncState *vs) {
-    char pad[3] = { 0, 0, 0 };
-
-    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
-    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
-
-#ifdef HOST_WORDS_BIGENDIAN
-    vnc_write_u8(vs, 1);             /* big-endian-flag */
-#else
-    vnc_write_u8(vs, 0);             /* big-endian-flag */
-#endif
-    vnc_write_u8(vs, 1);             /* true-color-flag */
-    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
-    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
-    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
-    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
-    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
-    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
-
-    vnc_hextile_set_pixel_conversion(vs, 0);
-
-    vs->clientds = *(vs->ds->surface);
-    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
-    vs->write_pixels = vnc_write_pixels_copy;
-
-    vnc_write(vs, pad, 3);           /* padding */
-}
-
-static void vnc_dpy_setdata(DisplayState *ds)
-{
-    /* We don't have to do anything */
-}
-
-static void vnc_colordepth(VncState *vs)
-{
-    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
-        /* Sending a WMVi message to notify the client*/
-        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-        vnc_write_u8(vs, 0);
-        vnc_write_u16(vs, 1); /* number of rects */
-        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
-                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
-        pixel_format_message(vs);
-        vnc_flush(vs);
-    } else {
-        set_pixel_conversion(vs);
-    }
-}
-
-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 VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
-        if (len == 1)
-            return 20;
-
-        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
-                         read_u8(data, 6), read_u8(data, 7),
-                         read_u16(data, 8), read_u16(data, 10),
-                         read_u16(data, 12), read_u8(data, 14),
-                         read_u8(data, 15), read_u8(data, 16));
-        break;
-    case VNC_MSG_CLIENT_SET_ENCODINGS:
-        if (len == 1)
-            return 4;
-
-        if (len == 4) {
-            limit = read_u16(data, 2);
-            if (limit > 0)
-                return 4 + (limit * 4);
-        } else
-            limit = read_u16(data, 2);
-
-        for (i = 0; i < limit; i++) {
-            int32_t val = read_s32(data, 4 + (i * 4));
-            memcpy(data + 4 + (i * 4), &val, sizeof(val));
-        }
-
-        set_encodings(vs, (int32_t *)(data + 4), limit);
-        break;
-    case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
-        if (len == 1)
-            return 10;
-
-        framebuffer_update_request(vs,
-                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
-                                   read_u16(data, 6), read_u16(data, 8));
-        break;
-    case VNC_MSG_CLIENT_KEY_EVENT:
-        if (len == 1)
-            return 8;
-
-        key_event(vs, read_u8(data, 1), read_u32(data, 4));
-        break;
-    case VNC_MSG_CLIENT_POINTER_EVENT:
-        if (len == 1)
-            return 6;
-
-        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
-        break;
-    case VNC_MSG_CLIENT_CUT_TEXT:
-        if (len == 1)
-            return 8;
-
-        if (len == 8) {
-            uint32_t dlen = read_u32(data, 4);
-            if (dlen > 0)
-                return 8 + dlen;
-        }
-
-        client_cut_text(vs, read_u32(data, 4), data + 8);
-        break;
-    case VNC_MSG_CLIENT_QEMU:
-        if (len == 1)
-            return 2;
-
-        switch (read_u8(data, 1)) {
-        case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
-            if (len == 2)
-                return 12;
-
-            ext_key_event(vs, read_u16(data, 2),
-                          read_u32(data, 4), read_u32(data, 8));
-            break;
-        case VNC_MSG_CLIENT_QEMU_AUDIO:
-            if (len == 2)
-                return 4;
-
-            switch (read_u16 (data, 2)) {
-            case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
-                audio_add(vs);
-                break;
-            case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
-                audio_del(vs);
-                break;
-            case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
-                if (len == 4)
-                    return 10;
-                switch (read_u8(data, 4)) {
-                case 0: vs->as.fmt = AUD_FMT_U8; break;
-                case 1: vs->as.fmt = AUD_FMT_S8; break;
-                case 2: vs->as.fmt = AUD_FMT_U16; break;
-                case 3: vs->as.fmt = AUD_FMT_S16; break;
-                case 4: vs->as.fmt = AUD_FMT_U32; break;
-                case 5: vs->as.fmt = AUD_FMT_S32; break;
-                default:
-                    printf("Invalid audio format %d\n", read_u8(data, 4));
-                    vnc_client_error(vs);
-                    break;
-                }
-                vs->as.nchannels = read_u8(data, 5);
-                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
-                    printf("Invalid audio channel coount %d\n",
-                           read_u8(data, 5));
-                    vnc_client_error(vs);
-                    break;
-                }
-                vs->as.freq = read_u32(data, 6);
-                break;
-            default:
-                printf ("Invalid audio message %d\n", read_u8(data, 4));
-                vnc_client_error(vs);
-                break;
-            }
-            break;
-
-        default:
-            printf("Msg: %d\n", read_u16(data, 0));
-            vnc_client_error(vs);
-            break;
-        }
-        break;
-    default:
-        printf("Msg: %d\n", data[0]);
-        vnc_client_error(vs);
-        break;
-    }
-
-    vnc_read_when(vs, protocol_client_msg, 1);
-    return 0;
-}
-
-static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
-{
-    char buf[1024];
-    int size;
-
-    vs->client_width = ds_get_width(vs->ds);
-    vs->client_height = ds_get_height(vs->ds);
-    vnc_write_u16(vs, vs->client_width);
-    vnc_write_u16(vs, vs->client_height);
-
-    pixel_format_message(vs);
-
-    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_client_cache_auth(vs);
-    vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
-
-    vnc_read_when(vs, protocol_client_msg, 1);
-
-    return 0;
-}
-
-void start_client_init(VncState *vs)
-{
-    vnc_read_when(vs, protocol_client_init, 1);
-}
-
-static void make_challenge(VncState *vs)
-{
-    int i;
-
-    srand(time(NULL)+getpid()+getpid()*987654+rand());
-
-    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
-        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
-}
-
-static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
-{
-    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
-    int i, j, pwlen;
-    unsigned char key[8];
-
-    if (!vs->vd->password || !vs->vd->password[0]) {
-        VNC_DEBUG("No password configured on server");
-        vnc_write_u32(vs, 1); /* Reject auth */
-        if (vs->minor >= 8) {
-            static const char err[] = "Authentication failed";
-            vnc_write_u32(vs, sizeof(err));
-            vnc_write(vs, err, sizeof(err));
-        }
-        vnc_flush(vs);
-        vnc_client_error(vs);
-        return 0;
-    }
-
-    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
-
-    /* Calculate the expected challenge response */
-    pwlen = strlen(vs->vd->password);
-    for (i=0; i<sizeof(key); i++)
-        key[i] = i<pwlen ? vs->vd->password[i] : 0;
-    deskey(key, EN0);
-    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
-        des(response+j, response+j);
-
-    /* Compare expected vs actual challenge response */
-    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
-        VNC_DEBUG("Client challenge reponse did not match\n");
-        vnc_write_u32(vs, 1); /* Reject auth */
-        if (vs->minor >= 8) {
-            static const char err[] = "Authentication failed";
-            vnc_write_u32(vs, sizeof(err));
-            vnc_write(vs, err, sizeof(err));
-        }
-        vnc_flush(vs);
-        vnc_client_error(vs);
-    } else {
-        VNC_DEBUG("Accepting VNC challenge response\n");
-        vnc_write_u32(vs, 0); /* Accept auth */
-        vnc_flush(vs);
-
-        start_client_init(vs);
-    }
-    return 0;
-}
-
-void start_auth_vnc(VncState *vs)
-{
-    make_challenge(vs);
-    /* Send client a 'random' challenge */
-    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
-    vnc_flush(vs);
-
-    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
-}
-
-
-static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
-{
-    /* We only advertise 1 auth scheme at a time, so client
-     * must pick the one we sent. Verify this */
-    if (data[0] != vs->vd->auth) { /* Reject auth */
-       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
-       vnc_write_u32(vs, 1);
-       if (vs->minor >= 8) {
-           static const char err[] = "Authentication failed";
-           vnc_write_u32(vs, sizeof(err));
-           vnc_write(vs, err, sizeof(err));
-       }
-       vnc_client_error(vs);
-    } else { /* Accept requested auth */
-       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
-       switch (vs->vd->auth) {
-       case VNC_AUTH_NONE:
-           VNC_DEBUG("Accept auth none\n");
-           if (vs->minor >= 8) {
-               vnc_write_u32(vs, 0); /* Accept auth completion */
-               vnc_flush(vs);
-           }
-           start_client_init(vs);
-           break;
-
-       case VNC_AUTH_VNC:
-           VNC_DEBUG("Start VNC auth\n");
-           start_auth_vnc(vs);
-           break;
-
-#ifdef CONFIG_VNC_TLS
-       case VNC_AUTH_VENCRYPT:
-           VNC_DEBUG("Accept VeNCrypt auth\n");;
-           start_auth_vencrypt(vs);
-           break;
-#endif /* CONFIG_VNC_TLS */
-
-#ifdef CONFIG_VNC_SASL
-       case VNC_AUTH_SASL:
-           VNC_DEBUG("Accept SASL auth\n");
-           start_auth_sasl(vs);
-           break;
-#endif /* CONFIG_VNC_SASL */
-
-       default: /* Should not be possible, but just in case */
-           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
-           vnc_write_u8(vs, 1);
-           if (vs->minor >= 8) {
-               static const char err[] = "Authentication failed";
-               vnc_write_u32(vs, sizeof(err));
-               vnc_write(vs, err, sizeof(err));
-           }
-           vnc_client_error(vs);
-       }
-    }
-    return 0;
-}
-
-static int protocol_version(VncState *vs, uint8_t *version, size_t len)
-{
-    char local[13];
-
-    memcpy(local, version, 12);
-    local[12] = 0;
-
-    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
-        VNC_DEBUG("Malformed protocol version %s\n", local);
-        vnc_client_error(vs);
-        return 0;
-    }
-    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
-    if (vs->major != 3 ||
-        (vs->minor != 3 &&
-         vs->minor != 4 &&
-         vs->minor != 5 &&
-         vs->minor != 7 &&
-         vs->minor != 8)) {
-        VNC_DEBUG("Unsupported client version\n");
-        vnc_write_u32(vs, VNC_AUTH_INVALID);
-        vnc_flush(vs);
-        vnc_client_error(vs);
-        return 0;
-    }
-    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
-     * as equivalent to v3.3 by servers
-     */
-    if (vs->minor == 4 || vs->minor == 5)
-        vs->minor = 3;
-
-    if (vs->minor == 3) {
-        if (vs->vd->auth == VNC_AUTH_NONE) {
-            VNC_DEBUG("Tell client auth none\n");
-            vnc_write_u32(vs, vs->vd->auth);
-            vnc_flush(vs);
-            start_client_init(vs);
-       } else if (vs->vd->auth == VNC_AUTH_VNC) {
-            VNC_DEBUG("Tell client VNC auth\n");
-            vnc_write_u32(vs, vs->vd->auth);
-            vnc_flush(vs);
-            start_auth_vnc(vs);
-       } else {
-            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
-            vnc_write_u32(vs, VNC_AUTH_INVALID);
-            vnc_flush(vs);
-            vnc_client_error(vs);
-       }
-    } else {
-        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
-        vnc_write_u8(vs, 1); /* num auth */
-        vnc_write_u8(vs, vs->vd->auth);
-        vnc_read_when(vs, protocol_client_auth, 1);
-        vnc_flush(vs);
-    }
-
-    return 0;
-}
-
-static int vnc_refresh_server_surface(VncDisplay *vd)
-{
-    int y;
-    uint8_t *guest_row;
-    uint8_t *server_row;
-    int cmp_bytes;
-    uint32_t width_mask[VNC_DIRTY_WORDS];
-    VncState *vs;
-    int has_dirty = 0;
-
-    /*
-     * Walk through the guest dirty map.
-     * Check and copy modified bits from guest to server surface.
-     * Update server dirty map.
-     */
-    vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
-    cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
-    guest_row  = vd->guest.ds->data;
-    server_row = vd->server->data;
-    for (y = 0; y < vd->guest.ds->height; y++) {
-        if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
-            int x;
-            uint8_t *guest_ptr;
-            uint8_t *server_ptr;
-
-            guest_ptr  = guest_row;
-            server_ptr = server_row;
-
-            for (x = 0; x < vd->guest.ds->width;
-                    x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
-                if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
-                    continue;
-                vnc_clear_bit(vd->guest.dirty[y], (x / 16));
-                if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
-                    continue;
-                memcpy(server_ptr, guest_ptr, cmp_bytes);
-                QTAILQ_FOREACH(vs, &vd->clients, next) {
-                    vnc_set_bit(vs->dirty[y], (x / 16));
-                }
-                has_dirty++;
-            }
-        }
-        guest_row  += ds_get_linesize(vd->ds);
-        server_row += ds_get_linesize(vd->ds);
-    }
-    return has_dirty;
-}
-
-static void vnc_refresh(void *opaque)
-{
-    VncDisplay *vd = opaque;
-    VncState *vs, *vn;
-    int has_dirty, rects = 0;
-
-    vga_hw_update();
-
-    has_dirty = vnc_refresh_server_surface(vd);
-
-    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
-        rects += vnc_update_client(vs, has_dirty);
-        /* vs might be free()ed here */
-    }
-    /* vd->timer could be NULL now if the last client disconnected,
-     * in this case don't update the timer */
-    if (vd->timer == NULL)
-        return;
-
-    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 && !QTAILQ_EMPTY(&vd->clients)) {
-        vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
-        vnc_refresh(vd);
-    }
-}
-
-static void vnc_remove_timer(VncDisplay *vd)
-{
-    if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) {
-        qemu_del_timer(vd->timer);
-        qemu_free_timer(vd->timer);
-        vd->timer = NULL;
-    }
-}
-
-static void vnc_connect(VncDisplay *vd, int csock)
-{
-    VncState *vs = qemu_mallocz(sizeof(VncState));
-    vs->csock = csock;
-
-    VNC_DEBUG("New client on socket %d\n", csock);
-    dcl->idle = 0;
-    socket_set_nonblock(vs->csock);
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
-
-    vnc_client_cache_addr(vs);
-    vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
-
-    vs->vd = vd;
-    vs->ds = vd->ds;
-    vs->last_x = -1;
-    vs->last_y = -1;
-
-    vs->as.freq = 44100;
-    vs->as.nchannels = 2;
-    vs->as.fmt = AUD_FMT_S16;
-    vs->as.endianness = 0;
-
-    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
-
-    vga_hw_update();
-
-    vnc_write(vs, "RFB 003.008\n", 12);
-    vnc_flush(vs);
-    vnc_read_when(vs, protocol_version, 12);
-    reset_keys(vs);
-    if (vs->vd->lock_key_sync)
-        vs->led = qemu_add_led_event_handler(kbd_leds, vs);
-
-    vs->mouse_mode_notifier.notify = check_pointer_type_change;
-    qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
-
-    vnc_init_timer(vd);
-
-    /* vs might be free()ed here */
-}
-
-static void vnc_listen_read(void *opaque)
-{
-    VncDisplay *vs = opaque;
-    struct sockaddr_in addr;
-    socklen_t addrlen = sizeof(addr);
-
-    /* Catch-up */
-    vga_hw_update();
-
-    int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
-    if (csock != -1) {
-        vnc_connect(vs, csock);
-    }
-}
-
-void vnc_display_init(DisplayState *ds)
-{
-    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
-
-    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
-
-    ds->opaque = vs;
-    dcl->idle = 1;
-    vnc_display = vs;
-
-    vs->lsock = -1;
-
-    vs->ds = ds;
-    QTAILQ_INIT(&vs->clients);
-
-    if (keyboard_layout)
-        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
-    else
-        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
-
-    if (!vs->kbd_layout)
-        exit(1);
-
-    dcl->dpy_copy = vnc_dpy_copy;
-    dcl->dpy_update = vnc_dpy_update;
-    dcl->dpy_resize = vnc_dpy_resize;
-    dcl->dpy_setdata = vnc_dpy_setdata;
-    register_displaychangelistener(ds, dcl);
-    ds->mouse_set = vnc_mouse_set;
-    ds->cursor_define = vnc_dpy_cursor_define;
-}
-
-
-void vnc_display_close(DisplayState *ds)
-{
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
-
-    if (!vs)
-        return;
-    if (vs->display) {
-        qemu_free(vs->display);
-        vs->display = NULL;
-    }
-    if (vs->lsock != -1) {
-        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
-        close(vs->lsock);
-        vs->lsock = -1;
-    }
-    vs->auth = VNC_AUTH_INVALID;
-#ifdef CONFIG_VNC_TLS
-    vs->subauth = VNC_AUTH_INVALID;
-    vs->tls.x509verify = 0;
-#endif
-}
-
-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;
-    }
-    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;
-}
-
-char *vnc_display_local_addr(DisplayState *ds)
-{
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
-    
-    return vnc_socket_local_addr("%s:%s", vs->lsock);
-}
-
-int vnc_display_open(DisplayState *ds, const char *display)
-{
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
-    const char *options;
-    int password = 0;
-    int reverse = 0;
-#ifdef CONFIG_VNC_TLS
-    int tls = 0, x509 = 0;
-#endif
-#ifdef CONFIG_VNC_SASL
-    int sasl = 0;
-    int saslErr;
-#endif
-    int acl = 0;
-    int lock_key_sync = 1;
-
-    if (!vnc_display)
-        return -1;
-    vnc_display_close(ds);
-    if (strcmp(display, "none") == 0)
-        return 0;
-
-    if (!(vs->display = strdup(display)))
-        return -1;
-
-    options = display;
-    while ((options = strchr(options, ','))) {
-        options++;
-        if (strncmp(options, "password", 8) == 0) {
-            password = 1; /* Require password auth */
-        } else if (strncmp(options, "reverse", 7) == 0) {
-            reverse = 1;
-        } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
-            lock_key_sync = 0;
-#ifdef CONFIG_VNC_SASL
-        } else if (strncmp(options, "sasl", 4) == 0) {
-            sasl = 1; /* Require SASL auth */
-#endif
-#ifdef CONFIG_VNC_TLS
-        } else if (strncmp(options, "tls", 3) == 0) {
-            tls = 1; /* Require TLS */
-        } else if (strncmp(options, "x509", 4) == 0) {
-            char *start, *end;
-            x509 = 1; /* Require x509 certificates */
-            if (strncmp(options, "x509verify", 10) == 0)
-                vs->tls.x509verify = 1; /* ...and verify client certs */
-
-            /* Now check for 'x509=/some/path' postfix
-             * and use that to setup x509 certificate/key paths */
-            start = strchr(options, '=');
-            end = strchr(options, ',');
-            if (start && (!end || (start < end))) {
-                int len = end ? end-(start+1) : strlen(start+1);
-                char *path = qemu_strndup(start + 1, len);
-
-                VNC_DEBUG("Trying certificate path '%s'\n", path);
-                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
-                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
-                    qemu_free(path);
-                    qemu_free(vs->display);
-                    vs->display = NULL;
-                    return -1;
-                }
-                qemu_free(path);
-            } else {
-                fprintf(stderr, "No certificate path provided\n");
-                qemu_free(vs->display);
-                vs->display = NULL;
-                return -1;
-            }
-#endif
-        } else if (strncmp(options, "acl", 3) == 0) {
-            acl = 1;
-        } else if (strncmp(options, "lossy", 5) == 0) {
-            vs->lossy = true;
-        }
-    }
-
-#ifdef CONFIG_VNC_TLS
-    if (acl && x509 && vs->tls.x509verify) {
-        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
-            fprintf(stderr, "Failed to create x509 dname ACL\n");
-            exit(1);
-        }
-    }
-#endif
-#ifdef CONFIG_VNC_SASL
-    if (acl && sasl) {
-        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
-            fprintf(stderr, "Failed to create username ACL\n");
-            exit(1);
-        }
-    }
-#endif
-
-    /*
-     * Combinations we support here:
-     *
-     *  - no-auth                (clear text, no auth)
-     *  - password               (clear text, weak auth)
-     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
-     *  - tls                    (encrypt, weak anonymous creds, no auth)
-     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
-     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
-     *  - tls + x509             (encrypt, good x509 creds, no auth)
-     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
-     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
-     *
-     * NB1. TLS is a stackable auth scheme.
-     * NB2. the x509 schemes have option to validate a client cert dname
-     */
-    if (password) {
-#ifdef CONFIG_VNC_TLS
-        if (tls) {
-            vs->auth = VNC_AUTH_VENCRYPT;
-            if (x509) {
-                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-            } else {
-                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-            }
-        } else {
-#endif /* CONFIG_VNC_TLS */
-            VNC_DEBUG("Initializing VNC server with password auth\n");
-            vs->auth = VNC_AUTH_VNC;
-#ifdef CONFIG_VNC_TLS
-            vs->subauth = VNC_AUTH_INVALID;
-        }
-#endif /* CONFIG_VNC_TLS */
-#ifdef CONFIG_VNC_SASL
-    } else if (sasl) {
-#ifdef CONFIG_VNC_TLS
-        if (tls) {
-            vs->auth = VNC_AUTH_VENCRYPT;
-            if (x509) {
-                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
-            } else {
-                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
-            }
-        } else {
-#endif /* CONFIG_VNC_TLS */
-            VNC_DEBUG("Initializing VNC server with SASL auth\n");
-            vs->auth = VNC_AUTH_SASL;
-#ifdef CONFIG_VNC_TLS
-            vs->subauth = VNC_AUTH_INVALID;
-        }
-#endif /* CONFIG_VNC_TLS */
-#endif /* CONFIG_VNC_SASL */
-    } else {
-#ifdef CONFIG_VNC_TLS
-        if (tls) {
-            vs->auth = VNC_AUTH_VENCRYPT;
-            if (x509) {
-                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
-            } else {
-                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
-                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
-            }
-        } else {
-#endif
-            VNC_DEBUG("Initializing VNC server with no auth\n");
-            vs->auth = VNC_AUTH_NONE;
-#ifdef CONFIG_VNC_TLS
-            vs->subauth = VNC_AUTH_INVALID;
-        }
-#endif
-    }
-
-#ifdef CONFIG_VNC_SASL
-    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
-        fprintf(stderr, "Failed to initialize SASL auth %s",
-                sasl_errstring(saslErr, NULL, NULL));
-        free(vs->display);
-        vs->display = NULL;
-        return -1;
-    }
-#endif
-    vs->lock_key_sync = lock_key_sync;
-
-    if (reverse) {
-        /* connect to viewer */
-        if (strncmp(display, "unix:", 5) == 0)
-            vs->lsock = unix_connect(display+5);
-        else
-            vs->lsock = inet_connect(display, SOCK_STREAM);
-        if (-1 == vs->lsock) {
-            free(vs->display);
-            vs->display = NULL;
-            return -1;
-        } else {
-            int csock = vs->lsock;
-            vs->lsock = -1;
-            vnc_connect(vs, csock);
-        }
-        return 0;
-
-    } else {
-        /* listen for connects */
-        char *dpy;
-        dpy = qemu_malloc(256);
-        if (strncmp(display, "unix:", 5) == 0) {
-            pstrcpy(dpy, 256, "unix:");
-            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
-        } else {
-            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
-        }
-        if (-1 == vs->lsock) {
-            free(dpy);
-            return -1;
-        } else {
-            free(vs->display);
-            vs->display = dpy;
-        }
-    }
-    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
-}
diff --git a/vnc.h b/vnc.h
deleted file mode 100644 (file)
index ec90cd3..0000000
--- a/vnc.h
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * QEMU VNC display driver
- *
- * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
- * Copyright (C) 2006 Fabrice Bellard
- * Copyright (C) 2009 Red Hat, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef __QEMU_VNC_H
-#define __QEMU_VNC_H
-
-#include "qemu-common.h"
-#include "qemu-queue.h"
-#include "console.h"
-#include "monitor.h"
-#include "audio/audio.h"
-#include <zlib.h>
-#include <stdbool.h>
-
-#include "keymaps.h"
-
-// #define _VNC_DEBUG 1
-
-#ifdef _VNC_DEBUG
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define VNC_DEBUG(fmt, ...) do { } while (0)
-#endif
-
-/*****************************************************************************
- *
- * Core data structures
- *
- *****************************************************************************/
-
-typedef struct Buffer
-{
-    size_t capacity;
-    size_t offset;
-    uint8_t *buffer;
-} Buffer;
-
-typedef struct VncState VncState;
-
-typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
-
-typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
-
-typedef void VncSendHextileTile(VncState *vs,
-                                int x, int y, int w, int h,
-                                void *last_bg,
-                                void *last_fg,
-                                int *has_bg, int *has_fg);
-
-#define VNC_MAX_WIDTH 2560
-#define VNC_MAX_HEIGHT 2048
-#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
-
-#define VNC_AUTH_CHALLENGE_SIZE 16
-
-typedef struct VncDisplay VncDisplay;
-
-#ifdef CONFIG_VNC_TLS
-#include "vnc-tls.h"
-#include "vnc-auth-vencrypt.h"
-#endif
-#ifdef CONFIG_VNC_SASL
-#include "vnc-auth-sasl.h"
-#endif
-
-struct VncSurface
-{
-    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
-    DisplaySurface *ds;
-};
-
-struct VncDisplay
-{
-    QTAILQ_HEAD(, VncState) clients;
-    QEMUTimer *timer;
-    int timer_interval;
-    int lsock;
-    DisplayState *ds;
-    kbd_layout_t *kbd_layout;
-    int lock_key_sync;
-
-    QEMUCursor *cursor;
-    int cursor_msize;
-    uint8_t *cursor_mask;
-
-    struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
-    DisplaySurface *server;  /* vnc server surface */
-
-    char *display;
-    char *password;
-    int auth;
-    bool lossy;
-#ifdef CONFIG_VNC_TLS
-    int subauth; /* Used by VeNCrypt */
-    VncDisplayTLS tls;
-#endif
-#ifdef CONFIG_VNC_SASL
-    VncDisplaySASL sasl;
-#endif
-};
-
-struct VncState
-{
-    int csock;
-
-    DisplayState *ds;
-    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
-
-    VncDisplay *vd;
-    int need_update;
-    int force_update;
-    uint32_t features;
-    int absolute;
-    int last_x;
-    int last_y;
-    int client_width;
-    int client_height;
-
-    uint32_t vnc_encoding;
-
-    int major;
-    int minor;
-
-    char challenge[VNC_AUTH_CHALLENGE_SIZE];
-#ifdef CONFIG_VNC_TLS
-    VncStateTLS tls;
-#endif
-#ifdef CONFIG_VNC_SASL
-    VncStateSASL sasl;
-#endif
-
-    QObject *info;
-
-    Buffer output;
-    Buffer input;
-    /* current output mode information */
-    VncWritePixels *write_pixels;
-    DisplaySurface clientds;
-
-    CaptureVoiceOut *audio_cap;
-    struct audsettings as;
-
-    VncReadEvent *read_handler;
-    size_t read_handler_expect;
-    /* input */
-    uint8_t modifiers_state[256];
-    QEMUPutLEDEntry *led;
-
-    /* Encoding specific */
-
-    /* Tight */
-    uint8_t tight_quality;
-    uint8_t tight_compression;
-    uint8_t tight_pixel24;
-    Buffer tight;
-    Buffer tight_tmp;
-    Buffer tight_zlib;
-    Buffer tight_gradient;
-#ifdef CONFIG_VNC_JPEG
-    Buffer tight_jpeg;
-#endif
-    int tight_levels[4];
-    z_stream tight_stream[4];
-
-    /* Hextile */
-    VncSendHextileTile *send_hextile_tile;
-
-    /* Zlib */
-    Buffer zlib;
-    Buffer zlib_tmp;
-    z_stream zlib_stream;
-    int zlib_level;
-
-    Notifier mouse_mode_notifier;
-
-    QTAILQ_ENTRY(VncState) next;
-};
-
-
-/*****************************************************************************
- *
- * Authentication modes
- *
- *****************************************************************************/
-
-enum {
-    VNC_AUTH_INVALID = 0,
-    VNC_AUTH_NONE = 1,
-    VNC_AUTH_VNC = 2,
-    VNC_AUTH_RA2 = 5,
-    VNC_AUTH_RA2NE = 6,
-    VNC_AUTH_TIGHT = 16,
-    VNC_AUTH_ULTRA = 17,
-    VNC_AUTH_TLS = 18,      /* Supported in GTK-VNC & VINO */
-    VNC_AUTH_VENCRYPT = 19, /* Supported in GTK-VNC & VeNCrypt */
-    VNC_AUTH_SASL = 20,     /* Supported in GTK-VNC & VINO */
-};
-
-enum {
-    VNC_AUTH_VENCRYPT_PLAIN = 256,
-    VNC_AUTH_VENCRYPT_TLSNONE = 257,
-    VNC_AUTH_VENCRYPT_TLSVNC = 258,
-    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
-    VNC_AUTH_VENCRYPT_X509NONE = 260,
-    VNC_AUTH_VENCRYPT_X509VNC = 261,
-    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
-    VNC_AUTH_VENCRYPT_X509SASL = 263,
-    VNC_AUTH_VENCRYPT_TLSSASL = 264,
-};
-
-
-/*****************************************************************************
- *
- * Encoding types
- *
- *****************************************************************************/
-
-#define VNC_ENCODING_RAW                  0x00000000
-#define VNC_ENCODING_COPYRECT             0x00000001
-#define VNC_ENCODING_RRE                  0x00000002
-#define VNC_ENCODING_CORRE                0x00000004
-#define VNC_ENCODING_HEXTILE              0x00000005
-#define VNC_ENCODING_ZLIB                 0x00000006
-#define VNC_ENCODING_TIGHT                0x00000007
-#define VNC_ENCODING_ZLIBHEX              0x00000008
-#define VNC_ENCODING_TRLE                 0x0000000f
-#define VNC_ENCODING_ZRLE                 0x00000010
-#define VNC_ENCODING_ZYWRLE               0x00000011
-#define VNC_ENCODING_COMPRESSLEVEL0       0xFFFFFF00 /* -256 */
-#define VNC_ENCODING_QUALITYLEVEL0        0xFFFFFFE0 /* -32  */
-#define VNC_ENCODING_XCURSOR              0xFFFFFF10 /* -240 */
-#define VNC_ENCODING_RICH_CURSOR          0xFFFFFF11 /* -239 */
-#define VNC_ENCODING_POINTER_POS          0xFFFFFF18 /* -232 */
-#define VNC_ENCODING_LASTRECT             0xFFFFFF20 /* -224 */
-#define VNC_ENCODING_DESKTOPRESIZE        0xFFFFFF21 /* -223 */
-#define VNC_ENCODING_POINTER_TYPE_CHANGE  0XFFFFFEFF /* -257 */
-#define VNC_ENCODING_EXT_KEY_EVENT        0XFFFFFEFE /* -258 */
-#define VNC_ENCODING_AUDIO                0XFFFFFEFD /* -259 */
-#define VNC_ENCODING_WMVi                 0x574D5669
-
-/*****************************************************************************
- *
- * Other tight constants
- *
- *****************************************************************************/
-
-/*
- * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
- */
-
-#define VNC_TIGHT_CCB_RESET_MASK   (0x0f)
-#define VNC_TIGHT_CCB_TYPE_MASK    (0x0f << 4)
-#define VNC_TIGHT_CCB_TYPE_FILL    (0x08 << 4)
-#define VNC_TIGHT_CCB_TYPE_JPEG    (0x09 << 4)
-#define VNC_TIGHT_CCB_BASIC_MAX    (0x07 << 4)
-#define VNC_TIGHT_CCB_BASIC_ZLIB   (0x03 << 4)
-#define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
-
-/*****************************************************************************
- *
- * Features
- *
- *****************************************************************************/
-
-#define VNC_FEATURE_RESIZE                   0
-#define VNC_FEATURE_HEXTILE                  1
-#define VNC_FEATURE_POINTER_TYPE_CHANGE      2
-#define VNC_FEATURE_WMVI                     3
-#define VNC_FEATURE_TIGHT                    4
-#define VNC_FEATURE_ZLIB                     5
-#define VNC_FEATURE_COPYRECT                 6
-#define VNC_FEATURE_RICH_CURSOR              7
-
-#define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
-#define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
-#define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
-#define VNC_FEATURE_WMVI_MASK                (1 << VNC_FEATURE_WMVI)
-#define VNC_FEATURE_TIGHT_MASK               (1 << VNC_FEATURE_TIGHT)
-#define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
-#define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
-#define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
-
-
-/* Client -> Server message IDs */
-#define VNC_MSG_CLIENT_SET_PIXEL_FORMAT           0
-#define VNC_MSG_CLIENT_SET_ENCODINGS              2
-#define VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST 3
-#define VNC_MSG_CLIENT_KEY_EVENT                  4
-#define VNC_MSG_CLIENT_POINTER_EVENT              5
-#define VNC_MSG_CLIENT_CUT_TEXT                   6
-#define VNC_MSG_CLIENT_VMWARE_0                   127
-#define VNC_MSG_CLIENT_CALL_CONTROL               249
-#define VNC_MSG_CLIENT_XVP                        250
-#define VNC_MSG_CLIENT_SET_DESKTOP_SIZE           251
-#define VNC_MSG_CLIENT_TIGHT                      252
-#define VNC_MSG_CLIENT_GII                        253
-#define VNC_MSG_CLIENT_VMWARE_1                   254
-#define VNC_MSG_CLIENT_QEMU                       255
-
-/* Server -> Client message IDs */
-#define VNC_MSG_SERVER_FRAMEBUFFER_UPDATE         0
-#define VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES     1
-#define VNC_MSG_SERVER_BELL                       2
-#define VNC_MSG_SERVER_CUT_TEXT                   3
-#define VNC_MSG_SERVER_VMWARE_0                   127
-#define VNC_MSG_SERVER_CALL_CONTROL               249
-#define VNC_MSG_SERVER_XVP                        250
-#define VNC_MSG_SERVER_TIGHT                      252
-#define VNC_MSG_SERVER_GII                        253
-#define VNC_MSG_SERVER_VMWARE_1                   254
-#define VNC_MSG_SERVER_QEMU                       255
-
-
-
-/* QEMU client -> server message IDs */
-#define VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT         0
-#define VNC_MSG_CLIENT_QEMU_AUDIO                 1
-
-/* QEMU server -> client message IDs */
-#define VNC_MSG_SERVER_QEMU_AUDIO                 1
-
-
-
-/* QEMU client -> server audio message IDs */
-#define VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE          0
-#define VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE         1
-#define VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT      2
-
-/* QEMU server -> client audio message IDs */
-#define VNC_MSG_SERVER_QEMU_AUDIO_END             0
-#define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN           1
-#define VNC_MSG_SERVER_QEMU_AUDIO_DATA            2
-
-
-/*****************************************************************************
- *
- * Internal APIs
- *
- *****************************************************************************/
-
-/* Event loop functions */
-void vnc_client_read(void *opaque);
-void vnc_client_write(void *opaque);
-
-long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
-long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
-
-/* Protocol I/O functions */
-void vnc_write(VncState *vs, const void *data, size_t len);
-void vnc_write_u32(VncState *vs, uint32_t value);
-void vnc_write_s32(VncState *vs, int32_t value);
-void vnc_write_u16(VncState *vs, uint16_t value);
-void vnc_write_u8(VncState *vs, uint8_t value);
-void vnc_flush(VncState *vs);
-void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
-
-
-/* Buffer I/O functions */
-uint8_t read_u8(uint8_t *data, size_t offset);
-uint16_t read_u16(uint8_t *data, size_t offset);
-int32_t read_s32(uint8_t *data, size_t offset);
-uint32_t read_u32(uint8_t *data, size_t offset);
-
-/* Protocol stage functions */
-void vnc_client_error(VncState *vs);
-int vnc_client_io_error(VncState *vs, int ret, int last_errno);
-
-void start_client_init(VncState *vs);
-void start_auth_vnc(VncState *vs);
-
-/* Buffer management */
-void buffer_reserve(Buffer *buffer, size_t len);
-int buffer_empty(Buffer *buffer);
-uint8_t *buffer_end(Buffer *buffer);
-void buffer_reset(Buffer *buffer);
-void buffer_free(Buffer *buffer);
-void buffer_append(Buffer *buffer, const void *data, size_t len);
-
-
-/* Misc helpers */
-
-char *vnc_socket_local_addr(const char *format, int fd);
-char *vnc_socket_remote_addr(const char *format, int fd);
-
-/* Framebuffer */
-void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
-                            int32_t encoding);
-
-void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
-
-/* Encodings */
-int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-
-int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
-                                         int y, int w, int h);
-void vnc_hextile_set_pixel_conversion(VncState *vs, int generic);
-
-void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size);
-void vnc_zlib_zfree(void *x, void *addr);
-int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-void vnc_zlib_clear(VncState *vs);
-
-
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-void vnc_tight_clear(VncState *vs);
-
-#endif /* __QEMU_VNC_H */
diff --git a/vnc_keysym.h b/vnc_keysym.h
deleted file mode 100644 (file)
index 55cb87e..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-
-#include "keymaps.h"
-
-static const name2keysym_t name2keysym[]={
-/* ascii */
-    { "space",                0x020},
-    { "exclam",               0x021},
-    { "quotedbl",             0x022},
-    { "numbersign",           0x023},
-    { "dollar",               0x024},
-    { "percent",              0x025},
-    { "ampersand",            0x026},
-    { "apostrophe",           0x027},
-    { "parenleft",            0x028},
-    { "parenright",           0x029},
-    { "asterisk",             0x02a},
-    { "plus",                 0x02b},
-    { "comma",                0x02c},
-    { "minus",                0x02d},
-    { "period",               0x02e},
-    { "slash",                0x02f},
-    { "0",                    0x030},
-    { "1",                    0x031},
-    { "2",                    0x032},
-    { "3",                    0x033},
-    { "4",                    0x034},
-    { "5",                    0x035},
-    { "6",                    0x036},
-    { "7",                    0x037},
-    { "8",                    0x038},
-    { "9",                    0x039},
-    { "colon",                0x03a},
-    { "semicolon",            0x03b},
-    { "less",                 0x03c},
-    { "equal",                0x03d},
-    { "greater",              0x03e},
-    { "question",             0x03f},
-    { "at",                   0x040},
-    { "A",                    0x041},
-    { "B",                    0x042},
-    { "C",                    0x043},
-    { "D",                    0x044},
-    { "E",                    0x045},
-    { "F",                    0x046},
-    { "G",                    0x047},
-    { "H",                    0x048},
-    { "I",                    0x049},
-    { "J",                    0x04a},
-    { "K",                    0x04b},
-    { "L",                    0x04c},
-    { "M",                    0x04d},
-    { "N",                    0x04e},
-    { "O",                    0x04f},
-    { "P",                    0x050},
-    { "Q",                    0x051},
-    { "R",                    0x052},
-    { "S",                    0x053},
-    { "T",                    0x054},
-    { "U",                    0x055},
-    { "V",                    0x056},
-    { "W",                    0x057},
-    { "X",                    0x058},
-    { "Y",                    0x059},
-    { "Z",                    0x05a},
-    { "bracketleft",          0x05b},
-    { "backslash",            0x05c},
-    { "bracketright",         0x05d},
-    { "asciicircum",          0x05e},
-    { "underscore",           0x05f},
-    { "grave",                0x060},
-    { "a",                    0x061},
-    { "b",                    0x062},
-    { "c",                    0x063},
-    { "d",                    0x064},
-    { "e",                    0x065},
-    { "f",                    0x066},
-    { "g",                    0x067},
-    { "h",                    0x068},
-    { "i",                    0x069},
-    { "j",                    0x06a},
-    { "k",                    0x06b},
-    { "l",                    0x06c},
-    { "m",                    0x06d},
-    { "n",                    0x06e},
-    { "o",                    0x06f},
-    { "p",                    0x070},
-    { "q",                    0x071},
-    { "r",                    0x072},
-    { "s",                    0x073},
-    { "t",                    0x074},
-    { "u",                    0x075},
-    { "v",                    0x076},
-    { "w",                    0x077},
-    { "x",                    0x078},
-    { "y",                    0x079},
-    { "z",                    0x07a},
-    { "braceleft",            0x07b},
-    { "bar",                  0x07c},
-    { "braceright",           0x07d},
-    { "asciitilde",           0x07e},
-
-/* latin 1 extensions */
-{ "nobreakspace",         0x0a0},
-{ "exclamdown",           0x0a1},
-{ "cent",                0x0a2},
-{ "sterling",             0x0a3},
-{ "currency",             0x0a4},
-{ "yen",                  0x0a5},
-{ "brokenbar",            0x0a6},
-{ "section",              0x0a7},
-{ "diaeresis",            0x0a8},
-{ "copyright",            0x0a9},
-{ "ordfeminine",          0x0aa},
-{ "guillemotleft",        0x0ab},
-{ "notsign",              0x0ac},
-{ "hyphen",               0x0ad},
-{ "registered",           0x0ae},
-{ "macron",               0x0af},
-{ "degree",               0x0b0},
-{ "plusminus",            0x0b1},
-{ "twosuperior",          0x0b2},
-{ "threesuperior",        0x0b3},
-{ "acute",                0x0b4},
-{ "mu",                   0x0b5},
-{ "paragraph",            0x0b6},
-{ "periodcentered",       0x0b7},
-{ "cedilla",              0x0b8},
-{ "onesuperior",          0x0b9},
-{ "masculine",            0x0ba},
-{ "guillemotright",       0x0bb},
-{ "onequarter",           0x0bc},
-{ "onehalf",              0x0bd},
-{ "threequarters",        0x0be},
-{ "questiondown",         0x0bf},
-{ "Agrave",               0x0c0},
-{ "Aacute",               0x0c1},
-{ "Acircumflex",          0x0c2},
-{ "Atilde",               0x0c3},
-{ "Adiaeresis",           0x0c4},
-{ "Aring",                0x0c5},
-{ "AE",                   0x0c6},
-{ "Ccedilla",             0x0c7},
-{ "Egrave",               0x0c8},
-{ "Eacute",               0x0c9},
-{ "Ecircumflex",          0x0ca},
-{ "Ediaeresis",           0x0cb},
-{ "Igrave",               0x0cc},
-{ "Iacute",               0x0cd},
-{ "Icircumflex",          0x0ce},
-{ "Idiaeresis",           0x0cf},
-{ "ETH",                  0x0d0},
-{ "Eth",                  0x0d0},
-{ "Ntilde",               0x0d1},
-{ "Ograve",               0x0d2},
-{ "Oacute",               0x0d3},
-{ "Ocircumflex",          0x0d4},
-{ "Otilde",               0x0d5},
-{ "Odiaeresis",           0x0d6},
-{ "multiply",             0x0d7},
-{ "Ooblique",             0x0d8},
-{ "Oslash",               0x0d8},
-{ "Ugrave",               0x0d9},
-{ "Uacute",               0x0da},
-{ "Ucircumflex",          0x0db},
-{ "Udiaeresis",           0x0dc},
-{ "Yacute",               0x0dd},
-{ "THORN",                0x0de},
-{ "Thorn",                0x0de},
-{ "ssharp",               0x0df},
-{ "agrave",               0x0e0},
-{ "aacute",               0x0e1},
-{ "acircumflex",          0x0e2},
-{ "atilde",               0x0e3},
-{ "adiaeresis",           0x0e4},
-{ "aring",                0x0e5},
-{ "ae",                   0x0e6},
-{ "ccedilla",             0x0e7},
-{ "egrave",               0x0e8},
-{ "eacute",               0x0e9},
-{ "ecircumflex",          0x0ea},
-{ "ediaeresis",           0x0eb},
-{ "igrave",               0x0ec},
-{ "iacute",               0x0ed},
-{ "icircumflex",          0x0ee},
-{ "idiaeresis",           0x0ef},
-{ "eth",                  0x0f0},
-{ "ntilde",               0x0f1},
-{ "ograve",               0x0f2},
-{ "oacute",               0x0f3},
-{ "ocircumflex",          0x0f4},
-{ "otilde",               0x0f5},
-{ "odiaeresis",           0x0f6},
-{ "division",             0x0f7},
-{ "oslash",               0x0f8},
-{ "ooblique",             0x0f8},
-{ "ugrave",               0x0f9},
-{ "uacute",               0x0fa},
-{ "ucircumflex",          0x0fb},
-{ "udiaeresis",           0x0fc},
-{ "yacute",               0x0fd},
-{ "thorn",                0x0fe},
-{ "ydiaeresis",           0x0ff},
-{"EuroSign", 0x20ac},  /* XK_EuroSign */
-
-    /* modifiers */
-{"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */
-{"Control_L", 0xffe3}, /* XK_Control_L */
-{"Control_R", 0xffe4}, /* XK_Control_R */
-{"Alt_L", 0xffe9},     /* XK_Alt_L */
-{"Alt_R", 0xffea},     /* XK_Alt_R */
-{"Caps_Lock", 0xffe5}, /* XK_Caps_Lock */
-{"Meta_L", 0xffe7},    /* XK_Meta_L */
-{"Meta_R", 0xffe8},    /* XK_Meta_R */
-{"Shift_L", 0xffe1},   /* XK_Shift_L */
-{"Shift_R", 0xffe2},   /* XK_Shift_R */
-{"Super_L", 0xffeb},   /* XK_Super_L */
-{"Super_R", 0xffec},   /* XK_Super_R */
-
-    /* special keys */
-{"BackSpace", 0xff08}, /* XK_BackSpace */
-{"Tab", 0xff09},       /* XK_Tab */
-{"Return", 0xff0d},    /* XK_Return */
-{"Right", 0xff53},     /* XK_Right */
-{"Left", 0xff51},      /* XK_Left */
-{"Up", 0xff52},        /* XK_Up */
-{"Down", 0xff54},      /* XK_Down */
-{"Page_Down", 0xff56}, /* XK_Page_Down */
-{"Page_Up", 0xff55},   /* XK_Page_Up */
-{"Insert", 0xff63},    /* XK_Insert */
-{"Delete", 0xffff},    /* XK_Delete */
-{"Home", 0xff50},      /* XK_Home */
-{"End", 0xff57},       /* XK_End */
-{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
-{"KP_Home", 0xff95},
-{"KP_Left", 0xff96},
-{"KP_Up", 0xff97},
-{"KP_Right", 0xff98},
-{"KP_Down", 0xff99},
-{"KP_Prior", 0xff9a},
-{"KP_Page_Up", 0xff9a},
-{"KP_Next", 0xff9b},
-{"KP_Page_Down", 0xff9b},
-{"KP_End", 0xff9c},
-{"KP_Begin", 0xff9d},
-{"KP_Insert", 0xff9e},
-{"KP_Delete", 0xff9f},
-{"F1", 0xffbe},        /* XK_F1 */
-{"F2", 0xffbf},        /* XK_F2 */
-{"F3", 0xffc0},        /* XK_F3 */
-{"F4", 0xffc1},        /* XK_F4 */
-{"F5", 0xffc2},        /* XK_F5 */
-{"F6", 0xffc3},        /* XK_F6 */
-{"F7", 0xffc4},        /* XK_F7 */
-{"F8", 0xffc5},        /* XK_F8 */
-{"F9", 0xffc6},        /* XK_F9 */
-{"F10", 0xffc7},       /* XK_F10 */
-{"F11", 0xffc8},       /* XK_F11 */
-{"F12", 0xffc9},       /* XK_F12 */
-{"F13", 0xffca},       /* XK_F13 */
-{"F14", 0xffcb},       /* XK_F14 */
-{"F15", 0xffcc},       /* XK_F15 */
-{"Sys_Req", 0xff15},   /* XK_Sys_Req */
-{"KP_0", 0xffb0},      /* XK_KP_0 */
-{"KP_1", 0xffb1},      /* XK_KP_1 */
-{"KP_2", 0xffb2},      /* XK_KP_2 */
-{"KP_3", 0xffb3},      /* XK_KP_3 */
-{"KP_4", 0xffb4},      /* XK_KP_4 */
-{"KP_5", 0xffb5},      /* XK_KP_5 */
-{"KP_6", 0xffb6},      /* XK_KP_6 */
-{"KP_7", 0xffb7},      /* XK_KP_7 */
-{"KP_8", 0xffb8},      /* XK_KP_8 */
-{"KP_9", 0xffb9},      /* XK_KP_9 */
-{"KP_Add", 0xffab},    /* XK_KP_Add */
-{"KP_Separator", 0xffac},/* XK_KP_Separator */
-{"KP_Decimal", 0xffae},  /* XK_KP_Decimal */
-{"KP_Divide", 0xffaf},   /* XK_KP_Divide */
-{"KP_Enter", 0xff8d},    /* XK_KP_Enter */
-{"KP_Equal", 0xffbd},    /* XK_KP_Equal */
-{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */
-{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */
-{"help", 0xff6a},        /* XK_Help */
-{"Menu", 0xff67},        /* XK_Menu */
-{"Print", 0xff61},       /* XK_Print */
-{"Mode_switch", 0xff7e}, /* XK_Mode_switch */
-{"Num_Lock", 0xff7f},    /* XK_Num_Lock */
-{"Pause", 0xff13},       /* XK_Pause */
-{"Escape", 0xff1b},      /* XK_Escape */
-
-/* dead keys */
-{"dead_grave", 0xfe50}, /* XK_dead_grave */
-{"dead_acute", 0xfe51}, /* XK_dead_acute */
-{"dead_circumflex", 0xfe52}, /* XK_dead_circumflex */
-{"dead_tilde", 0xfe53}, /* XK_dead_tilde */
-{"dead_macron", 0xfe54}, /* XK_dead_macron */
-{"dead_breve", 0xfe55}, /* XK_dead_breve */
-{"dead_abovedot", 0xfe56}, /* XK_dead_abovedot */
-{"dead_diaeresis", 0xfe57}, /* XK_dead_diaeresis */
-{"dead_abovering", 0xfe58}, /* XK_dead_abovering */
-{"dead_doubleacute", 0xfe59}, /* XK_dead_doubleacute */
-{"dead_caron", 0xfe5a}, /* XK_dead_caron */
-{"dead_cedilla", 0xfe5b}, /* XK_dead_cedilla */
-{"dead_ogonek", 0xfe5c}, /* XK_dead_ogonek */
-{"dead_iota", 0xfe5d}, /* XK_dead_iota */
-{"dead_voiced_sound", 0xfe5e}, /* XK_dead_voiced_sound */
-{"dead_semivoiced_sound", 0xfe5f}, /* XK_dead_semivoiced_sound */
-{"dead_belowdot", 0xfe60}, /* XK_dead_belowdot */
-{"dead_hook", 0xfe61}, /* XK_dead_hook */
-{"dead_horn", 0xfe62}, /* XK_dead_horn */
-
-
-    /* localized keys */
-{"BackApostrophe", 0xff21},
-{"Muhenkan", 0xff22},
-{"Katakana", 0xff27},
-{"Hankaku", 0xff29},
-{"Zenkaku_Hankaku", 0xff2a},
-{"Henkan_Mode_Real", 0xff23},
-{"Henkan_Mode_Ultra", 0xff3e},
-{"backslash_ja", 0xffa5},
-{"Katakana_Real", 0xff25},
-{"Eisu_toggle", 0xff30},
-
-{NULL,0},
-};
diff --git a/vnchextile.h b/vnchextile.h
deleted file mode 100644 (file)
index b9f9f5e..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-#define CONCAT_I(a, b) a ## b
-#define CONCAT(a, b) CONCAT_I(a, b)
-#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
-#ifdef GENERIC
-#define NAME CONCAT(generic_, BPP)
-#else
-#define NAME BPP
-#endif
-
-static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
-                                             int x, int y, int w, int h,
-                                             void *last_bg_,
-                                             void *last_fg_,
-                                             int *has_bg, int *has_fg)
-{
-    VncDisplay *vd = vs->vd;
-    uint8_t *row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
-    pixel_t *irow = (pixel_t *)row;
-    int j, i;
-    pixel_t *last_bg = (pixel_t *)last_bg_;
-    pixel_t *last_fg = (pixel_t *)last_fg_;
-    pixel_t bg = 0;
-    pixel_t fg = 0;
-    int n_colors = 0;
-    int bg_count = 0;
-    int fg_count = 0;
-    int flags = 0;
-    uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
-    int n_data = 0;
-    int n_subtiles = 0;
-
-    for (j = 0; j < h; j++) {
-       for (i = 0; i < w; i++) {
-           switch (n_colors) {
-           case 0:
-               bg = irow[i];
-               n_colors = 1;
-               break;
-           case 1:
-               if (irow[i] != bg) {
-                   fg = irow[i];
-                   n_colors = 2;
-               }
-               break;
-           case 2:
-               if (irow[i] != bg && irow[i] != fg) {
-                   n_colors = 3;
-               } else {
-                   if (irow[i] == bg)
-                       bg_count++;
-                   else if (irow[i] == fg)
-                       fg_count++;
-               }
-               break;
-           default:
-               break;
-           }
-       }
-       if (n_colors > 2)
-           break;
-       irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
-    }
-
-    if (n_colors > 1 && fg_count > bg_count) {
-       pixel_t tmp = fg;
-       fg = bg;
-       bg = tmp;
-    }
-
-    if (!*has_bg || *last_bg != bg) {
-       flags |= 0x02;
-       *has_bg = 1;
-       *last_bg = bg;
-    }
-
-    if (n_colors < 3 && (!*has_fg || *last_fg != fg)) {
-       flags |= 0x04;
-       *has_fg = 1;
-       *last_fg = fg;
-    }
-
-    switch (n_colors) {
-    case 1:
-       n_data = 0;
-       break;
-    case 2:
-       flags |= 0x08;
-
-       irow = (pixel_t *)row;
-
-       for (j = 0; j < h; j++) {
-           int min_x = -1;
-           for (i = 0; i < w; i++) {
-               if (irow[i] == fg) {
-                   if (min_x == -1)
-                       min_x = i;
-               } else if (min_x != -1) {
-                   hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
-                   n_data += 2;
-                   n_subtiles++;
-                   min_x = -1;
-               }
-           }
-           if (min_x != -1) {
-               hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
-               n_data += 2;
-               n_subtiles++;
-           }
-           irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
-       }
-       break;
-    case 3:
-       flags |= 0x18;
-
-       irow = (pixel_t *)row;
-
-       if (!*has_bg || *last_bg != bg)
-           flags |= 0x02;
-
-       for (j = 0; j < h; j++) {
-           int has_color = 0;
-           int min_x = -1;
-           pixel_t color = 0; /* shut up gcc */
-
-           for (i = 0; i < w; i++) {
-               if (!has_color) {
-                   if (irow[i] == bg)
-                       continue;
-                   color = irow[i];
-                   min_x = i;
-                   has_color = 1;
-               } else if (irow[i] != color) {
-                   has_color = 0;
-#ifdef GENERIC
-                    vnc_convert_pixel(vs, data + n_data, color);
-                    n_data += vs->clientds.pf.bytes_per_pixel;
-#else
-                   memcpy(data + n_data, &color, sizeof(color));
-                    n_data += sizeof(pixel_t);
-#endif
-                   hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
-                   n_data += 2;
-                   n_subtiles++;
-
-                   min_x = -1;
-                   if (irow[i] != bg) {
-                       color = irow[i];
-                       min_x = i;
-                       has_color = 1;
-                   }
-               }
-           }
-           if (has_color) {
-#ifdef GENERIC
-                vnc_convert_pixel(vs, data + n_data, color);
-                n_data += vs->clientds.pf.bytes_per_pixel;
-#else
-                memcpy(data + n_data, &color, sizeof(color));
-                n_data += sizeof(pixel_t);
-#endif
-               hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
-               n_data += 2;
-               n_subtiles++;
-           }
-           irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
-       }
-
-       /* A SubrectsColoured subtile invalidates the foreground color */
-       *has_fg = 0;
-       if (n_data > (w * h * sizeof(pixel_t))) {
-           n_colors = 4;
-           flags = 0x01;
-           *has_bg = 0;
-
-           /* we really don't have to invalidate either the bg or fg
-              but we've lost the old values.  oh well. */
-       }
-    default:
-       break;
-    }
-
-    if (n_colors > 3) {
-       flags = 0x01;
-       *has_fg = 0;
-       *has_bg = 0;
-       n_colors = 4;
-    }
-
-    vnc_write_u8(vs, flags);
-    if (n_colors < 4) {
-       if (flags & 0x02)
-           vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
-       if (flags & 0x04)
-           vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
-       if (n_subtiles) {
-           vnc_write_u8(vs, n_subtiles);
-           vnc_write(vs, data, n_data);
-       }
-    } else {
-       for (j = 0; j < h; j++) {
-           vs->write_pixels(vs, &vd->server->pf, row,
-                             w * ds_get_bytes_per_pixel(vs->ds));
-           row += ds_get_linesize(vs->ds);
-       }
-    }
-}
-
-#undef NAME
-#undef pixel_t
-#undef CONCAT_I
-#undef CONCAT
diff --git a/x_keymap.c b/x_keymap.c
deleted file mode 100644 (file)
index b9b0944..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * QEMU SDL display driver
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "x_keymap.h"
-
-static const uint8_t x_keycode_to_pc_keycode[115] = {
-   0xc7,      /*  97  Home   */
-   0xc8,      /*  98  Up     */
-   0xc9,      /*  99  PgUp   */
-   0xcb,      /* 100  Left   */
-   0x4c,        /* 101  KP-5   */
-   0xcd,      /* 102  Right  */
-   0xcf,      /* 103  End    */
-   0xd0,      /* 104  Down   */
-   0xd1,      /* 105  PgDn   */
-   0xd2,      /* 106  Ins    */
-   0xd3,      /* 107  Del    */
-   0x9c,      /* 108  Enter  */
-   0x9d,      /* 109  Ctrl-R */
-   0x0,       /* 110  Pause  */
-   0xb7,      /* 111  Print  */
-   0xb5,      /* 112  Divide */
-   0xb8,      /* 113  Alt-R  */
-   0xc6,      /* 114  Break  */
-   0x0,         /* 115 */
-   0x0,         /* 116 */
-   0x0,         /* 117 */
-   0x0,         /* 118 */
-   0x0,         /* 119 */
-   0x0,         /* 120 */
-   0x0,         /* 121 */
-   0x0,         /* 122 */
-   0x0,         /* 123 */
-   0x0,         /* 124 */
-   0x0,         /* 125 */
-   0x0,         /* 126 */
-   0x0,         /* 127 */
-   0x0,         /* 128 */
-   0x79,         /* 129 Henkan */
-   0x0,         /* 130 */
-   0x7b,         /* 131 Muhenkan */
-   0x0,         /* 132 */
-   0x7d,         /* 133 Yen */
-   0x0,         /* 134 */
-   0x0,         /* 135 */
-   0x47,         /* 136 KP_7 */
-   0x48,         /* 137 KP_8 */
-   0x49,         /* 138 KP_9 */
-   0x4b,         /* 139 KP_4 */
-   0x4c,         /* 140 KP_5 */
-   0x4d,         /* 141 KP_6 */
-   0x4f,         /* 142 KP_1 */
-   0x50,         /* 143 KP_2 */
-   0x51,         /* 144 KP_3 */
-   0x52,         /* 145 KP_0 */
-   0x53,         /* 146 KP_. */
-   0x47,         /* 147 KP_HOME */
-   0x48,         /* 148 KP_UP */
-   0x49,         /* 149 KP_PgUp */
-   0x4b,         /* 150 KP_Left */
-   0x4c,         /* 151 KP_ */
-   0x4d,         /* 152 KP_Right */
-   0x4f,         /* 153 KP_End */
-   0x50,         /* 154 KP_Down */
-   0x51,         /* 155 KP_PgDn */
-   0x52,         /* 156 KP_Ins */
-   0x53,         /* 157 KP_Del */
-};
-
-/* This table is generated based off the xfree86 -> scancode mapping above
- * and the keycode mappings in /usr/share/X11/xkb/keycodes/evdev
- * and  /usr/share/X11/xkb/keycodes/xfree86
- */
-
-static const uint8_t evdev_keycode_to_pc_keycode[61] = {
-    0,         /*  97 EVDEV - RO   ("Internet" Keyboards) */
-    0,         /*  98 EVDEV - KATA (Katakana) */
-    0,         /*  99 EVDEV - HIRA (Hiragana) */
-    0x79,      /* 100 EVDEV - HENK (Henkan) */
-    0x70,      /* 101 EVDEV - HKTG (Hiragana/Katakana toggle) */
-    0x7b,      /* 102 EVDEV - MUHE (Muhenkan) */
-    0,         /* 103 EVDEV - JPCM (KPJPComma) */
-    0x9c,      /* 104 KPEN */
-    0x9d,      /* 105 RCTL */
-    0xb5,      /* 106 KPDV */
-    0xb7,      /* 107 PRSC */
-    0xb8,      /* 108 RALT */
-    0,         /* 109 EVDEV - LNFD ("Internet" Keyboards) */
-    0xc7,      /* 110 HOME */
-    0xc8,      /* 111 UP */
-    0xc9,      /* 112 PGUP */
-    0xcb,      /* 113 LEFT */
-    0xcd,      /* 114 RGHT */
-    0xcf,      /* 115 END */
-    0xd0,      /* 116 DOWN */
-    0xd1,      /* 117 PGDN */
-    0xd2,      /* 118 INS */
-    0xd3,      /* 119 DELE */
-    0,         /* 120 EVDEV - I120 ("Internet" Keyboards) */
-    0,         /* 121 EVDEV - MUTE */
-    0,         /* 122 EVDEV - VOL- */
-    0,         /* 123 EVDEV - VOL+ */
-    0,         /* 124 EVDEV - POWR */
-    0,         /* 125 EVDEV - KPEQ */
-    0,         /* 126 EVDEV - I126 ("Internet" Keyboards) */
-    0,         /* 127 EVDEV - PAUS */
-    0,         /* 128 EVDEV - ???? */
-    0,         /* 129 EVDEV - I129 ("Internet" Keyboards) */
-    0xf1,      /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
-    0xf2,      /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
-    0x7d,      /* 132 AE13 (Yen)*/
-    0xdb,      /* 133 EVDEV - LWIN */
-    0xdc,      /* 134 EVDEV - RWIN */
-    0xdd,      /* 135 EVDEV - MENU */
-    0,         /* 136 EVDEV - STOP */
-    0,         /* 137 EVDEV - AGAI */
-    0,         /* 138 EVDEV - PROP */
-    0,         /* 139 EVDEV - UNDO */
-    0,         /* 140 EVDEV - FRNT */
-    0,         /* 141 EVDEV - COPY */
-    0,         /* 142 EVDEV - OPEN */
-    0,         /* 143 EVDEV - PAST */
-    0,         /* 144 EVDEV - FIND */
-    0,         /* 145 EVDEV - CUT  */
-    0,         /* 146 EVDEV - HELP */
-    0,         /* 147 EVDEV - I147 */
-    0,         /* 148 EVDEV - I148 */
-    0,         /* 149 EVDEV - I149 */
-    0,         /* 150 EVDEV - I150 */
-    0,         /* 151 EVDEV - I151 */
-    0,         /* 152 EVDEV - I152 */
-    0,         /* 153 EVDEV - I153 */
-    0,         /* 154 EVDEV - I154 */
-    0,         /* 155 EVDEV - I156 */
-    0,         /* 156 EVDEV - I157 */
-    0,         /* 157 EVDEV - I158 */
-};
-
-uint8_t translate_xfree86_keycode(const int key)
-{
-    return x_keycode_to_pc_keycode[key];
-}
-
-uint8_t translate_evdev_keycode(const int key)
-{
-    return evdev_keycode_to_pc_keycode[key];
-}
diff --git a/x_keymap.h b/x_keymap.h
deleted file mode 100644 (file)
index 2042ce0..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * QEMU SDL display driver
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef QEMU_X_KEYMAP_H
-#define QEMU_X_KEYMAP_H
-
-extern uint8_t translate_xfree86_keycode(const int key);
-
-extern uint8_t translate_evdev_keycode(const int key);
-
-#endif