diff options
Diffstat (limited to 'qemu/ui')
64 files changed, 0 insertions, 31335 deletions
diff --git a/qemu/ui/Makefile.objs b/qemu/ui/Makefile.objs deleted file mode 100644 index dc936f150..000000000 --- a/qemu/ui/Makefile.objs +++ /dev/null @@ -1,53 +0,0 @@ -vnc-obj-y += vnc.o -vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o -vnc-obj-y += vnc-enc-tight.o vnc-palette.o -vnc-obj-y += vnc-enc-zrle.o -vnc-obj-y += vnc-auth-vencrypt.o -vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o -vnc-obj-y += vnc-ws.o -vnc-obj-y += vnc-jobs.o - -common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o -common-obj-y += input.o input-keymap.o input-legacy.o -common-obj-$(CONFIG_LINUX) += input-linux.o -common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o -common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o -common-obj-$(CONFIG_COCOA) += cocoa.o -common-obj-$(CONFIG_CURSES) += curses.o -common-obj-$(CONFIG_VNC) += $(vnc-obj-y) -common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o - -ifeq ($(CONFIG_SDLABI),1.2) -sdl.mo-objs := sdl.o sdl_zoom.o -endif -ifeq ($(CONFIG_SDLABI),2.0) -sdl.mo-objs := sdl2.o sdl2-input.o sdl2-2d.o -ifeq ($(CONFIG_OPENGL),y) -sdl.mo-objs += sdl2-gl.o -endif -endif -sdl.mo-cflags := $(SDL_CFLAGS) - -ifeq ($(CONFIG_OPENGL),y) -common-obj-y += shader.o -common-obj-y += console-gl.o -common-obj-y += egl-helpers.o -common-obj-y += egl-context.o -ifeq ($(CONFIG_GTK_GL),y) -common-obj-$(CONFIG_GTK) += gtk-gl-area.o -else -common-obj-$(CONFIG_GTK) += gtk-egl.o -endif -endif - -gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) -gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS) -gtk-gl-area.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS) -shader.o-cflags += $(OPENGL_CFLAGS) -console-gl.o-cflags += $(OPENGL_CFLAGS) -egl-helpers.o-cflags += $(OPENGL_CFLAGS) - -gtk-egl.o-libs += $(OPENGL_LIBS) -shader.o-libs += $(OPENGL_LIBS) -console-gl.o-libs += $(OPENGL_LIBS) -egl-helpers.o-libs += $(OPENGL_LIBS) diff --git a/qemu/ui/cocoa.m b/qemu/ui/cocoa.m deleted file mode 100644 index 60a7c07ec..000000000 --- a/qemu/ui/cocoa.m +++ /dev/null @@ -1,1450 +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. - */ - -#include "qemu/osdep.h" - -#import <Cocoa/Cocoa.h> -#include <crt_externs.h> - -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" -#include "qmp-commands.h" -#include "sysemu/blockdev.h" -#include <Carbon/Carbon.h> - -#ifndef MAC_OS_X_VERSION_10_5 -#define MAC_OS_X_VERSION_10_5 1050 -#endif -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif -#ifndef MAC_OS_X_VERSION_10_10 -#define MAC_OS_X_VERSION_10_10 101000 -#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)) - -typedef struct { - int width; - int height; - int bitsPerComponent; - int bitsPerPixel; -} QEMUScreen; - -NSWindow *normalWindow; -static DisplayChangeListener *dcl; -static int last_buttons; - -int gArgc; -char **gArgv; -bool stretch_video; -NSTextField *pauseLabel; -NSArray * supportedImageFileTypes; - -// Mac to QKeyCode conversion -const int mac_to_qkeycode_map[] = { - [kVK_ANSI_A] = Q_KEY_CODE_A, - [kVK_ANSI_B] = Q_KEY_CODE_B, - [kVK_ANSI_C] = Q_KEY_CODE_C, - [kVK_ANSI_D] = Q_KEY_CODE_D, - [kVK_ANSI_E] = Q_KEY_CODE_E, - [kVK_ANSI_F] = Q_KEY_CODE_F, - [kVK_ANSI_G] = Q_KEY_CODE_G, - [kVK_ANSI_H] = Q_KEY_CODE_H, - [kVK_ANSI_I] = Q_KEY_CODE_I, - [kVK_ANSI_J] = Q_KEY_CODE_J, - [kVK_ANSI_K] = Q_KEY_CODE_K, - [kVK_ANSI_L] = Q_KEY_CODE_L, - [kVK_ANSI_M] = Q_KEY_CODE_M, - [kVK_ANSI_N] = Q_KEY_CODE_N, - [kVK_ANSI_O] = Q_KEY_CODE_O, - [kVK_ANSI_P] = Q_KEY_CODE_P, - [kVK_ANSI_Q] = Q_KEY_CODE_Q, - [kVK_ANSI_R] = Q_KEY_CODE_R, - [kVK_ANSI_S] = Q_KEY_CODE_S, - [kVK_ANSI_T] = Q_KEY_CODE_T, - [kVK_ANSI_U] = Q_KEY_CODE_U, - [kVK_ANSI_V] = Q_KEY_CODE_V, - [kVK_ANSI_W] = Q_KEY_CODE_W, - [kVK_ANSI_X] = Q_KEY_CODE_X, - [kVK_ANSI_Y] = Q_KEY_CODE_Y, - [kVK_ANSI_Z] = Q_KEY_CODE_Z, - - [kVK_ANSI_0] = Q_KEY_CODE_0, - [kVK_ANSI_1] = Q_KEY_CODE_1, - [kVK_ANSI_2] = Q_KEY_CODE_2, - [kVK_ANSI_3] = Q_KEY_CODE_3, - [kVK_ANSI_4] = Q_KEY_CODE_4, - [kVK_ANSI_5] = Q_KEY_CODE_5, - [kVK_ANSI_6] = Q_KEY_CODE_6, - [kVK_ANSI_7] = Q_KEY_CODE_7, - [kVK_ANSI_8] = Q_KEY_CODE_8, - [kVK_ANSI_9] = Q_KEY_CODE_9, - - [kVK_ANSI_Grave] = Q_KEY_CODE_GRAVE_ACCENT, - [kVK_ANSI_Minus] = Q_KEY_CODE_MINUS, - [kVK_ANSI_Equal] = Q_KEY_CODE_EQUAL, - [kVK_Delete] = Q_KEY_CODE_BACKSPACE, - [kVK_CapsLock] = Q_KEY_CODE_CAPS_LOCK, - [kVK_Tab] = Q_KEY_CODE_TAB, - [kVK_Return] = Q_KEY_CODE_RET, - [kVK_ANSI_LeftBracket] = Q_KEY_CODE_BRACKET_LEFT, - [kVK_ANSI_RightBracket] = Q_KEY_CODE_BRACKET_RIGHT, - [kVK_ANSI_Backslash] = Q_KEY_CODE_BACKSLASH, - [kVK_ANSI_Semicolon] = Q_KEY_CODE_SEMICOLON, - [kVK_ANSI_Quote] = Q_KEY_CODE_APOSTROPHE, - [kVK_ANSI_Comma] = Q_KEY_CODE_COMMA, - [kVK_ANSI_Period] = Q_KEY_CODE_DOT, - [kVK_ANSI_Slash] = Q_KEY_CODE_SLASH, - [kVK_Shift] = Q_KEY_CODE_SHIFT, - [kVK_RightShift] = Q_KEY_CODE_SHIFT_R, - [kVK_Control] = Q_KEY_CODE_CTRL, - [kVK_RightControl] = Q_KEY_CODE_CTRL_R, - [kVK_Option] = Q_KEY_CODE_ALT, - [kVK_RightOption] = Q_KEY_CODE_ALT_R, - [kVK_Command] = Q_KEY_CODE_META_L, - [0x36] = Q_KEY_CODE_META_R, /* There is no kVK_RightCommand */ - [kVK_Space] = Q_KEY_CODE_SPC, - - [kVK_ANSI_Keypad0] = Q_KEY_CODE_KP_0, - [kVK_ANSI_Keypad1] = Q_KEY_CODE_KP_1, - [kVK_ANSI_Keypad2] = Q_KEY_CODE_KP_2, - [kVK_ANSI_Keypad3] = Q_KEY_CODE_KP_3, - [kVK_ANSI_Keypad4] = Q_KEY_CODE_KP_4, - [kVK_ANSI_Keypad5] = Q_KEY_CODE_KP_5, - [kVK_ANSI_Keypad6] = Q_KEY_CODE_KP_6, - [kVK_ANSI_Keypad7] = Q_KEY_CODE_KP_7, - [kVK_ANSI_Keypad8] = Q_KEY_CODE_KP_8, - [kVK_ANSI_Keypad9] = Q_KEY_CODE_KP_9, - [kVK_ANSI_KeypadDecimal] = Q_KEY_CODE_KP_DECIMAL, - [kVK_ANSI_KeypadEnter] = Q_KEY_CODE_KP_ENTER, - [kVK_ANSI_KeypadPlus] = Q_KEY_CODE_KP_ADD, - [kVK_ANSI_KeypadMinus] = Q_KEY_CODE_KP_SUBTRACT, - [kVK_ANSI_KeypadMultiply] = Q_KEY_CODE_KP_MULTIPLY, - [kVK_ANSI_KeypadDivide] = Q_KEY_CODE_KP_DIVIDE, - [kVK_ANSI_KeypadEquals] = Q_KEY_CODE_KP_EQUALS, - [kVK_ANSI_KeypadClear] = Q_KEY_CODE_NUM_LOCK, - - [kVK_UpArrow] = Q_KEY_CODE_UP, - [kVK_DownArrow] = Q_KEY_CODE_DOWN, - [kVK_LeftArrow] = Q_KEY_CODE_LEFT, - [kVK_RightArrow] = Q_KEY_CODE_RIGHT, - - [kVK_Help] = Q_KEY_CODE_INSERT, - [kVK_Home] = Q_KEY_CODE_HOME, - [kVK_PageUp] = Q_KEY_CODE_PGUP, - [kVK_PageDown] = Q_KEY_CODE_PGDN, - [kVK_End] = Q_KEY_CODE_END, - [kVK_ForwardDelete] = Q_KEY_CODE_DELETE, - - [kVK_Escape] = Q_KEY_CODE_ESC, - - /* The Power key can't be used directly because the operating system uses - * it. This key can be emulated by using it in place of another key such as - * F1. Don't forget to disable the real key binding. - */ - /* [kVK_F1] = Q_KEY_CODE_POWER, */ - - [kVK_F1] = Q_KEY_CODE_F1, - [kVK_F2] = Q_KEY_CODE_F2, - [kVK_F3] = Q_KEY_CODE_F3, - [kVK_F4] = Q_KEY_CODE_F4, - [kVK_F5] = Q_KEY_CODE_F5, - [kVK_F6] = Q_KEY_CODE_F6, - [kVK_F7] = Q_KEY_CODE_F7, - [kVK_F8] = Q_KEY_CODE_F8, - [kVK_F9] = Q_KEY_CODE_F9, - [kVK_F10] = Q_KEY_CODE_F10, - [kVK_F11] = Q_KEY_CODE_F11, - [kVK_F12] = Q_KEY_CODE_F12, - [kVK_F13] = Q_KEY_CODE_PRINT, - [kVK_F14] = Q_KEY_CODE_SCROLL_LOCK, - [kVK_F15] = Q_KEY_CODE_PAUSE, - - /* - * The eject and volume keys can't be used here because they are handled at - * a lower level than what an Application can see. - */ -}; - -static int cocoa_keycode_to_qemu(int keycode) -{ - if (ARRAY_SIZE(mac_to_qkeycode_map) <= keycode) { - fprintf(stderr, "(cocoa) warning unknown keycode 0x%x\n", keycode); - return 0; - } - return mac_to_qkeycode_map[keycode]; -} - -/* Displays an alert dialog box with the specified message */ -static void QEMU_Alert(NSString *message) -{ - NSAlert *alert; - alert = [NSAlert new]; - [alert setMessageText: message]; - [alert runModal]; -} - -/* Handles any errors that happen with a device transaction */ -static void handleAnyDeviceErrors(Error * err) -{ - if (err) { - QEMU_Alert([NSString stringWithCString: error_get_pretty(err) - encoding: NSASCIIStringEncoding]); - error_free(err); - } -} - -/* - ------------------------------------------------------ - QemuCocoaView - ------------------------------------------------------ -*/ -@interface QemuCocoaView : NSView -{ - QEMUScreen screen; - NSWindow *fullScreenWindow; - float cx,cy,cw,ch,cdx,cdy; - CGDataProviderRef dataProviderRef; - int modifiers_state[256]; - BOOL isMouseGrabbed; - BOOL isFullscreen; - BOOL isAbsoluteEnabled; - BOOL isMouseDeassociated; -} -- (void) switchSurface:(DisplaySurface *)surface; -- (void) grabMouse; -- (void) ungrabMouse; -- (void) toggleFullScreen:(id)sender; -- (void) handleEvent:(NSEvent *)event; -- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled; -/* The state surrounding mouse grabbing is potentially confusing. - * isAbsoluteEnabled tracks qemu_input_is_absolute() [ie "is the emulated - * pointing device an absolute-position one?"], but is only updated on - * next refresh. - * isMouseGrabbed tracks whether GUI events are directed to the guest; - * it controls whether special keys like Cmd get sent to the guest, - * and whether we capture the mouse when in non-absolute mode. - * isMouseDeassociated tracks whether we've told MacOSX to disassociate - * the mouse and mouse cursor position by calling - * CGAssociateMouseAndMouseCursorPosition(FALSE) - * (which basically happens if we grab in non-absolute mode). - */ -- (BOOL) isMouseGrabbed; -- (BOOL) isAbsoluteEnabled; -- (BOOL) isMouseDeassociated; -- (float) cdx; -- (float) cdy; -- (QEMUScreen) gscreen; -- (void) raiseAllKeys; -@end - -QemuCocoaView *cocoaView; - -@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; -} - -- (BOOL) screenContainsPoint:(NSPoint) p -{ - return (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height); -} - -- (void) hideCursor -{ - if (!cursor_hide) { - return; - } - [NSCursor hide]; -} - -- (void) unhideCursor -{ - if (!cursor_hide) { - return; - } - [NSCursor unhide]; -} - -- (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) { - // Draw request before any guest device has set up a framebuffer: - // just draw an opaque black rectangle - CGContextSetRGBFillColor(viewContextRef, 0, 0, 0, 1.0); - CGContextFillRect(viewContextRef, NSRectToCGRect(rect)); - } else { - 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 - ); - // selective drawing code (draws only dirty rectangles) (OS X >= 10.4) - const NSRect *rectList; - NSInteger rectCount; - 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); - } - 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; - - /* stretches video, but keeps same aspect ratio */ - if (stretch_video == true) { - /* use smallest stretch value - prevents clipping on sides */ - if (MIN(cdx, cdy) == cdx) { - cdy = cdx; - } else { - cdx = cdy; - } - } else { /* No stretching */ - cdx = cdy = 1; - } - 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) switchSurface:(DisplaySurface *)surface -{ - COCOA_DEBUG("QemuCocoaView: switchSurface\n"); - - int w = surface_width(surface); - int h = surface_height(surface); - /* cdx == 0 means this is our very first surface, in which case we need - * to recalculate the content dimensions even if it happens to be the size - * of the initial empty window. - */ - bool isResize = (w != screen.width || h != screen.height || cdx == 0.0); - - int oldh = screen.height; - if (isResize) { - // Resize before we trigger the redraw, or we'll redraw at the wrong size - COCOA_DEBUG("switchSurface: new size %d x %d\n", w, h); - screen.width = w; - screen.height = h; - [self setContentDimensions]; - [self setFrame:NSMakeRect(cx, cy, cw, ch)]; - } - - // update screenBuffer - if (dataProviderRef) - CGDataProviderRelease(dataProviderRef); - - //sync host window color space with guests - screen.bitsPerPixel = surface_bits_per_pixel(surface); - screen.bitsPerComponent = surface_bytes_per_pixel(surface) * 2; - - dataProviderRef = CGDataProviderCreateWithData(NULL, surface_data(surface), 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 + oldh, w, h + [normalWindow frame].size.height - oldh) 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 + oldh, w, h + [normalWindow frame].size.height - oldh) display:YES animate:NO]; - } - - if (isResize) { - [normalWindow center]; - } -} - -- (void) toggleFullScreen:(id)sender -{ - COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n"); - - if (isFullscreen) { // switch from fullscreen to desktop - isFullscreen = FALSE; - [self ungrabMouse]; - [self setContentDimensions]; - if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime - [self exitFullScreenModeWithOptions:nil]; - } else { - [fullScreenWindow close]; - [normalWindow setContentView: self]; - [normalWindow makeKeyAndOrderFront: self]; - [NSMenu setMenuBarVisible:YES]; - } - } else { // switch from desktop to fullscreen - isFullscreen = TRUE; - [normalWindow orderOut: nil]; /* Hide the window */ - [self grabMouse]; - [self setContentDimensions]; - 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 { - [NSMenu setMenuBarVisible:NO]; - fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - [fullScreenWindow setAcceptsMouseMovedEvents: YES]; - [fullScreenWindow setHasShadow:NO]; - [fullScreenWindow setBackgroundColor: [NSColor blackColor]]; - [self setFrame:NSMakeRect(cx, cy, cw, ch)]; - [[fullScreenWindow contentView] addSubview: self]; - [fullScreenWindow makeKeyAndOrderFront:self]; - } - } -} - -- (void) handleEvent:(NSEvent *)event -{ - COCOA_DEBUG("QemuCocoaView: handleEvent\n"); - - int buttons = 0; - int keycode; - bool mouse_event = false; - NSPoint p = [event locationInWindow]; - - switch ([event type]) { - case NSFlagsChanged: - keycode = cocoa_keycode_to_qemu([event keyCode]); - - if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R) - && !isMouseGrabbed) { - /* Don't pass command key changes to guest unless mouse is grabbed */ - keycode = 0; - } - - if (keycode) { - // emulate caps lock and num lock keydown and keyup - if (keycode == Q_KEY_CODE_CAPS_LOCK || - keycode == Q_KEY_CODE_NUM_LOCK) { - qemu_input_event_send_key_qcode(dcl->con, keycode, true); - qemu_input_event_send_key_qcode(dcl->con, keycode, false); - } else if (qemu_console_is_graphic(NULL)) { - if (modifiers_state[keycode] == 0) { // keydown - qemu_input_event_send_key_qcode(dcl->con, keycode, true); - modifiers_state[keycode] = 1; - } else { // keyup - qemu_input_event_send_key_qcode(dcl->con, keycode, false); - modifiers_state[keycode] = 0; - } - } - } - - // release Mouse grab when pressing ctrl+alt - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { - [self ungrabMouse]; - } - break; - case NSKeyDown: - keycode = cocoa_keycode_to_qemu([event keyCode]); - - // forward command key combos to the host UI unless the mouse is grabbed - if (!isMouseGrabbed && ([event modifierFlags] & NSCommandKeyMask)) { - [NSApp sendEvent:event]; - return; - } - - // default - - // handle control + alt Key Combos (ctrl+alt is reserved for QEMU) - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { - switch (keycode) { - - // enable graphic console - case Q_KEY_CODE_1 ... Q_KEY_CODE_9: // '1' to '9' keys - console_select(keycode - 11); - break; - } - - // handle keys for graphic console - } else if (qemu_console_is_graphic(NULL)) { - qemu_input_event_send_key_qcode(dcl->con, keycode, true); - - // 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]); - - // don't pass the guest a spurious key-up if we treated this - // command-key combo as a host UI action - if (!isMouseGrabbed && ([event modifierFlags] & NSCommandKeyMask)) { - return; - } - - if (qemu_console_is_graphic(NULL)) { - qemu_input_event_send_key_qcode(dcl->con, keycode, false); - } - break; - case NSMouseMoved: - if (isAbsoluteEnabled) { - if (![self screenContainsPoint:p] || ![[self window] isKeyWindow]) { - if (isMouseGrabbed) { - [self ungrabMouse]; - } - } else { - if (!isMouseGrabbed) { - [self grabMouse]; - } - } - } - mouse_event = true; - break; - case NSLeftMouseDown: - if ([event modifierFlags] & NSCommandKeyMask) { - buttons |= MOUSE_EVENT_RBUTTON; - } else { - buttons |= MOUSE_EVENT_LBUTTON; - } - mouse_event = true; - break; - case NSRightMouseDown: - buttons |= MOUSE_EVENT_RBUTTON; - mouse_event = true; - break; - case NSOtherMouseDown: - buttons |= MOUSE_EVENT_MBUTTON; - mouse_event = true; - break; - case NSLeftMouseDragged: - if ([event modifierFlags] & NSCommandKeyMask) { - buttons |= MOUSE_EVENT_RBUTTON; - } else { - buttons |= MOUSE_EVENT_LBUTTON; - } - mouse_event = true; - break; - case NSRightMouseDragged: - buttons |= MOUSE_EVENT_RBUTTON; - mouse_event = true; - break; - case NSOtherMouseDragged: - buttons |= MOUSE_EVENT_MBUTTON; - mouse_event = true; - break; - case NSLeftMouseUp: - mouse_event = true; - if (!isMouseGrabbed && [self screenContainsPoint:p]) { - [self grabMouse]; - } - break; - case NSRightMouseUp: - mouse_event = true; - break; - case NSOtherMouseUp: - mouse_event = true; - break; - case NSScrollWheel: - if (isMouseGrabbed) { - buttons |= ([event deltaY] < 0) ? - MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN; - } - mouse_event = true; - break; - default: - [NSApp sendEvent:event]; - } - - if (mouse_event) { - /* Don't send button events to the guest unless we've got a - * mouse grab or window focus. If we have neither then this event - * is the user clicking on the background window to activate and - * bring us to the front, which will be done by the sendEvent - * call below. We definitely don't want to pass that click through - * to the guest. - */ - if ((isMouseGrabbed || [[self window] isKeyWindow]) && - (last_buttons != buttons)) { - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, - [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, - [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, - [INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP, - [INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN, - }; - qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons); - last_buttons = buttons; - } - if (isMouseGrabbed) { - if (isAbsoluteEnabled) { - /* Note that the origin for Cocoa mouse coords is bottom left, not top left. - * The check on screenContainsPoint is to avoid sending out of range values for - * clicks in the titlebar. - */ - if ([self screenContainsPoint:p]) { - qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width); - qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, screen.height); - } - } else { - qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]); - qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]); - } - } else { - [NSApp sendEvent:event]; - } - qemu_input_event_sync(); - } -} - -- (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)"]; - } - [self hideCursor]; - if (!isAbsoluteEnabled) { - isMouseDeassociated = TRUE; - CGAssociateMouseAndMouseCursorPosition(FALSE); - } - isMouseGrabbed = TRUE; // while isMouseGrabbed = 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"]; - } - [self unhideCursor]; - if (isMouseDeassociated) { - CGAssociateMouseAndMouseCursorPosition(TRUE); - isMouseDeassociated = FALSE; - } - isMouseGrabbed = FALSE; -} - -- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;} -- (BOOL) isMouseGrabbed {return isMouseGrabbed;} -- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;} -- (BOOL) isMouseDeassociated {return isMouseDeassociated;} -- (float) cdx {return cdx;} -- (float) cdy {return cdy;} -- (QEMUScreen) gscreen {return screen;} - -/* - * Makes the target think all down keys are being released. - * This prevents a stuck key problem, since we will not see - * key up events for those keys after we have lost focus. - */ -- (void) raiseAllKeys -{ - int index; - const int max_index = ARRAY_SIZE(modifiers_state); - - for (index = 0; index < max_index; index++) { - if (modifiers_state[index]) { - modifiers_state[index] = 0; - qemu_input_event_send_key_qcode(dcl->con, index, false); - } - } -} -@end - - - -/* - ------------------------------------------------------ - QemuCocoaAppController - ------------------------------------------------------ -*/ -@interface QemuCocoaAppController : NSObject -#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) - <NSWindowDelegate, NSApplicationDelegate> -#endif -{ -} -- (void)startEmulationWithArgc:(int)argc argv:(char**)argv; -- (void)doToggleFullScreen:(id)sender; -- (void)toggleFullScreen:(id)sender; -- (void)showQEMUDoc:(id)sender; -- (void)showQEMUTec:(id)sender; -- (void)zoomToFit:(id) sender; -- (void)displayConsole:(id)sender; -- (void)pauseQEMU:(id)sender; -- (void)resumeQEMU:(id)sender; -- (void)displayPause; -- (void)removePause; -- (void)restartQEMU:(id)sender; -- (void)powerDownQEMU:(id)sender; -- (void)ejectDeviceMedia:(id)sender; -- (void)changeDeviceMedia:(id)sender; -- (BOOL)verifyQuit; -- (void)openDocumentation:(NSString *)filename; -@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:@"QEMU"]; - [normalWindow setContentView:cocoaView]; -#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10) - [normalWindow useOptimizedDrawing:YES]; -#endif - [normalWindow makeKeyAndOrderFront:self]; - [normalWindow center]; - [normalWindow setDelegate: self]; - stretch_video = false; - - /* Used for displaying pause on the screen */ - pauseLabel = [NSTextField new]; - [pauseLabel setBezeled:YES]; - [pauseLabel setDrawsBackground:YES]; - [pauseLabel setBackgroundColor: [NSColor whiteColor]]; - [pauseLabel setEditable:NO]; - [pauseLabel setSelectable:NO]; - [pauseLabel setStringValue: @"Paused"]; - [pauseLabel setFont: [NSFont fontWithName: @"Helvetica" size: 90]]; - [pauseLabel setTextColor: [NSColor blackColor]]; - [pauseLabel sizeToFit]; - - // set the supported image file types that can be opened - supportedImageFileTypes = [NSArray arrayWithObjects: @"img", @"iso", @"dmg", - @"qcow", @"qcow2", @"cloop", @"vmdk", @"cdr", - nil]; - } - return self; -} - -- (void) dealloc -{ - COCOA_DEBUG("QemuCocoaAppController: dealloc\n"); - - if (cocoaView) - [cocoaView release]; - [super dealloc]; -} - -- (void)applicationDidFinishLaunching: (NSNotification *) note -{ - COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); - // 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; -} - -- (NSApplicationTerminateReply)applicationShouldTerminate: - (NSApplication *)sender -{ - COCOA_DEBUG("QemuCocoaAppController: applicationShouldTerminate\n"); - return [self verifyQuit]; -} - -/* Called when the user clicks on a window's close button */ -- (BOOL)windowShouldClose:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: windowShouldClose\n"); - [NSApp terminate: sender]; - /* If the user allows the application to quit then the call to - * NSApp terminate will never return. If we get here then the user - * cancelled the quit, so we should return NO to not permit the - * closing of this window. - */ - return NO; -} - -/* Called when QEMU goes into the background */ -- (void) applicationWillResignActive: (NSNotification *)aNotification -{ - COCOA_DEBUG("QemuCocoaAppController: applicationWillResignActive\n"); - [cocoaView raiseAllKeys]; -} - -- (void)startEmulationWithArgc:(int)argc argv:(char**)argv -{ - COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n"); - - int status; - status = qemu_main(argc, argv, *_NSGetEnviron()); - exit(status); -} - -/* We abstract the method called by the Enter Fullscreen menu item - * because Mac OS 10.7 and higher disables it. This is because of the - * menu item's old selector's name toggleFullScreen: - */ -- (void) doToggleFullScreen:(id)sender -{ - [self toggleFullScreen:(id)sender]; -} - -- (void)toggleFullScreen:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n"); - - [cocoaView toggleFullScreen:sender]; -} - -/* Tries to find then open the specified filename */ -- (void) openDocumentation: (NSString *) filename -{ - /* Where to look for local files */ - NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../"}; - NSString *full_file_path; - - /* iterate thru the possible paths until the file is found */ - int index; - for (index = 0; index < ARRAY_SIZE(path_array); index++) { - full_file_path = [[NSBundle mainBundle] executablePath]; - full_file_path = [full_file_path stringByDeletingLastPathComponent]; - full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path, - path_array[index], filename]; - if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) { - return; - } - } - - /* If none of the paths opened a file */ - NSBeep(); - QEMU_Alert(@"Failed to open file"); -} - -- (void)showQEMUDoc:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n"); - - [self openDocumentation: @"qemu-doc.html"]; -} - -- (void)showQEMUTec:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n"); - - [self openDocumentation: @"qemu-tech.html"]; -} - -/* Stretches video to fit host monitor size */ -- (void)zoomToFit:(id) sender -{ - stretch_video = !stretch_video; - if (stretch_video == true) { - [sender setState: NSOnState]; - } else { - [sender setState: NSOffState]; - } -} - -/* Displays the console on the screen */ -- (void)displayConsole:(id)sender -{ - console_select([sender tag]); -} - -/* Pause the guest */ -- (void)pauseQEMU:(id)sender -{ - qmp_stop(NULL); - [sender setEnabled: NO]; - [[[sender menu] itemWithTitle: @"Resume"] setEnabled: YES]; - [self displayPause]; -} - -/* Resume running the guest operating system */ -- (void)resumeQEMU:(id) sender -{ - qmp_cont(NULL); - [sender setEnabled: NO]; - [[[sender menu] itemWithTitle: @"Pause"] setEnabled: YES]; - [self removePause]; -} - -/* Displays the word pause on the screen */ -- (void)displayPause -{ - /* Coordinates have to be calculated each time because the window can change its size */ - int xCoord, yCoord, width, height; - xCoord = ([normalWindow frame].size.width - [pauseLabel frame].size.width)/2; - yCoord = [normalWindow frame].size.height - [pauseLabel frame].size.height - ([pauseLabel frame].size.height * .5); - width = [pauseLabel frame].size.width; - height = [pauseLabel frame].size.height; - [pauseLabel setFrame: NSMakeRect(xCoord, yCoord, width, height)]; - [cocoaView addSubview: pauseLabel]; -} - -/* Removes the word pause from the screen */ -- (void)removePause -{ - [pauseLabel removeFromSuperview]; -} - -/* Restarts QEMU */ -- (void)restartQEMU:(id)sender -{ - qmp_system_reset(NULL); -} - -/* Powers down QEMU */ -- (void)powerDownQEMU:(id)sender -{ - qmp_system_powerdown(NULL); -} - -/* Ejects the media. - * Uses sender's tag to figure out the device to eject. - */ -- (void)ejectDeviceMedia:(id)sender -{ - NSString * drive; - drive = [sender representedObject]; - if(drive == nil) { - NSBeep(); - QEMU_Alert(@"Failed to find drive to eject!"); - return; - } - - Error *err = NULL; - qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], false, false, &err); - handleAnyDeviceErrors(err); -} - -/* Displays a dialog box asking the user to select an image file to load. - * Uses sender's represented object value to figure out which drive to use. - */ -- (void)changeDeviceMedia:(id)sender -{ - /* Find the drive name */ - NSString * drive; - drive = [sender representedObject]; - if(drive == nil) { - NSBeep(); - QEMU_Alert(@"Could not find drive!"); - return; - } - - /* Display the file open dialog */ - NSOpenPanel * openPanel; - openPanel = [NSOpenPanel openPanel]; - [openPanel setCanChooseFiles: YES]; - [openPanel setAllowsMultipleSelection: NO]; - [openPanel setAllowedFileTypes: supportedImageFileTypes]; - if([openPanel runModal] == NSFileHandlingPanelOKButton) { - NSString * file = [[[openPanel URLs] objectAtIndex: 0] path]; - if(file == nil) { - NSBeep(); - QEMU_Alert(@"Failed to convert URL to file path!"); - return; - } - - Error *err = NULL; - qmp_blockdev_change_medium([drive cStringUsingEncoding: - NSASCIIStringEncoding], - [file cStringUsingEncoding: - NSASCIIStringEncoding], - true, "raw", - false, 0, - &err); - handleAnyDeviceErrors(err); - } -} - -/* Verifies if the user really wants to quit */ -- (BOOL)verifyQuit -{ - NSAlert *alert = [NSAlert new]; - [alert autorelease]; - [alert setMessageText: @"Are you sure you want to quit QEMU?"]; - [alert addButtonWithTitle: @"Cancel"]; - [alert addButtonWithTitle: @"Quit"]; - if([alert runModal] == NSAlertSecondButtonReturn) { - return YES; - } else { - return NO; - } -} - -@end - - -int main (int argc, const char * argv[]) { - - gArgc = argc; - gArgv = (char **)argv; - int i; - - /* In case we don't need to display a window, let's not do that */ - for (i = 1; i < argc; i++) { - const char *opt = argv[i]; - - if (opt[0] == '-') { - /* Treat --foo the same as -foo. */ - if (opt[1] == '-') { - opt++; - } - if (!strcmp(opt, "-h") || !strcmp(opt, "-help") || - !strcmp(opt, "-vnc") || - !strcmp(opt, "-nographic") || - !strcmp(opt, "-version") || - !strcmp(opt, "-curses") || - !strcmp(opt, "-display") || - !strcmp(opt, "-qtest")) { - return qemu_main(gArgc, gArgv, *_NSGetEnviron()); - } - } - } - - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - // Pull this console process up to being a fully-fledged graphical - // app with a menubar and Dock icon - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - [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+) - - // Machine menu - menu = [[NSMenu alloc] initWithTitle: @"Machine"]; - [menu setAutoenablesItems: NO]; - [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Pause" action: @selector(pauseQEMU:) keyEquivalent: @""] autorelease]]; - menuItem = [[[NSMenuItem alloc] initWithTitle: @"Resume" action: @selector(resumeQEMU:) keyEquivalent: @""] autorelease]; - [menu addItem: menuItem]; - [menuItem setEnabled: NO]; - [menu addItem: [NSMenuItem separatorItem]]; - [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Reset" action: @selector(restartQEMU:) keyEquivalent: @""] autorelease]]; - [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Power Down" action: @selector(powerDownQEMU:) keyEquivalent: @""] autorelease]]; - menuItem = [[[NSMenuItem alloc] initWithTitle: @"Machine" action:nil keyEquivalent:@""] autorelease]; - [menuItem setSubmenu:menu]; - [[NSApp mainMenu] addItem:menuItem]; - - // View menu - menu = [[NSMenu alloc] initWithTitle:@"View"]; - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(doToggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Zoom To Fit" action:@selector(zoomToFit:) keyEquivalent:@""] autorelease]]; - 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(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - 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]; - - [pool release]; -} - -static void cocoa_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - COCOA_DEBUG("qemu_cocoa: cocoa_switch\n"); - [cocoaView switchSurface:surface]; - [pool release]; -} - -static void cocoa_refresh(DisplayChangeListener *dcl) -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); - graphic_hw_update(NULL); - - if (qemu_input_is_absolute()) { - if (![cocoaView isAbsoluteEnabled]) { - if ([cocoaView isMouseGrabbed]) { - [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); - [pool release]; -} - -static void cocoa_cleanup(void) -{ - COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n"); - g_free(dcl); -} - -static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "cocoa", - .dpy_gfx_update = cocoa_update, - .dpy_gfx_switch = cocoa_switch, - .dpy_refresh = cocoa_refresh, -}; - -/* Returns a name for a given console */ -static NSString * getConsoleName(QemuConsole * console) -{ - return [NSString stringWithFormat: @"%s", qemu_console_get_label(console)]; -} - -/* Add an entry to the View menu for each console */ -static void add_console_menu_entries(void) -{ - NSMenu *menu; - NSMenuItem *menuItem; - int index = 0; - - menu = [[[NSApp mainMenu] itemWithTitle:@"View"] submenu]; - - [menu addItem:[NSMenuItem separatorItem]]; - - while (qemu_console_lookup_by_index(index) != NULL) { - menuItem = [[[NSMenuItem alloc] initWithTitle: getConsoleName(qemu_console_lookup_by_index(index)) - action: @selector(displayConsole:) keyEquivalent: @""] autorelease]; - [menuItem setTag: index]; - [menu addItem: menuItem]; - index++; - } -} - -/* Make menu items for all removable devices. - * Each device is given an 'Eject' and 'Change' menu item. - */ -static void addRemovableDevicesMenuItems(void) -{ - NSMenu *menu; - NSMenuItem *menuItem; - BlockInfoList *currentDevice, *pointerToFree; - NSString *deviceName; - - currentDevice = qmp_query_block(NULL); - pointerToFree = currentDevice; - if(currentDevice == NULL) { - NSBeep(); - QEMU_Alert(@"Failed to query for block devices!"); - return; - } - - menu = [[[NSApp mainMenu] itemWithTitle:@"Machine"] submenu]; - - // Add a separator between related groups of menu items - [menu addItem:[NSMenuItem separatorItem]]; - - // Set the attributes to the "Removable Media" menu item - NSString *titleString = @"Removable Media"; - NSMutableAttributedString *attString=[[NSMutableAttributedString alloc] initWithString:titleString]; - NSColor *newColor = [NSColor blackColor]; - NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFont *font = [fontManager fontWithFamily:@"Helvetica" - traits:NSBoldFontMask|NSItalicFontMask - weight:0 - size:14]; - [attString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [titleString length])]; - [attString addAttribute:NSForegroundColorAttributeName value:newColor range:NSMakeRange(0, [titleString length])]; - [attString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt: 1] range:NSMakeRange(0, [titleString length])]; - - // Add the "Removable Media" menu item - menuItem = [NSMenuItem new]; - [menuItem setAttributedTitle: attString]; - [menuItem setEnabled: NO]; - [menu addItem: menuItem]; - - /* Loop thru all the block devices in the emulator */ - while (currentDevice) { - deviceName = [[NSString stringWithFormat: @"%s", currentDevice->value->device] retain]; - - if(currentDevice->value->removable) { - menuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Change %s...", currentDevice->value->device] - action: @selector(changeDeviceMedia:) - keyEquivalent: @""]; - [menu addItem: menuItem]; - [menuItem setRepresentedObject: deviceName]; - [menuItem autorelease]; - - menuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Eject %s", currentDevice->value->device] - action: @selector(ejectDeviceMedia:) - keyEquivalent: @""]; - [menu addItem: menuItem]; - [menuItem setRepresentedObject: deviceName]; - [menuItem autorelease]; - } - currentDevice = currentDevice->next; - } - qapi_free_BlockInfoList(pointerToFree); -} - -void cocoa_display_init(DisplayState *ds, int full_screen) -{ - COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); - - /* if fullscreen mode is to be used */ - if (full_screen == true) { - [NSApp activateIgnoringOtherApps: YES]; - [(QemuCocoaAppController *)[[NSApplication sharedApplication] delegate] toggleFullScreen: nil]; - } - - dcl = g_malloc0(sizeof(DisplayChangeListener)); - - // register vga output callbacks - dcl->ops = &dcl_ops; - register_displaychangelistener(dcl); - - // register cleanup function - atexit(cocoa_cleanup); - - /* At this point QEMU has created all the consoles, so we can add View - * menu entries for them. - */ - add_console_menu_entries(); - - /* Give all removable devices a menu item. - * Has to be called after QEMU has started to - * find out what removable devices it has. - */ - addRemovableDevicesMenuItems(); -} diff --git a/qemu/ui/console-gl.c b/qemu/ui/console-gl.c deleted file mode 100644 index 74b1bed6e..000000000 --- a/qemu/ui/console-gl.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * QEMU graphical console -- opengl helper bits - * - * Copyright (c) 2014 Red Hat - * - * Authors: - * Gerd Hoffmann <kraxel@redhat.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/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/shader.h" - -#include "shader/texture-blit-vert.h" -#include "shader/texture-blit-frag.h" - -struct ConsoleGLState { - GLint texture_blit_prog; - GLint texture_blit_vao; -}; - -/* ---------------------------------------------------------------------- */ - -ConsoleGLState *console_gl_init_context(void) -{ - ConsoleGLState *gls = g_new0(ConsoleGLState, 1); - - gls->texture_blit_prog = qemu_gl_create_compile_link_program - (texture_blit_vert_src, texture_blit_frag_src); - if (!gls->texture_blit_prog) { - exit(1); - } - - gls->texture_blit_vao = - qemu_gl_init_texture_blit(gls->texture_blit_prog); - - return gls; -} - -void console_gl_fini_context(ConsoleGLState *gls) -{ - if (!gls) { - return; - } - g_free(gls); -} - -bool console_gl_check_format(DisplayChangeListener *dcl, - pixman_format_code_t format) -{ - switch (format) { - case PIXMAN_BE_b8g8r8x8: - case PIXMAN_BE_b8g8r8a8: - case PIXMAN_r5g6b5: - return true; - default: - return false; - } -} - -void surface_gl_create_texture(ConsoleGLState *gls, - DisplaySurface *surface) -{ - assert(gls); - assert(surface_stride(surface) % surface_bytes_per_pixel(surface) == 0); - - switch (surface->format) { - case PIXMAN_BE_b8g8r8x8: - case PIXMAN_BE_b8g8r8a8: - surface->glformat = GL_BGRA_EXT; - surface->gltype = GL_UNSIGNED_BYTE; - break; - case PIXMAN_r5g6b5: - surface->glformat = GL_RGB; - surface->gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - default: - g_assert_not_reached(); - } - - glGenTextures(1, &surface->texture); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, surface->texture); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, - surface_stride(surface) / surface_bytes_per_pixel(surface)); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - surface_width(surface), - surface_height(surface), - 0, surface->glformat, surface->gltype, - surface_data(surface)); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void surface_gl_update_texture(ConsoleGLState *gls, - DisplaySurface *surface, - int x, int y, int w, int h) -{ - uint8_t *data = (void *)surface_data(surface); - - assert(gls); - - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, - surface_stride(surface) / surface_bytes_per_pixel(surface)); - glTexSubImage2D(GL_TEXTURE_2D, 0, - x, y, w, h, - surface->glformat, surface->gltype, - data + surface_stride(surface) * y - + surface_bytes_per_pixel(surface) * x); -} - -void surface_gl_render_texture(ConsoleGLState *gls, - DisplaySurface *surface) -{ - assert(gls); - - glClearColor(0.1f, 0.1f, 0.1f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - qemu_gl_run_texture_blit(gls->texture_blit_prog, - gls->texture_blit_vao); -} - -void surface_gl_destroy_texture(ConsoleGLState *gls, - DisplaySurface *surface) -{ - if (!surface || !surface->texture) { - return; - } - glDeleteTextures(1, &surface->texture); - surface->texture = 0; -} - -void surface_gl_setup_viewport(ConsoleGLState *gls, - DisplaySurface *surface, - int ww, int wh) -{ - int gw, gh, stripe; - float sw, sh; - - assert(gls); - - gw = surface_width(surface); - gh = surface_height(surface); - - sw = (float)ww/gw; - sh = (float)wh/gh; - if (sw < sh) { - stripe = wh - wh*sw/sh; - glViewport(0, stripe / 2, ww, wh - stripe); - } else { - stripe = ww - ww*sh/sw; - glViewport(stripe / 2, 0, ww - stripe, wh); - } -} diff --git a/qemu/ui/console.c b/qemu/ui/console.c deleted file mode 100644 index bf385790b..000000000 --- a/qemu/ui/console.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * QEMU graphical console - * - * Copyright (c) 2004 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/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "hw/qdev-core.h" -#include "qemu/timer.h" -#include "qmp-commands.h" -#include "sysemu/char.h" -#include "trace.h" -#include "exec/memory.h" - -#define DEFAULT_BACKSCROLL 512 -#define CONSOLE_CURSOR_PERIOD 500 - -typedef struct TextAttributes { - uint8_t fgcol:4; - uint8_t bgcol:4; - uint8_t bold:1; - uint8_t uline:1; - uint8_t blink:1; - uint8_t invers:1; - uint8_t unvisible:1; -} TextAttributes; - -typedef struct TextCell { - uint8_t ch; - TextAttributes t_attrib; -} TextCell; - -#define MAX_ESC_PARAMS 3 - -enum TTYState { - TTY_STATE_NORM, - TTY_STATE_ESC, - TTY_STATE_CSI, -}; - -typedef struct QEMUFIFO { - uint8_t *buf; - int buf_size; - int count, wptr, rptr; -} QEMUFIFO; - -static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) -{ - int l, len; - - l = f->buf_size - f->count; - if (len1 > l) - len1 = l; - len = len1; - while (len > 0) { - l = f->buf_size - f->wptr; - if (l > len) - l = len; - memcpy(f->buf + f->wptr, buf, l); - f->wptr += l; - if (f->wptr >= f->buf_size) - f->wptr = 0; - buf += l; - len -= l; - } - f->count += len1; - return len1; -} - -static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) -{ - int l, len; - - if (len1 > f->count) - len1 = f->count; - len = len1; - while (len > 0) { - l = f->buf_size - f->rptr; - if (l > len) - l = len; - memcpy(buf, f->buf + f->rptr, l); - f->rptr += l; - if (f->rptr >= f->buf_size) - f->rptr = 0; - buf += l; - len -= l; - } - f->count -= len1; - return len1; -} - -typedef enum { - GRAPHIC_CONSOLE, - TEXT_CONSOLE, - TEXT_CONSOLE_FIXED_SIZE -} console_type_t; - -struct QemuConsole { - Object parent; - - int index; - console_type_t console_type; - DisplayState *ds; - DisplaySurface *surface; - int dcls; - DisplayChangeListener *gl; - - /* Graphic console state. */ - Object *device; - uint32_t head; - QemuUIInfo ui_info; - QEMUTimer *ui_timer; - const GraphicHwOps *hw_ops; - void *hw; - - /* Text console state */ - int width; - int height; - int total_height; - int backscroll_height; - int x, y; - int x_saved, y_saved; - int y_displayed; - int y_base; - TextAttributes t_attrib_default; /* default text attributes */ - TextAttributes t_attrib; /* currently active text attributes */ - TextCell *cells; - int text_x[2], text_y[2], cursor_invalidate; - int echo; - - int update_x0; - int update_y0; - int update_x1; - int update_y1; - - enum TTYState state; - int esc_params[MAX_ESC_PARAMS]; - int nb_esc_params; - - CharDriverState *chr; - /* fifo for key pressed */ - QEMUFIFO out_fifo; - uint8_t out_fifo_buf[16]; - QEMUTimer *kbd_timer; -}; - -struct DisplayState { - QEMUTimer *gui_timer; - uint64_t last_update; - uint64_t update_interval; - bool refreshing; - bool have_gfx; - bool have_text; - - QLIST_HEAD(, DisplayChangeListener) listeners; -}; - -static DisplayState *display_state; -static QemuConsole *active_console; -static QemuConsole **consoles; -static int nb_consoles = 0; -static bool cursor_visible_phase; -static QEMUTimer *cursor_timer; - -static void text_console_do_init(CharDriverState *chr, DisplayState *ds); -static void dpy_refresh(DisplayState *s); -static DisplayState *get_alloc_displaystate(void); -static void text_console_update_cursor_timer(void); -static void text_console_update_cursor(void *opaque); - -static void gui_update(void *opaque) -{ - uint64_t interval = GUI_REFRESH_INTERVAL_IDLE; - uint64_t dcl_interval; - DisplayState *ds = opaque; - DisplayChangeListener *dcl; - int i; - - ds->refreshing = true; - dpy_refresh(ds); - ds->refreshing = false; - - QLIST_FOREACH(dcl, &ds->listeners, next) { - dcl_interval = dcl->update_interval ? - dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT; - if (interval > dcl_interval) { - interval = dcl_interval; - } - } - if (ds->update_interval != interval) { - ds->update_interval = interval; - for (i = 0; i < nb_consoles; i++) { - if (consoles[i]->hw_ops->update_interval) { - consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval); - } - } - trace_console_refresh(interval); - } - ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - timer_mod(ds->gui_timer, ds->last_update + interval); -} - -static void gui_setup_refresh(DisplayState *ds) -{ - DisplayChangeListener *dcl; - bool need_timer = false; - bool have_gfx = false; - bool have_text = false; - - QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->ops->dpy_refresh != NULL) { - need_timer = true; - } - if (dcl->ops->dpy_gfx_update != NULL) { - have_gfx = true; - } - if (dcl->ops->dpy_text_update != NULL) { - have_text = true; - } - } - - if (need_timer && ds->gui_timer == NULL) { - ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds); - timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); - } - if (!need_timer && ds->gui_timer != NULL) { - timer_del(ds->gui_timer); - timer_free(ds->gui_timer); - ds->gui_timer = NULL; - } - - ds->have_gfx = have_gfx; - ds->have_text = have_text; -} - -void graphic_hw_update(QemuConsole *con) -{ - if (!con) { - con = active_console; - } - if (con && con->hw_ops->gfx_update) { - con->hw_ops->gfx_update(con->hw); - } -} - -void graphic_hw_gl_block(QemuConsole *con, bool block) -{ - if (!con) { - con = active_console; - } - if (con && con->hw_ops->gl_block) { - con->hw_ops->gl_block(con->hw, block); - } -} - -void graphic_hw_invalidate(QemuConsole *con) -{ - if (!con) { - con = active_console; - } - if (con && con->hw_ops->invalidate) { - con->hw_ops->invalidate(con->hw); - } -} - -static void ppm_save(const char *filename, DisplaySurface *ds, - Error **errp) -{ - int width = pixman_image_get_width(ds->image); - int height = pixman_image_get_height(ds->image); - int fd; - FILE *f; - int y; - int ret; - pixman_image_t *linebuf; - - trace_ppm_save(filename, ds); - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); - if (fd == -1) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - f = fdopen(fd, "wb"); - ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); - if (ret < 0) { - linebuf = NULL; - goto write_err; - } - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); - for (y = 0; y < height; y++) { - qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y); - clearerr(f); - ret = fwrite(pixman_image_get_data(linebuf), 1, - pixman_image_get_stride(linebuf), f); - (void)ret; - if (ferror(f)) { - goto write_err; - } - } - -out: - qemu_pixman_image_unref(linebuf); - fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; -} - -void qmp_screendump(const char *filename, Error **errp) -{ - QemuConsole *con = qemu_console_lookup_by_index(0); - DisplaySurface *surface; - - if (con == NULL) { - error_setg(errp, "There is no QemuConsole I can screendump from."); - return; - } - - graphic_hw_update(con); - surface = qemu_console_surface(con); - ppm_save(filename, surface, errp); -} - -void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) -{ - if (!con) { - con = active_console; - } - if (con && con->hw_ops->text_update) { - con->hw_ops->text_update(con->hw, chardata); - } -} - -static void vga_fill_rect(QemuConsole *con, - int posx, int posy, int width, int height, - pixman_color_t color) -{ - DisplaySurface *surface = qemu_console_surface(con); - pixman_rectangle16_t rect = { - .x = posx, .y = posy, .width = width, .height = height - }; - - pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image, - &color, 1, &rect); -} - -/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ -static void vga_bitblt(QemuConsole *con, - int xs, int ys, int xd, int yd, int w, int h) -{ - DisplaySurface *surface = qemu_console_surface(con); - - pixman_image_composite(PIXMAN_OP_SRC, - surface->image, NULL, surface->image, - xs, ys, 0, 0, xd, yd, w, h); -} - -/***********************************************************/ -/* basic char display */ - -#define FONT_HEIGHT 16 -#define FONT_WIDTH 8 - -#include "vgafont.h" - -#define QEMU_RGB(r, g, b) \ - { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff } - -static const pixman_color_t color_table_rgb[2][8] = { - { /* dark */ - [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */ - [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xaa), /* blue */ - [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xaa, 0x00), /* green */ - [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */ - [QEMU_COLOR_RED] = QEMU_RGB(0xaa, 0x00, 0x00), /* red */ - [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */ - [QEMU_COLOR_YELLOW] = QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */ - [QEMU_COLOR_WHITE] = QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */ - }, - { /* bright */ - [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */ - [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xff), /* blue */ - [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xff, 0x00), /* green */ - [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xff, 0xff), /* cyan */ - [QEMU_COLOR_RED] = QEMU_RGB(0xff, 0x00, 0x00), /* red */ - [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff), /* magenta */ - [QEMU_COLOR_YELLOW] = QEMU_RGB(0xff, 0xff, 0x00), /* yellow */ - [QEMU_COLOR_WHITE] = QEMU_RGB(0xff, 0xff, 0xff), /* white */ - } -}; - -static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, - TextAttributes *t_attrib) -{ - static pixman_image_t *glyphs[256]; - DisplaySurface *surface = qemu_console_surface(s); - pixman_color_t fgcol, bgcol; - - if (t_attrib->invers) { - bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol]; - fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol]; - } else { - fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol]; - bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol]; - } - - if (!glyphs[ch]) { - glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch); - } - qemu_pixman_glyph_render(glyphs[ch], surface->image, - &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT); -} - -static void text_console_resize(QemuConsole *s) -{ - TextCell *cells, *c, *c1; - int w1, x, y, last_width; - - last_width = s->width; - s->width = surface_width(s->surface) / FONT_WIDTH; - s->height = surface_height(s->surface) / FONT_HEIGHT; - - w1 = last_width; - if (s->width < w1) - w1 = s->width; - - cells = g_new(TextCell, s->width * s->total_height); - for(y = 0; y < s->total_height; y++) { - c = &cells[y * s->width]; - if (w1 > 0) { - c1 = &s->cells[y * last_width]; - for(x = 0; x < w1; x++) { - *c++ = *c1++; - } - } - for(x = w1; x < s->width; x++) { - c->ch = ' '; - c->t_attrib = s->t_attrib_default; - c++; - } - } - g_free(s->cells); - s->cells = cells; -} - -static inline void text_update_xy(QemuConsole *s, int x, int y) -{ - s->text_x[0] = MIN(s->text_x[0], x); - s->text_x[1] = MAX(s->text_x[1], x); - s->text_y[0] = MIN(s->text_y[0], y); - s->text_y[1] = MAX(s->text_y[1], y); -} - -static void invalidate_xy(QemuConsole *s, int x, int y) -{ - if (!qemu_console_is_visible(s)) { - return; - } - if (s->update_x0 > x * FONT_WIDTH) - s->update_x0 = x * FONT_WIDTH; - if (s->update_y0 > y * FONT_HEIGHT) - s->update_y0 = y * FONT_HEIGHT; - if (s->update_x1 < (x + 1) * FONT_WIDTH) - s->update_x1 = (x + 1) * FONT_WIDTH; - if (s->update_y1 < (y + 1) * FONT_HEIGHT) - s->update_y1 = (y + 1) * FONT_HEIGHT; -} - -static void update_xy(QemuConsole *s, int x, int y) -{ - TextCell *c; - int y1, y2; - - if (s->ds->have_text) { - text_update_xy(s, x, y); - } - - y1 = (s->y_base + y) % s->total_height; - y2 = y1 - s->y_displayed; - if (y2 < 0) { - y2 += s->total_height; - } - if (y2 < s->height) { - c = &s->cells[y1 * s->width + x]; - vga_putcharxy(s, x, y2, c->ch, - &(c->t_attrib)); - invalidate_xy(s, x, y2); - } -} - -static void console_show_cursor(QemuConsole *s, int show) -{ - TextCell *c; - int y, y1; - int x = s->x; - - if (s->ds->have_text) { - s->cursor_invalidate = 1; - } - - if (x >= s->width) { - x = s->width - 1; - } - y1 = (s->y_base + s->y) % s->total_height; - y = y1 - s->y_displayed; - if (y < 0) { - y += s->total_height; - } - if (y < s->height) { - c = &s->cells[y1 * s->width + x]; - if (show && cursor_visible_phase) { - TextAttributes t_attrib = s->t_attrib_default; - t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */ - vga_putcharxy(s, x, y, c->ch, &t_attrib); - } else { - vga_putcharxy(s, x, y, c->ch, &(c->t_attrib)); - } - invalidate_xy(s, x, y); - } -} - -static void console_refresh(QemuConsole *s) -{ - DisplaySurface *surface = qemu_console_surface(s); - TextCell *c; - int x, y, y1; - - if (s->ds->have_text) { - s->text_x[0] = 0; - s->text_y[0] = 0; - s->text_x[1] = s->width - 1; - s->text_y[1] = s->height - 1; - s->cursor_invalidate = 1; - } - - vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface), - color_table_rgb[0][QEMU_COLOR_BLACK]); - y1 = s->y_displayed; - for (y = 0; y < s->height; y++) { - c = s->cells + y1 * s->width; - for (x = 0; x < s->width; x++) { - vga_putcharxy(s, x, y, c->ch, - &(c->t_attrib)); - c++; - } - if (++y1 == s->total_height) { - y1 = 0; - } - } - console_show_cursor(s, 1); - dpy_gfx_update(s, 0, 0, - surface_width(surface), surface_height(surface)); -} - -static void console_scroll(QemuConsole *s, int ydelta) -{ - int i, y1; - - if (ydelta > 0) { - for(i = 0; i < ydelta; i++) { - if (s->y_displayed == s->y_base) - break; - if (++s->y_displayed == s->total_height) - s->y_displayed = 0; - } - } else { - ydelta = -ydelta; - i = s->backscroll_height; - if (i > s->total_height - s->height) - i = s->total_height - s->height; - y1 = s->y_base - i; - if (y1 < 0) - y1 += s->total_height; - for(i = 0; i < ydelta; i++) { - if (s->y_displayed == y1) - break; - if (--s->y_displayed < 0) - s->y_displayed = s->total_height - 1; - } - } - console_refresh(s); -} - -static void console_put_lf(QemuConsole *s) -{ - TextCell *c; - int x, y1; - - s->y++; - if (s->y >= s->height) { - s->y = s->height - 1; - - if (s->y_displayed == s->y_base) { - if (++s->y_displayed == s->total_height) - s->y_displayed = 0; - } - if (++s->y_base == s->total_height) - s->y_base = 0; - if (s->backscroll_height < s->total_height) - s->backscroll_height++; - y1 = (s->y_base + s->height - 1) % s->total_height; - c = &s->cells[y1 * s->width]; - for(x = 0; x < s->width; x++) { - c->ch = ' '; - c->t_attrib = s->t_attrib_default; - c++; - } - if (s->y_displayed == s->y_base) { - if (s->ds->have_text) { - s->text_x[0] = 0; - s->text_y[0] = 0; - s->text_x[1] = s->width - 1; - s->text_y[1] = s->height - 1; - } - - vga_bitblt(s, 0, FONT_HEIGHT, 0, 0, - s->width * FONT_WIDTH, - (s->height - 1) * FONT_HEIGHT); - vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT, - s->width * FONT_WIDTH, FONT_HEIGHT, - color_table_rgb[0][s->t_attrib_default.bgcol]); - s->update_x0 = 0; - s->update_y0 = 0; - s->update_x1 = s->width * FONT_WIDTH; - s->update_y1 = s->height * FONT_HEIGHT; - } - } -} - -/* Set console attributes depending on the current escape codes. - * NOTE: I know this code is not very efficient (checking every color for it - * self) but it is more readable and better maintainable. - */ -static void console_handle_escape(QemuConsole *s) -{ - int i; - - for (i=0; i<s->nb_esc_params; i++) { - switch (s->esc_params[i]) { - case 0: /* reset all console attributes to default */ - s->t_attrib = s->t_attrib_default; - break; - case 1: - s->t_attrib.bold = 1; - break; - case 4: - s->t_attrib.uline = 1; - break; - case 5: - s->t_attrib.blink = 1; - break; - case 7: - s->t_attrib.invers = 1; - break; - case 8: - s->t_attrib.unvisible = 1; - break; - case 22: - s->t_attrib.bold = 0; - break; - case 24: - s->t_attrib.uline = 0; - break; - case 25: - s->t_attrib.blink = 0; - break; - case 27: - s->t_attrib.invers = 0; - break; - case 28: - s->t_attrib.unvisible = 0; - break; - /* set foreground color */ - case 30: - s->t_attrib.fgcol = QEMU_COLOR_BLACK; - break; - case 31: - s->t_attrib.fgcol = QEMU_COLOR_RED; - break; - case 32: - s->t_attrib.fgcol = QEMU_COLOR_GREEN; - break; - case 33: - s->t_attrib.fgcol = QEMU_COLOR_YELLOW; - break; - case 34: - s->t_attrib.fgcol = QEMU_COLOR_BLUE; - break; - case 35: - s->t_attrib.fgcol = QEMU_COLOR_MAGENTA; - break; - case 36: - s->t_attrib.fgcol = QEMU_COLOR_CYAN; - break; - case 37: - s->t_attrib.fgcol = QEMU_COLOR_WHITE; - break; - /* set background color */ - case 40: - s->t_attrib.bgcol = QEMU_COLOR_BLACK; - break; - case 41: - s->t_attrib.bgcol = QEMU_COLOR_RED; - break; - case 42: - s->t_attrib.bgcol = QEMU_COLOR_GREEN; - break; - case 43: - s->t_attrib.bgcol = QEMU_COLOR_YELLOW; - break; - case 44: - s->t_attrib.bgcol = QEMU_COLOR_BLUE; - break; - case 45: - s->t_attrib.bgcol = QEMU_COLOR_MAGENTA; - break; - case 46: - s->t_attrib.bgcol = QEMU_COLOR_CYAN; - break; - case 47: - s->t_attrib.bgcol = QEMU_COLOR_WHITE; - break; - } - } -} - -static void console_clear_xy(QemuConsole *s, int x, int y) -{ - int y1 = (s->y_base + y) % s->total_height; - TextCell *c = &s->cells[y1 * s->width + x]; - c->ch = ' '; - c->t_attrib = s->t_attrib_default; - update_xy(s, x, y); -} - -static void console_put_one(QemuConsole *s, int ch) -{ - TextCell *c; - int y1; - if (s->x >= s->width) { - /* line wrap */ - s->x = 0; - console_put_lf(s); - } - y1 = (s->y_base + s->y) % s->total_height; - c = &s->cells[y1 * s->width + s->x]; - c->ch = ch; - c->t_attrib = s->t_attrib; - update_xy(s, s->x, s->y); - s->x++; -} - -static void console_respond_str(QemuConsole *s, const char *buf) -{ - while (*buf) { - console_put_one(s, *buf); - buf++; - } -} - -/* set cursor, checking bounds */ -static void set_cursor(QemuConsole *s, int x, int y) -{ - if (x < 0) { - x = 0; - } - if (y < 0) { - y = 0; - } - if (y >= s->height) { - y = s->height - 1; - } - if (x >= s->width) { - x = s->width - 1; - } - - s->x = x; - s->y = y; -} - -static void console_putchar(QemuConsole *s, int ch) -{ - int i; - int x, y; - char response[40]; - - switch(s->state) { - case TTY_STATE_NORM: - switch(ch) { - case '\r': /* carriage return */ - s->x = 0; - break; - case '\n': /* newline */ - console_put_lf(s); - break; - case '\b': /* backspace */ - if (s->x > 0) - s->x--; - break; - case '\t': /* tabspace */ - if (s->x + (8 - (s->x % 8)) > s->width) { - s->x = 0; - console_put_lf(s); - } else { - s->x = s->x + (8 - (s->x % 8)); - } - break; - case '\a': /* alert aka. bell */ - /* TODO: has to be implemented */ - break; - case 14: - /* SI (shift in), character set 0 (ignored) */ - break; - case 15: - /* SO (shift out), character set 1 (ignored) */ - break; - case 27: /* esc (introducing an escape sequence) */ - s->state = TTY_STATE_ESC; - break; - default: - console_put_one(s, ch); - break; - } - break; - case TTY_STATE_ESC: /* check if it is a terminal escape sequence */ - if (ch == '[') { - for(i=0;i<MAX_ESC_PARAMS;i++) - s->esc_params[i] = 0; - s->nb_esc_params = 0; - s->state = TTY_STATE_CSI; - } else { - s->state = TTY_STATE_NORM; - } - break; - case TTY_STATE_CSI: /* handle escape sequence parameters */ - if (ch >= '0' && ch <= '9') { - if (s->nb_esc_params < MAX_ESC_PARAMS) { - int *param = &s->esc_params[s->nb_esc_params]; - int digit = (ch - '0'); - - *param = (*param <= (INT_MAX - digit) / 10) ? - *param * 10 + digit : INT_MAX; - } - } else { - if (s->nb_esc_params < MAX_ESC_PARAMS) - s->nb_esc_params++; - if (ch == ';') - break; - trace_console_putchar_csi(s->esc_params[0], s->esc_params[1], - ch, s->nb_esc_params); - s->state = TTY_STATE_NORM; - switch(ch) { - case 'A': - /* move cursor up */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } - set_cursor(s, s->x, s->y - s->esc_params[0]); - break; - case 'B': - /* move cursor down */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } - set_cursor(s, s->x, s->y + s->esc_params[0]); - break; - case 'C': - /* move cursor right */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } - set_cursor(s, s->x + s->esc_params[0], s->y); - break; - case 'D': - /* move cursor left */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } - set_cursor(s, s->x - s->esc_params[0], s->y); - break; - case 'G': - /* move cursor to column */ - set_cursor(s, s->esc_params[0] - 1, s->y); - break; - case 'f': - case 'H': - /* move cursor to row, column */ - set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1); - break; - case 'J': - switch (s->esc_params[0]) { - case 0: - /* clear to end of screen */ - for (y = s->y; y < s->height; y++) { - for (x = 0; x < s->width; x++) { - if (y == s->y && x < s->x) { - continue; - } - console_clear_xy(s, x, y); - } - } - break; - case 1: - /* clear from beginning of screen */ - for (y = 0; y <= s->y; y++) { - for (x = 0; x < s->width; x++) { - if (y == s->y && x > s->x) { - break; - } - console_clear_xy(s, x, y); - } - } - break; - case 2: - /* clear entire screen */ - for (y = 0; y <= s->height; y++) { - for (x = 0; x < s->width; x++) { - console_clear_xy(s, x, y); - } - } - break; - } - break; - case 'K': - switch (s->esc_params[0]) { - case 0: - /* clear to eol */ - for(x = s->x; x < s->width; x++) { - console_clear_xy(s, x, s->y); - } - break; - case 1: - /* clear from beginning of line */ - for (x = 0; x <= s->x; x++) { - console_clear_xy(s, x, s->y); - } - break; - case 2: - /* clear entire line */ - for(x = 0; x < s->width; x++) { - console_clear_xy(s, x, s->y); - } - break; - } - break; - case 'm': - console_handle_escape(s); - break; - case 'n': - switch (s->esc_params[0]) { - case 5: - /* report console status (always succeed)*/ - console_respond_str(s, "\033[0n"); - break; - case 6: - /* report cursor position */ - sprintf(response, "\033[%d;%dR", - (s->y_base + s->y) % s->total_height + 1, - s->x + 1); - console_respond_str(s, response); - break; - } - break; - case 's': - /* save cursor position */ - s->x_saved = s->x; - s->y_saved = s->y; - break; - case 'u': - /* restore cursor position */ - s->x = s->x_saved; - s->y = s->y_saved; - break; - default: - trace_console_putchar_unhandled(ch); - break; - } - break; - } - } -} - -void console_select(unsigned int index) -{ - DisplayChangeListener *dcl; - QemuConsole *s; - - trace_console_select(index); - s = qemu_console_lookup_by_index(index); - if (s) { - DisplayState *ds = s->ds; - - active_console = s; - if (ds->have_gfx) { - QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->con != NULL) { - continue; - } - if (dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, s->surface); - } - } - dpy_gfx_update(s, 0, 0, surface_width(s->surface), - surface_height(s->surface)); - } - if (ds->have_text) { - dpy_text_resize(s, s->width, s->height); - } - text_console_update_cursor(NULL); - } -} - -static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) -{ - QemuConsole *s = chr->opaque; - int i; - - s->update_x0 = s->width * FONT_WIDTH; - s->update_y0 = s->height * FONT_HEIGHT; - s->update_x1 = 0; - s->update_y1 = 0; - console_show_cursor(s, 0); - for(i = 0; i < len; i++) { - console_putchar(s, buf[i]); - } - console_show_cursor(s, 1); - if (s->ds->have_gfx && s->update_x0 < s->update_x1) { - dpy_gfx_update(s, s->update_x0, s->update_y0, - s->update_x1 - s->update_x0, - s->update_y1 - s->update_y0); - } - return len; -} - -static void kbd_send_chars(void *opaque) -{ - QemuConsole *s = opaque; - int len; - uint8_t buf[16]; - - len = qemu_chr_be_can_write(s->chr); - if (len > s->out_fifo.count) - len = s->out_fifo.count; - if (len > 0) { - if (len > sizeof(buf)) - len = sizeof(buf); - qemu_fifo_read(&s->out_fifo, buf, len); - qemu_chr_be_write(s->chr, buf, len); - } - /* characters are pending: we send them a bit later (XXX: - horrible, should change char device API) */ - if (s->out_fifo.count > 0) { - timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1); - } -} - -/* called when an ascii key is pressed */ -void kbd_put_keysym_console(QemuConsole *s, int keysym) -{ - uint8_t buf[16], *q; - int c; - - if (!s || (s->console_type == GRAPHIC_CONSOLE)) - return; - - switch(keysym) { - case QEMU_KEY_CTRL_UP: - console_scroll(s, -1); - break; - case QEMU_KEY_CTRL_DOWN: - console_scroll(s, 1); - break; - case QEMU_KEY_CTRL_PAGEUP: - console_scroll(s, -10); - break; - case QEMU_KEY_CTRL_PAGEDOWN: - console_scroll(s, 10); - break; - default: - /* convert the QEMU keysym to VT100 key string */ - q = buf; - if (keysym >= 0xe100 && keysym <= 0xe11f) { - *q++ = '\033'; - *q++ = '['; - c = keysym - 0xe100; - if (c >= 10) - *q++ = '0' + (c / 10); - *q++ = '0' + (c % 10); - *q++ = '~'; - } else if (keysym >= 0xe120 && keysym <= 0xe17f) { - *q++ = '\033'; - *q++ = '['; - *q++ = keysym & 0xff; - } else if (s->echo && (keysym == '\r' || keysym == '\n')) { - console_puts(s->chr, (const uint8_t *) "\r", 1); - *q++ = '\n'; - } else { - *q++ = keysym; - } - if (s->echo) { - console_puts(s->chr, buf, q - buf); - } - if (s->chr->chr_read) { - qemu_fifo_write(&s->out_fifo, buf, q - buf); - kbd_send_chars(s); - } - break; - } -} - -static const int qcode_to_keysym[Q_KEY_CODE__MAX] = { - [Q_KEY_CODE_UP] = QEMU_KEY_UP, - [Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN, - [Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT, - [Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT, - [Q_KEY_CODE_HOME] = QEMU_KEY_HOME, - [Q_KEY_CODE_END] = QEMU_KEY_END, - [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP, - [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN, - [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE, -}; - -bool kbd_put_qcode_console(QemuConsole *s, int qcode) -{ - int keysym; - - keysym = qcode_to_keysym[qcode]; - if (keysym == 0) { - return false; - } - kbd_put_keysym_console(s, keysym); - return true; -} - -void kbd_put_string_console(QemuConsole *s, const char *str, int len) -{ - int i; - - for (i = 0; i < len && str[i]; i++) { - kbd_put_keysym_console(s, str[i]); - } -} - -void kbd_put_keysym(int keysym) -{ - kbd_put_keysym_console(active_console, keysym); -} - -static void text_console_invalidate(void *opaque) -{ - QemuConsole *s = (QemuConsole *) opaque; - - if (s->ds->have_text && s->console_type == TEXT_CONSOLE) { - text_console_resize(s); - } - console_refresh(s); -} - -static void text_console_update(void *opaque, console_ch_t *chardata) -{ - QemuConsole *s = (QemuConsole *) opaque; - int i, j, src; - - if (s->text_x[0] <= s->text_x[1]) { - src = (s->y_base + s->text_y[0]) * s->width; - chardata += s->text_y[0] * s->width; - for (i = s->text_y[0]; i <= s->text_y[1]; i ++) - for (j = 0; j < s->width; j++, src++) { - console_write_ch(chardata ++, - ATTR2CHTYPE(s->cells[src].ch, - s->cells[src].t_attrib.fgcol, - s->cells[src].t_attrib.bgcol, - s->cells[src].t_attrib.bold)); - } - dpy_text_update(s, s->text_x[0], s->text_y[0], - s->text_x[1] - s->text_x[0], i - s->text_y[0]); - s->text_x[0] = s->width; - s->text_y[0] = s->height; - s->text_x[1] = 0; - s->text_y[1] = 0; - } - if (s->cursor_invalidate) { - dpy_text_cursor(s, s->x, s->y); - s->cursor_invalidate = 0; - } -} - -static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, - uint32_t head) -{ - Object *obj; - QemuConsole *s; - int i; - - obj = object_new(TYPE_QEMU_CONSOLE); - s = QEMU_CONSOLE(obj); - s->head = head; - object_property_add_link(obj, "device", TYPE_DEVICE, - (Object **)&s->device, - object_property_allow_set_link, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - object_property_add_uint32_ptr(obj, "head", - &s->head, &error_abort); - - if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && - (console_type == GRAPHIC_CONSOLE))) { - active_console = s; - } - s->ds = ds; - s->console_type = console_type; - - consoles = g_realloc(consoles, sizeof(*consoles) * (nb_consoles+1)); - if (console_type != GRAPHIC_CONSOLE) { - s->index = nb_consoles; - consoles[nb_consoles++] = s; - } else { - /* HACK: Put graphical consoles before text consoles. */ - for (i = nb_consoles; i > 0; i--) { - if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE) - break; - consoles[i] = consoles[i - 1]; - consoles[i]->index = i; - } - s->index = i; - consoles[i] = s; - nb_consoles++; - } - return s; -} - -static void qemu_alloc_display(DisplaySurface *surface, int width, int height) -{ - qemu_pixman_image_unref(surface->image); - surface->image = NULL; - - surface->format = PIXMAN_x8r8g8b8; - surface->image = pixman_image_create_bits(surface->format, - width, height, - NULL, width * 4); - assert(surface->image != NULL); - - surface->flags = QEMU_ALLOCATED_FLAG; -} - -DisplaySurface *qemu_create_displaysurface(int width, int height) -{ - DisplaySurface *surface = g_new0(DisplaySurface, 1); - - trace_displaysurface_create(surface, width, height); - qemu_alloc_display(surface, width, height); - return surface; -} - -DisplaySurface *qemu_create_displaysurface_from(int width, int height, - pixman_format_code_t format, - int linesize, uint8_t *data) -{ - DisplaySurface *surface = g_new0(DisplaySurface, 1); - - trace_displaysurface_create_from(surface, width, height, format); - surface->format = format; - surface->image = pixman_image_create_bits(surface->format, - width, height, - (void *)data, linesize); - assert(surface->image != NULL); - - return surface; -} - -DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image) -{ - DisplaySurface *surface = g_new0(DisplaySurface, 1); - - trace_displaysurface_create_pixman(surface); - surface->format = pixman_image_get_format(image); - surface->image = pixman_image_ref(image); - - return surface; -} - -static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image, - void *unused) -{ - void *data = pixman_image_get_data(image); - uint32_t size = pixman_image_get_stride(image) * - pixman_image_get_height(image); - cpu_physical_memory_unmap(data, size, 0, 0); -} - -DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height, - pixman_format_code_t format, - int linesize, uint64_t addr) -{ - DisplaySurface *surface; - hwaddr size; - void *data; - - if (linesize == 0) { - linesize = width * PIXMAN_FORMAT_BPP(format) / 8; - } - - size = (hwaddr)linesize * height; - data = cpu_physical_memory_map(addr, &size, 0); - if (size != (hwaddr)linesize * height) { - cpu_physical_memory_unmap(data, size, 0, 0); - return NULL; - } - - surface = qemu_create_displaysurface_from - (width, height, format, linesize, data); - pixman_image_set_destroy_function - (surface->image, qemu_unmap_displaysurface_guestmem, NULL); - - return surface; -} - -static DisplaySurface *qemu_create_message_surface(int w, int h, - const char *msg) -{ - DisplaySurface *surface = qemu_create_displaysurface(w, h); - pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK]; - pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE]; - pixman_image_t *glyph; - int len, x, y, i; - - len = strlen(msg); - x = (w / FONT_WIDTH - len) / 2; - y = (h / FONT_HEIGHT - 1) / 2; - for (i = 0; i < len; i++) { - glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]); - qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg, - x+i, y, FONT_WIDTH, FONT_HEIGHT); - qemu_pixman_image_unref(glyph); - } - return surface; -} - -void qemu_free_displaysurface(DisplaySurface *surface) -{ - if (surface == NULL) { - return; - } - trace_displaysurface_free(surface); - qemu_pixman_image_unref(surface->image); - g_free(surface); -} - -bool console_has_gl(QemuConsole *con) -{ - return con->gl != NULL; -} - -void register_displaychangelistener(DisplayChangeListener *dcl) -{ - static const char nodev[] = - "This VM has no graphic display device."; - static DisplaySurface *dummy; - QemuConsole *con; - - if (dcl->ops->dpy_gl_ctx_create) { - /* display has opengl support */ - assert(dcl->con); - if (dcl->con->gl) { - fprintf(stderr, "can't register two opengl displays (%s, %s)\n", - dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name); - exit(1); - } - dcl->con->gl = dcl; - } - - trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); - dcl->ds = get_alloc_displaystate(); - QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next); - gui_setup_refresh(dcl->ds); - if (dcl->con) { - dcl->con->dcls++; - con = dcl->con; - } else { - con = active_console; - } - if (dcl->ops->dpy_gfx_switch) { - if (con) { - dcl->ops->dpy_gfx_switch(dcl, con->surface); - } else { - if (!dummy) { - dummy = qemu_create_message_surface(640, 480, nodev); - } - dcl->ops->dpy_gfx_switch(dcl, dummy); - } - } - text_console_update_cursor(NULL); -} - -void update_displaychangelistener(DisplayChangeListener *dcl, - uint64_t interval) -{ - DisplayState *ds = dcl->ds; - - dcl->update_interval = interval; - if (!ds->refreshing && ds->update_interval > interval) { - timer_mod(ds->gui_timer, ds->last_update + interval); - } -} - -void unregister_displaychangelistener(DisplayChangeListener *dcl) -{ - DisplayState *ds = dcl->ds; - trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name); - if (dcl->con) { - dcl->con->dcls--; - } - QLIST_REMOVE(dcl, next); - gui_setup_refresh(ds); -} - -static void dpy_set_ui_info_timer(void *opaque) -{ - QemuConsole *con = opaque; - - con->hw_ops->ui_info(con->hw, con->head, &con->ui_info); -} - -bool dpy_ui_info_supported(QemuConsole *con) -{ - return con->hw_ops->ui_info != NULL; -} - -int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info) -{ - assert(con != NULL); - con->ui_info = *info; - if (!dpy_ui_info_supported(con)) { - return -1; - } - - /* - * Typically we get a flood of these as the user resizes the window. - * Wait until the dust has settled (one second without updates), then - * go notify the guest. - */ - timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); - return 0; -} - -void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - int width = w; - int height = h; - - if (con->surface) { - width = surface_width(con->surface); - height = surface_height(con->surface); - } - x = MAX(x, 0); - y = MAX(y, 0); - x = MIN(x, width); - y = MIN(y, height); - w = MIN(w, width - x); - h = MIN(h, height - y); - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_gfx_update) { - dcl->ops->dpy_gfx_update(dcl, x, y, w, h); - } - } -} - -void dpy_gfx_replace_surface(QemuConsole *con, - DisplaySurface *surface) -{ - DisplayState *s = con->ds; - DisplaySurface *old_surface = con->surface; - DisplayChangeListener *dcl; - - con->surface = surface; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, surface); - } - } - qemu_free_displaysurface(old_surface); -} - -bool dpy_gfx_check_format(QemuConsole *con, - pixman_format_code_t format) -{ - DisplayChangeListener *dcl; - DisplayState *s = con->ds; - - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->con && dcl->con != con) { - /* dcl bound to another console -> skip */ - continue; - } - if (dcl->ops->dpy_gfx_check_format) { - if (!dcl->ops->dpy_gfx_check_format(dcl, format)) { - return false; - } - } else { - /* default is to whitelist native 32 bpp only */ - if (format != qemu_default_pixman_format(32, true)) { - return false; - } - } - } - return true; -} - -static void dpy_refresh(DisplayState *s) -{ - DisplayChangeListener *dcl; - - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->ops->dpy_refresh) { - dcl->ops->dpy_refresh(dcl); - } - } -} - -void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_gfx_copy) { - dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h); - } else { /* TODO */ - dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h); - } - } -} - -void dpy_text_cursor(QemuConsole *con, int x, int y) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_text_cursor) { - dcl->ops->dpy_text_cursor(dcl, x, y); - } - } -} - -void dpy_text_update(QemuConsole *con, int x, int y, int w, int h) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_text_update) { - dcl->ops->dpy_text_update(dcl, x, y, w, h); - } - } -} - -void dpy_text_resize(QemuConsole *con, int w, int h) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_text_resize) { - dcl->ops->dpy_text_resize(dcl, w, h); - } - } -} - -void dpy_mouse_set(QemuConsole *con, int x, int y, int on) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_mouse_set) { - dcl->ops->dpy_mouse_set(dcl, x, y, on); - } - } -} - -void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_cursor_define) { - dcl->ops->dpy_cursor_define(dcl, cursor); - } - } -} - -bool dpy_cursor_define_supported(QemuConsole *con) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->ops->dpy_cursor_define) { - return true; - } - } - return false; -} - -QEMUGLContext dpy_gl_ctx_create(QemuConsole *con, - struct QEMUGLParams *qparams) -{ - assert(con->gl); - return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams); -} - -void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx) -{ - assert(con->gl); - con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx); -} - -int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx) -{ - assert(con->gl); - return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx); -} - -QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con) -{ - assert(con->gl); - return con->gl->ops->dpy_gl_ctx_get_current(con->gl); -} - -void dpy_gl_scanout(QemuConsole *con, - uint32_t backing_id, bool backing_y_0_top, - uint32_t x, uint32_t y, uint32_t width, uint32_t height) -{ - assert(con->gl); - con->gl->ops->dpy_gl_scanout(con->gl, backing_id, - backing_y_0_top, - x, y, width, height); -} - -void dpy_gl_update(QemuConsole *con, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - assert(con->gl); - con->gl->ops->dpy_gl_update(con->gl, x, y, w, h); -} - -/***********************************************************/ -/* register display */ - -/* console.c internal use only */ -static DisplayState *get_alloc_displaystate(void) -{ - if (!display_state) { - display_state = g_new0(DisplayState, 1); - cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, - text_console_update_cursor, NULL); - } - return display_state; -} - -/* - * Called by main(), after creating QemuConsoles - * and before initializing ui (sdl/vnc/...). - */ -DisplayState *init_displaystate(void) -{ - gchar *name; - int i; - - get_alloc_displaystate(); - for (i = 0; i < nb_consoles; i++) { - if (consoles[i]->console_type != GRAPHIC_CONSOLE && - consoles[i]->ds == NULL) { - text_console_do_init(consoles[i]->chr, display_state); - } - - /* Hook up into the qom tree here (not in new_console()), once - * all QemuConsoles are created and the order / numbering - * doesn't change any more */ - name = g_strdup_printf("console[%d]", i); - object_property_add_child(container_get(object_get_root(), "/backend"), - name, OBJECT(consoles[i]), &error_abort); - g_free(name); - } - - return display_state; -} - -void graphic_console_set_hwops(QemuConsole *con, - const GraphicHwOps *hw_ops, - void *opaque) -{ - con->hw_ops = hw_ops; - con->hw = opaque; -} - -QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, - const GraphicHwOps *hw_ops, - void *opaque) -{ - static const char noinit[] = - "Guest has not initialized the display (yet)."; - int width = 640; - int height = 480; - QemuConsole *s; - DisplayState *ds; - - ds = get_alloc_displaystate(); - trace_console_gfx_new(); - s = new_console(ds, GRAPHIC_CONSOLE, head); - s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s); - graphic_console_set_hwops(s, hw_ops, opaque); - if (dev) { - object_property_set_link(OBJECT(s), OBJECT(dev), "device", - &error_abort); - } - - s->surface = qemu_create_message_surface(width, height, noinit); - return s; -} - -QemuConsole *qemu_console_lookup_by_index(unsigned int index) -{ - if (index >= nb_consoles) { - return NULL; - } - return consoles[index]; -} - -QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head) -{ - Object *obj; - uint32_t h; - int i; - - for (i = 0; i < nb_consoles; i++) { - if (!consoles[i]) { - continue; - } - obj = object_property_get_link(OBJECT(consoles[i]), - "device", &error_abort); - if (DEVICE(obj) != dev) { - continue; - } - h = object_property_get_int(OBJECT(consoles[i]), - "head", &error_abort); - if (h != head) { - continue; - } - return consoles[i]; - } - return NULL; -} - -QemuConsole *qemu_console_lookup_by_device_name(const char *device_id, - uint32_t head, Error **errp) -{ - DeviceState *dev; - QemuConsole *con; - - dev = qdev_find_recursive(sysbus_get_default(), device_id); - if (dev == NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device_id); - return NULL; - } - - con = qemu_console_lookup_by_device(dev, head); - if (con == NULL) { - error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole", - device_id, head); - return NULL; - } - - return con; -} - -bool qemu_console_is_visible(QemuConsole *con) -{ - return (con == active_console) || (con->dcls > 0); -} - -bool qemu_console_is_graphic(QemuConsole *con) -{ - if (con == NULL) { - con = active_console; - } - return con && (con->console_type == GRAPHIC_CONSOLE); -} - -bool qemu_console_is_fixedsize(QemuConsole *con) -{ - if (con == NULL) { - con = active_console; - } - return con && (con->console_type != TEXT_CONSOLE); -} - -char *qemu_console_get_label(QemuConsole *con) -{ - if (con->console_type == GRAPHIC_CONSOLE) { - if (con->device) { - return g_strdup(object_get_typename(con->device)); - } - return g_strdup("VGA"); - } else { - if (con->chr && con->chr->label) { - return g_strdup(con->chr->label); - } - return g_strdup_printf("vc%d", con->index); - } -} - -int qemu_console_get_index(QemuConsole *con) -{ - if (con == NULL) { - con = active_console; - } - return con ? con->index : -1; -} - -uint32_t qemu_console_get_head(QemuConsole *con) -{ - if (con == NULL) { - con = active_console; - } - return con ? con->head : -1; -} - -QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con) -{ - assert(con != NULL); - return &con->ui_info; -} - -int qemu_console_get_width(QemuConsole *con, int fallback) -{ - if (con == NULL) { - con = active_console; - } - return con ? surface_width(con->surface) : fallback; -} - -int qemu_console_get_height(QemuConsole *con, int fallback) -{ - if (con == NULL) { - con = active_console; - } - return con ? surface_height(con->surface) : fallback; -} - -static void text_console_set_echo(CharDriverState *chr, bool echo) -{ - QemuConsole *s = chr->opaque; - - s->echo = echo; -} - -static void text_console_update_cursor_timer(void) -{ - timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - + CONSOLE_CURSOR_PERIOD / 2); -} - -static void text_console_update_cursor(void *opaque) -{ - QemuConsole *s; - int i, count = 0; - - cursor_visible_phase = !cursor_visible_phase; - - for (i = 0; i < nb_consoles; i++) { - s = consoles[i]; - if (qemu_console_is_graphic(s) || - !qemu_console_is_visible(s)) { - continue; - } - count++; - graphic_hw_invalidate(s); - } - - if (count) { - text_console_update_cursor_timer(); - } -} - -static const GraphicHwOps text_console_ops = { - .invalidate = text_console_invalidate, - .text_update = text_console_update, -}; - -static void text_console_do_init(CharDriverState *chr, DisplayState *ds) -{ - QemuConsole *s; - int g_width = 80 * FONT_WIDTH; - int g_height = 24 * FONT_HEIGHT; - - s = chr->opaque; - - chr->chr_write = console_puts; - - s->out_fifo.buf = s->out_fifo_buf; - s->out_fifo.buf_size = sizeof(s->out_fifo_buf); - s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s); - s->ds = ds; - - s->y_displayed = 0; - s->y_base = 0; - s->total_height = DEFAULT_BACKSCROLL; - s->x = 0; - s->y = 0; - if (!s->surface) { - if (active_console && active_console->surface) { - g_width = surface_width(active_console->surface); - g_height = surface_height(active_console->surface); - } - s->surface = qemu_create_displaysurface(g_width, g_height); - } - - s->hw_ops = &text_console_ops; - s->hw = s; - - /* Set text attribute defaults */ - s->t_attrib_default.bold = 0; - s->t_attrib_default.uline = 0; - s->t_attrib_default.blink = 0; - s->t_attrib_default.invers = 0; - s->t_attrib_default.unvisible = 0; - s->t_attrib_default.fgcol = QEMU_COLOR_WHITE; - s->t_attrib_default.bgcol = QEMU_COLOR_BLACK; - /* set current text attributes to default */ - s->t_attrib = s->t_attrib_default; - text_console_resize(s); - - if (chr->label) { - char msg[128]; - int len; - - s->t_attrib.bgcol = QEMU_COLOR_BLUE; - len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); - console_puts(chr, (uint8_t*)msg, len); - s->t_attrib = s->t_attrib_default; - } - - qemu_chr_be_generic_open(chr); - if (chr->init) - chr->init(chr); -} - -static CharDriverState *text_console_init(ChardevVC *vc, Error **errp) -{ - ChardevCommon *common = qapi_ChardevVC_base(vc); - CharDriverState *chr; - QemuConsole *s; - unsigned width = 0; - unsigned height = 0; - - chr = qemu_chr_alloc(common, errp); - if (!chr) { - return NULL; - } - - if (vc->has_width) { - width = vc->width; - } else if (vc->has_cols) { - width = vc->cols * FONT_WIDTH; - } - - if (vc->has_height) { - height = vc->height; - } else if (vc->has_rows) { - height = vc->rows * FONT_HEIGHT; - } - - trace_console_txt_new(width, height); - if (width == 0 || height == 0) { - s = new_console(NULL, TEXT_CONSOLE, 0); - } else { - s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0); - s->surface = qemu_create_displaysurface(width, height); - } - - if (!s) { - g_free(chr); - error_setg(errp, "cannot create text console"); - return NULL; - } - - s->chr = chr; - chr->opaque = s; - chr->chr_set_echo = text_console_set_echo; - /* console/chardev init sometimes completes elsewhere in a 2nd - * stage, so defer OPENED events until they are fully initialized - */ - chr->explicit_be_open = true; - - if (display_state) { - text_console_do_init(chr, display_state); - } - return chr; -} - -static VcHandler *vc_handler = text_console_init; - -static CharDriverState *vc_init(const char *id, ChardevBackend *backend, - ChardevReturn *ret, Error **errp) -{ - return vc_handler(backend->u.vc.data, errp); -} - -void register_vc_handler(VcHandler *handler) -{ - vc_handler = handler; -} - -void qemu_console_resize(QemuConsole *s, int width, int height) -{ - DisplaySurface *surface; - - assert(s->console_type == GRAPHIC_CONSOLE); - surface = qemu_create_displaysurface(width, height); - dpy_gfx_replace_surface(s, surface); -} - -void qemu_console_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - assert(con->console_type == GRAPHIC_CONSOLE); - dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h); -} - -DisplaySurface *qemu_console_surface(QemuConsole *console) -{ - return console->surface; -} - -PixelFormat qemu_default_pixelformat(int bpp) -{ - pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true); - PixelFormat pf = qemu_pixelformat_from_pixman(fmt); - return pf; -} - -static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, - Error **errp) -{ - int val; - ChardevVC *vc; - - vc = backend->u.vc.data = g_new0(ChardevVC, 1); - qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc)); - - val = qemu_opt_get_number(opts, "width", 0); - if (val != 0) { - vc->has_width = true; - vc->width = val; - } - - val = qemu_opt_get_number(opts, "height", 0); - if (val != 0) { - vc->has_height = true; - vc->height = val; - } - - val = qemu_opt_get_number(opts, "cols", 0); - if (val != 0) { - vc->has_cols = true; - vc->cols = val; - } - - val = qemu_opt_get_number(opts, "rows", 0); - if (val != 0) { - vc->has_rows = true; - vc->rows = val; - } -} - -static const TypeInfo qemu_console_info = { - .name = TYPE_QEMU_CONSOLE, - .parent = TYPE_OBJECT, - .instance_size = sizeof(QemuConsole), - .class_size = sizeof(QemuConsoleClass), -}; - - -static void register_types(void) -{ - type_register_static(&qemu_console_info); - register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc, - vc_init); -} - -type_init(register_types); diff --git a/qemu/ui/curses.c b/qemu/ui/curses.c deleted file mode 100644 index b47558956..000000000 --- a/qemu/ui/curses.c +++ /dev/null @@ -1,447 +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 "qemu/osdep.h" -#include <curses.h> - -#ifndef _WIN32 -#include <sys/ioctl.h> -#include <termios.h> -#endif - -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" - -#define FONT_HEIGHT 16 -#define FONT_WIDTH 8 - -static DisplayChangeListener *dcl; -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; - -chtype vga_to_curses[256]; - -static void curses_update(DisplayChangeListener *dcl, - 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 (qemu_console_is_fixedsize(NULL)) { - 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(DisplayChangeListener *dcl, - int width, int height) -{ - if (width == gwidth && height == gheight) { - return; - } - - gwidth = width; - gheight = height; - - curses_calc_pad(); -} - -#if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE) -static volatile sig_atomic_t got_sigwinch; -static void curses_winch_check(void) -{ - struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; /* unused */ - unsigned short ws_ypixel; /* unused */ - } ws; - - if (!got_sigwinch) { - return; - } - got_sigwinch = false; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1) { - return; - } - - resize_term(ws.ws_row, ws.ws_col); - invalidate = 1; -} - -static void curses_winch_handler(int signum) -{ - got_sigwinch = true; -} - -static void curses_winch_init(void) -{ - struct sigaction old, winch = { - .sa_handler = curses_winch_handler, - }; - sigaction(SIGWINCH, &winch, &old); -} -#else -static void curses_winch_check(void) {} -static void curses_winch_init(void) {} -#endif - -static void curses_cursor_position(DisplayChangeListener *dcl, - 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 (!qemu_console_is_graphic(NULL)) { - 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(DisplayChangeListener *dcl) -{ - int chr, nextchr, keysym, keycode, keycode_alt; - - curses_winch_check(); - - if (invalidate) { - clear(); - refresh(); - curses_calc_pad(); - graphic_hw_invalidate(NULL); - invalidate = 0; - } - - graphic_hw_text_update(NULL, 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(dcl, 0, 0, width, 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 + '@'; - if (keysym >= 'A' && keysym <= 'Z') - keysym += 'a' - 'A'; - keysym |= 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 (qemu_console_is_graphic(NULL)) { - /* since terminals don't know about key press and release - * events, we need to emit both for each key received */ - if (keycode & SHIFT) { - qemu_input_event_send_key_number(NULL, SHIFT_CODE, true); - qemu_input_event_send_key_delay(0); - } - if (keycode & CNTRL) { - qemu_input_event_send_key_number(NULL, CNTRL_CODE, true); - qemu_input_event_send_key_delay(0); - } - if (keycode & ALT) { - qemu_input_event_send_key_number(NULL, ALT_CODE, true); - qemu_input_event_send_key_delay(0); - } - if (keycode & ALTGR) { - qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); - qemu_input_event_send_key_delay(0); - } - - qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true); - qemu_input_event_send_key_delay(0); - qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false); - qemu_input_event_send_key_delay(0); - - if (keycode & ALTGR) { - qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); - qemu_input_event_send_key_delay(0); - } - if (keycode & ALT) { - qemu_input_event_send_key_number(NULL, ALT_CODE, false); - qemu_input_event_send_key_delay(0); - } - if (keycode & CNTRL) { - qemu_input_event_send_key_number(NULL, CNTRL_CODE, false); - qemu_input_event_send_key_delay(0); - } - if (keycode & SHIFT) { - qemu_input_event_send_key_number(NULL, SHIFT_CODE, false); - qemu_input_event_send_key_delay(0); - } - } 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] = { - [QEMU_COLOR_BLACK] = COLOR_BLACK, - [QEMU_COLOR_BLUE] = COLOR_BLUE, - [QEMU_COLOR_GREEN] = COLOR_GREEN, - [QEMU_COLOR_CYAN] = COLOR_CYAN, - [QEMU_COLOR_RED] = COLOR_RED, - [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA, - [QEMU_COLOR_YELLOW] = COLOR_YELLOW, - [QEMU_COLOR_WHITE] = 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); - - /* Make color pair to match color format (3bits bg:3bits fg) */ - for (i = 0; i < 64; i++) { - init_pair(i, colour_default[i & 7], colour_default[i >> 3]); - } - /* Set default color for more than 64 for safety. */ - for (i = 64; i < COLOR_PAIRS; i++) { - init_pair(i, COLOR_WHITE, COLOR_BLACK); - } - - /* - * Setup mapping for vga to curses line graphics. - * FIXME: for better font, have to use ncursesw and setlocale() - */ -#if 0 - /* FIXME: map from where? */ - ACS_S1; - ACS_S3; - ACS_S7; - ACS_S9; -#endif - /* ACS_* is not constant. So, we can't initialize statically. */ - vga_to_curses['\0'] = ' '; - vga_to_curses[0x04] = ACS_DIAMOND; - vga_to_curses[0x0a] = ACS_RARROW; - vga_to_curses[0x0b] = ACS_LARROW; - vga_to_curses[0x18] = ACS_UARROW; - vga_to_curses[0x19] = ACS_DARROW; - vga_to_curses[0x9c] = ACS_STERLING; - vga_to_curses[0xb0] = ACS_BOARD; - vga_to_curses[0xb1] = ACS_CKBOARD; - vga_to_curses[0xb3] = ACS_VLINE; - vga_to_curses[0xb4] = ACS_RTEE; - vga_to_curses[0xbf] = ACS_URCORNER; - vga_to_curses[0xc0] = ACS_LLCORNER; - vga_to_curses[0xc1] = ACS_BTEE; - vga_to_curses[0xc2] = ACS_TTEE; - vga_to_curses[0xc3] = ACS_LTEE; - vga_to_curses[0xc4] = ACS_HLINE; - vga_to_curses[0xc5] = ACS_PLUS; - vga_to_curses[0xce] = ACS_LANTERN; - vga_to_curses[0xd8] = ACS_NEQUAL; - vga_to_curses[0xd9] = ACS_LRCORNER; - vga_to_curses[0xda] = ACS_ULCORNER; - vga_to_curses[0xdb] = ACS_BLOCK; - vga_to_curses[0xe3] = ACS_PI; - vga_to_curses[0xf1] = ACS_PLMINUS; - vga_to_curses[0xf2] = ACS_GEQUAL; - vga_to_curses[0xf3] = ACS_LEQUAL; - vga_to_curses[0xf8] = ACS_DEGREE; - vga_to_curses[0xfe] = ACS_BULLET; -} - -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); - } -} - -static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "curses", - .dpy_text_update = curses_update, - .dpy_text_resize = curses_resize, - .dpy_refresh = curses_refresh, - .dpy_text_cursor = curses_cursor_position, -}; - -void curses_display_init(DisplayState *ds, int full_screen) -{ -#ifndef _WIN32 - if (!isatty(1)) { - fprintf(stderr, "We need a terminal output\n"); - exit(1); - } -#endif - - curses_setup(); - curses_keyboard_setup(); - atexit(curses_atexit); - - curses_winch_init(); - - dcl = g_new0(DisplayChangeListener, 1); - dcl->ops = &dcl_ops; - register_displaychangelistener(dcl); - - invalidate = 1; -} diff --git a/qemu/ui/curses_keys.h b/qemu/ui/curses_keys.h deleted file mode 100644 index f7467449b..000000000 --- a/qemu/ui/curses_keys.h +++ /dev/null @@ -1,518 +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. - */ - -#ifndef QEMU_CURSES_KEYS_H -#define QEMU_CURSES_KEYS_H 1 - -#include <curses.h> -#include "keymaps.h" - - -#define KEY_MASK SCANCODE_KEYMASK -#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, - [27] = 27, - [KEY_BTAB] = '\t' | KEYSYM_SHIFT, - [KEY_SPREVIOUS] = KEY_PPAGE | KEYSYM_SHIFT, - [KEY_SNEXT] = KEY_NPAGE | 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 */ - - [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ - [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ - - ['!'] = 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 }, -}; - -#endif diff --git a/qemu/ui/cursor.c b/qemu/ui/cursor.c deleted file mode 100644 index a276e01f1..000000000 --- a/qemu/ui/cursor.c +++ /dev/null @@ -1,212 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" - -#include "cursor_hidden.xpm" -#include "cursor_left_ptr.xpm" - -/* for creating built-in cursors */ -static QEMUCursor *cursor_parse_xpm(const char *xpm[]) -{ - QEMUCursor *c; - uint32_t ctab[128]; - unsigned int width, height, colors, chars; - unsigned int line = 0, i, r, g, b, x, y, pixel; - char name[16]; - uint8_t idx; - - /* parse header line: width, height, #colors, #chars */ - if (sscanf(xpm[line], "%u %u %u %u", - &width, &height, &colors, &chars) != 4) { - fprintf(stderr, "%s: header parse error: \"%s\"\n", - __FUNCTION__, xpm[line]); - return NULL; - } - if (chars != 1) { - fprintf(stderr, "%s: chars != 1 not supported\n", __FUNCTION__); - return NULL; - } - line++; - - /* parse color table */ - for (i = 0; i < colors; i++, line++) { - if (sscanf(xpm[line], "%c c %15s", &idx, name) == 2) { - if (sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3) { - ctab[idx] = (0xff << 24) | (b << 16) | (g << 8) | r; - continue; - } - if (strcmp(name, "None") == 0) { - ctab[idx] = 0x00000000; - continue; - } - } - fprintf(stderr, "%s: color parse error: \"%s\"\n", - __FUNCTION__, xpm[line]); - return NULL; - } - - /* parse pixel data */ - c = cursor_alloc(width, height); - for (pixel = 0, y = 0; y < height; y++, line++) { - for (x = 0; x < height; x++, pixel++) { - idx = xpm[line][x]; - c->data[pixel] = ctab[idx]; - } - } - return c; -} - -/* nice for debugging */ -void cursor_print_ascii_art(QEMUCursor *c, const char *prefix) -{ - uint32_t *data = c->data; - int x,y; - - for (y = 0; y < c->height; y++) { - fprintf(stderr, "%s: %2d: |", prefix, y); - for (x = 0; x < c->width; x++, data++) { - if ((*data & 0xff000000) != 0xff000000) { - fprintf(stderr, " "); /* transparent */ - } else if ((*data & 0x00ffffff) == 0x00ffffff) { - fprintf(stderr, "."); /* white */ - } else if ((*data & 0x00ffffff) == 0x00000000) { - fprintf(stderr, "X"); /* black */ - } else { - fprintf(stderr, "o"); /* other */ - } - } - fprintf(stderr, "|\n"); - } -} - -QEMUCursor *cursor_builtin_hidden(void) -{ - QEMUCursor *c; - - c = cursor_parse_xpm(cursor_hidden_xpm); - return c; -} - -QEMUCursor *cursor_builtin_left_ptr(void) -{ - QEMUCursor *c; - - c = cursor_parse_xpm(cursor_left_ptr_xpm); - return c; -} - -QEMUCursor *cursor_alloc(int width, int height) -{ - QEMUCursor *c; - int datasize = width * height * sizeof(uint32_t); - - c = g_malloc0(sizeof(QEMUCursor) + datasize); - c->width = width; - c->height = height; - c->refcount = 1; - return c; -} - -void cursor_get(QEMUCursor *c) -{ - c->refcount++; -} - -void cursor_put(QEMUCursor *c) -{ - if (c == NULL) - return; - c->refcount--; - if (c->refcount) - return; - g_free(c); -} - -int cursor_get_mono_bpl(QEMUCursor *c) -{ - return (c->width + 7) / 8; -} - -void cursor_set_mono(QEMUCursor *c, - uint32_t foreground, uint32_t background, uint8_t *image, - int transparent, uint8_t *mask) -{ - uint32_t *data = c->data; - uint8_t bit; - int x,y,bpl; - - bpl = cursor_get_mono_bpl(c); - for (y = 0; y < c->height; y++) { - bit = 0x80; - for (x = 0; x < c->width; x++, data++) { - if (transparent && mask[x/8] & bit) { - *data = 0x00000000; - } else if (!transparent && !(mask[x/8] & bit)) { - *data = 0x00000000; - } else if (image[x/8] & bit) { - *data = 0xff000000 | foreground; - } else { - *data = 0xff000000 | background; - } - bit >>= 1; - if (bit == 0) { - bit = 0x80; - } - } - mask += bpl; - image += bpl; - } -} - -void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image) -{ - uint32_t *data = c->data; - uint8_t bit; - int x,y,bpl; - - bpl = cursor_get_mono_bpl(c); - memset(image, 0, bpl * c->height); - for (y = 0; y < c->height; y++) { - bit = 0x80; - for (x = 0; x < c->width; x++, data++) { - if (((*data & 0xff000000) == 0xff000000) && - ((*data & 0x00ffffff) == foreground)) { - image[x/8] |= bit; - } - bit >>= 1; - if (bit == 0) { - bit = 0x80; - } - } - image += bpl; - } -} - -void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask) -{ - uint32_t *data = c->data; - uint8_t bit; - int x,y,bpl; - - bpl = cursor_get_mono_bpl(c); - memset(mask, 0, bpl * c->height); - for (y = 0; y < c->height; y++) { - bit = 0x80; - for (x = 0; x < c->width; x++, data++) { - if ((*data & 0xff000000) != 0xff000000) { - if (transparent != 0) { - mask[x/8] |= bit; - } - } else { - if (transparent == 0) { - mask[x/8] |= bit; - } - } - bit >>= 1; - if (bit == 0) { - bit = 0x80; - } - } - mask += bpl; - } -} diff --git a/qemu/ui/cursor_hidden.xpm b/qemu/ui/cursor_hidden.xpm deleted file mode 100644 index 354e7a939..000000000 --- a/qemu/ui/cursor_hidden.xpm +++ /dev/null @@ -1,37 +0,0 @@ -/* XPM */ -static const char *cursor_hidden_xpm[] = { - "32 32 1 1", - " c None", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", -}; diff --git a/qemu/ui/cursor_left_ptr.xpm b/qemu/ui/cursor_left_ptr.xpm deleted file mode 100644 index 6c9ada902..000000000 --- a/qemu/ui/cursor_left_ptr.xpm +++ /dev/null @@ -1,39 +0,0 @@ -/* XPM */ -static const char *cursor_left_ptr_xpm[] = { - "32 32 3 1", - "X c #000000", - ". c #ffffff", - " c None", - "X ", - "XX ", - "X.X ", - "X..X ", - "X...X ", - "X....X ", - "X.....X ", - "X......X ", - "X.......X ", - "X........X ", - "X.....XXXXX ", - "X..X..X ", - "X.X X..X ", - "XX X..X ", - "X X..X ", - " X..X ", - " X..X ", - " X..X ", - " XX ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", -}; diff --git a/qemu/ui/egl-context.c b/qemu/ui/egl-context.c deleted file mode 100644 index 3a02b68d1..000000000 --- a/qemu/ui/egl-context.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/egl-context.h" - -QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl, - QEMUGLParams *params) -{ - EGLContext ctx; - EGLint ctx_att[] = { - EGL_CONTEXT_CLIENT_VERSION, params->major_ver, - EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver, - EGL_NONE - }; - - ctx = eglCreateContext(qemu_egl_display, qemu_egl_config, - eglGetCurrentContext(), ctx_att); - return ctx; -} - -void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) -{ - eglDestroyContext(qemu_egl_display, ctx); -} - -int qemu_egl_make_context_current(DisplayChangeListener *dcl, - QEMUGLContext ctx) -{ - return eglMakeCurrent(qemu_egl_display, - EGL_NO_SURFACE, EGL_NO_SURFACE, ctx); -} - -QEMUGLContext qemu_egl_get_current_context(DisplayChangeListener *dcl) -{ - return eglGetCurrentContext(); -} diff --git a/qemu/ui/egl-helpers.c b/qemu/ui/egl-helpers.c deleted file mode 100644 index 558edfdeb..000000000 --- a/qemu/ui/egl-helpers.c +++ /dev/null @@ -1,269 +0,0 @@ -#include "qemu/osdep.h" -#include <glob.h> -#include <dirent.h> - -#include "ui/egl-helpers.h" - -EGLDisplay *qemu_egl_display; -EGLConfig qemu_egl_config; - -/* ---------------------------------------------------------------------- */ - -static bool egl_gles; -static int egl_debug; - -#define egl_dbg(_x ...) \ - do { \ - if (egl_debug) { \ - fprintf(stderr, "egl: " _x); \ - } \ - } while (0); - -/* ---------------------------------------------------------------------- */ - -#ifdef CONFIG_OPENGL_DMABUF - -int qemu_egl_rn_fd; -struct gbm_device *qemu_egl_rn_gbm_dev; -EGLContext qemu_egl_rn_ctx; - -int qemu_egl_rendernode_open(void) -{ - DIR *dir; - struct dirent *e; - int r, fd; - char *p; - - dir = opendir("/dev/dri"); - if (!dir) { - return -1; - } - - fd = -1; - while ((e = readdir(dir))) { - if (e->d_type != DT_CHR) { - continue; - } - - if (strncmp(e->d_name, "renderD", 7)) { - continue; - } - - r = asprintf(&p, "/dev/dri/%s", e->d_name); - if (r < 0) { - return -1; - } - - r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); - if (r < 0) { - free(p); - continue; - } - fd = r; - free(p); - break; - } - - closedir(dir); - if (fd < 0) { - return -1; - } - return fd; -} - -int egl_rendernode_init(void) -{ - qemu_egl_rn_fd = -1; - - qemu_egl_rn_fd = qemu_egl_rendernode_open(); - if (qemu_egl_rn_fd == -1) { - fprintf(stderr, "egl: no drm render node available\n"); - goto err; - } - - qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd); - if (!qemu_egl_rn_gbm_dev) { - fprintf(stderr, "egl: gbm_create_device failed\n"); - goto err; - } - - qemu_egl_init_dpy((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, false, false); - - if (!epoxy_has_egl_extension(qemu_egl_display, - "EGL_KHR_surfaceless_context")) { - fprintf(stderr, "egl: EGL_KHR_surfaceless_context not supported\n"); - goto err; - } - if (!epoxy_has_egl_extension(qemu_egl_display, - "EGL_MESA_image_dma_buf_export")) { - fprintf(stderr, "egl: EGL_MESA_image_dma_buf_export not supported\n"); - goto err; - } - - qemu_egl_rn_ctx = qemu_egl_init_ctx(); - if (!qemu_egl_rn_ctx) { - fprintf(stderr, "egl: egl_init_ctx failed\n"); - goto err; - } - - return 0; - -err: - if (qemu_egl_rn_gbm_dev) { - gbm_device_destroy(qemu_egl_rn_gbm_dev); - } - if (qemu_egl_rn_fd != -1) { - close(qemu_egl_rn_fd); - } - - return -1; -} - -int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc) -{ - EGLImageKHR image; - EGLint num_planes, fd; - - image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), - EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer)(unsigned long)tex_id, - NULL); - if (!image) { - return -1; - } - - eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, - &num_planes, NULL); - if (num_planes != 1) { - eglDestroyImageKHR(qemu_egl_display, image); - return -1; - } - eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); - eglDestroyImageKHR(qemu_egl_display, image); - - return fd; -} - -#endif /* CONFIG_OPENGL_DMABUF */ - -/* ---------------------------------------------------------------------- */ - -EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win) -{ - EGLSurface esurface; - EGLBoolean b; - - egl_dbg("eglCreateWindowSurface (x11 win id 0x%lx) ...\n", - (unsigned long) win); - esurface = eglCreateWindowSurface(qemu_egl_display, - qemu_egl_config, - (EGLNativeWindowType)win, NULL); - if (esurface == EGL_NO_SURFACE) { - fprintf(stderr, "egl: eglCreateWindowSurface failed\n"); - return NULL; - } - - b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx); - if (b == EGL_FALSE) { - fprintf(stderr, "egl: eglMakeCurrent failed\n"); - return NULL; - } - - return esurface; -} - -/* ---------------------------------------------------------------------- */ - -int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug) -{ - static const EGLint conf_att_gl[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_RED_SIZE, 5, - EGL_GREEN_SIZE, 5, - EGL_BLUE_SIZE, 5, - EGL_ALPHA_SIZE, 0, - EGL_NONE, - }; - static const EGLint conf_att_gles[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 5, - EGL_GREEN_SIZE, 5, - EGL_BLUE_SIZE, 5, - EGL_ALPHA_SIZE, 0, - EGL_NONE, - }; - EGLint major, minor; - EGLBoolean b; - EGLint n; - - if (debug) { - egl_debug = 1; - setenv("EGL_LOG_LEVEL", "debug", true); - setenv("LIBGL_DEBUG", "verbose", true); - } - - egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy); - qemu_egl_display = eglGetDisplay(dpy); - if (qemu_egl_display == EGL_NO_DISPLAY) { - fprintf(stderr, "egl: eglGetDisplay failed\n"); - return -1; - } - - egl_dbg("eglInitialize ...\n"); - b = eglInitialize(qemu_egl_display, &major, &minor); - if (b == EGL_FALSE) { - fprintf(stderr, "egl: eglInitialize failed\n"); - return -1; - } - - egl_dbg("eglBindAPI ...\n"); - b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); - if (b == EGL_FALSE) { - fprintf(stderr, "egl: eglBindAPI failed\n"); - return -1; - } - - egl_dbg("eglChooseConfig ...\n"); - b = eglChooseConfig(qemu_egl_display, - gles ? conf_att_gles : conf_att_gl, - &qemu_egl_config, 1, &n); - if (b == EGL_FALSE || n != 1) { - fprintf(stderr, "egl: eglChooseConfig failed\n"); - return -1; - } - - egl_gles = gles; - return 0; -} - -EGLContext qemu_egl_init_ctx(void) -{ - static const EGLint ctx_att_gl[] = { - EGL_NONE - }; - static const EGLint ctx_att_gles[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLContext ectx; - EGLBoolean b; - - egl_dbg("eglCreateContext ...\n"); - ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT, - egl_gles ? ctx_att_gles : ctx_att_gl); - if (ectx == EGL_NO_CONTEXT) { - fprintf(stderr, "egl: eglCreateContext failed\n"); - return NULL; - } - - b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx); - if (b == EGL_FALSE) { - fprintf(stderr, "egl: eglMakeCurrent failed\n"); - return NULL; - } - - return ectx; -} diff --git a/qemu/ui/gtk-egl.c b/qemu/ui/gtk-egl.c deleted file mode 100644 index 431457c74..000000000 --- a/qemu/ui/gtk-egl.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * GTK UI -- egl opengl code. - * - * Note that gtk 3.16+ (released 2015-03-23) has a GtkGLArea widget, - * which is GtkDrawingArea like widget with opengl rendering support. - * - * This code handles opengl support on older gtk versions, using egl - * to get a opengl context for the X11 window. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" - -#include "trace.h" - -#include "ui/console.h" -#include "ui/gtk.h" -#include "ui/egl-helpers.h" - -#include "sysemu/sysemu.h" - -static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout) -{ - if (vc->gfx.scanout_mode == scanout) { - return; - } - - vc->gfx.scanout_mode = scanout; - if (!vc->gfx.scanout_mode) { - if (vc->gfx.fbo_id) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - glDeleteFramebuffers(1, &vc->gfx.fbo_id); - vc->gfx.fbo_id = 0; - } - if (vc->gfx.surface) { - surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); - surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); - } - } -} - -/** DisplayState Callbacks (opengl version) **/ - -void gd_egl_init(VirtualConsole *vc) -{ - GdkWindow *gdk_window = gtk_widget_get_window(vc->gfx.drawing_area); - if (!gdk_window) { - return; - } - -#if GTK_CHECK_VERSION(3, 0, 0) - Window x11_window = gdk_x11_window_get_xid(gdk_window); -#else - Window x11_window = gdk_x11_drawable_get_xid(gdk_window); -#endif - if (!x11_window) { - return; - } - - vc->gfx.ectx = qemu_egl_init_ctx(); - vc->gfx.esurface = qemu_egl_init_surface_x11(vc->gfx.ectx, x11_window); - - assert(vc->gfx.esurface); -} - -void gd_egl_draw(VirtualConsole *vc) -{ - GdkWindow *window; - int ww, wh; - - if (!vc->gfx.gls) { - return; - } - - if (vc->gfx.scanout_mode) { - gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h); - } else { - if (!vc->gfx.ds) { - return; - } - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); - - window = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_drawable_get_size(window, &ww, &wh); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); - surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); - - eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); - } -} - -void gd_egl_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - if (!vc->gfx.gls || !vc->gfx.ds) { - return; - } - - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); - surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h); - vc->gfx.glupdates++; -} - -void gd_egl_refresh(DisplayChangeListener *dcl) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - if (!vc->gfx.esurface) { - gd_egl_init(vc); - if (!vc->gfx.esurface) { - return; - } - vc->gfx.gls = console_gl_init_context(); - if (vc->gfx.ds) { - surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); - } - } - - graphic_hw_update(dcl->con); - - if (vc->gfx.glupdates) { - vc->gfx.glupdates = 0; - gtk_egl_set_scanout_mode(vc, false); - gd_egl_draw(vc); - } -} - -void gd_egl_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - bool resized = true; - - trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); - - if (vc->gfx.ds && - surface_width(vc->gfx.ds) == surface_width(surface) && - surface_height(vc->gfx.ds) == surface_height(surface)) { - resized = false; - } - - surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); - vc->gfx.ds = surface; - if (vc->gfx.gls) { - surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); - } - - if (resized) { - gd_update_windowsize(vc); - } -} - -QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl, - QEMUGLParams *params) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); - return qemu_egl_create_context(dcl, params); -} - -void gd_egl_scanout(DisplayChangeListener *dcl, - uint32_t backing_id, bool backing_y_0_top, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - vc->gfx.x = x; - vc->gfx.y = y; - vc->gfx.w = w; - vc->gfx.h = h; - vc->gfx.tex_id = backing_id; - vc->gfx.y0_top = backing_y_0_top; - - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); - - if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) { - gtk_egl_set_scanout_mode(vc, false); - return; - } - - gtk_egl_set_scanout_mode(vc, true); - if (!vc->gfx.fbo_id) { - glGenFramebuffers(1, &vc->gfx.fbo_id); - } - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, vc->gfx.tex_id, 0); -} - -void gd_egl_scanout_flush(DisplayChangeListener *dcl, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkWindow *window; - int ww, wh, y1, y2; - - if (!vc->gfx.scanout_mode) { - return; - } - if (!vc->gfx.fbo_id) { - return; - } - - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - window = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_drawable_get_size(window, &ww, &wh); - glViewport(0, 0, ww, wh); - y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; - y2 = vc->gfx.y0_top ? vc->gfx.h : 0; - glBlitFramebuffer(0, y1, vc->gfx.w, y2, - 0, 0, ww, wh, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); - - eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); -} - -void gtk_egl_init(void) -{ - GdkDisplay *gdk_display = gdk_display_get_default(); - Display *x11_display = gdk_x11_display_get_xdisplay(gdk_display); - - if (qemu_egl_init_dpy(x11_display, false, false) < 0) { - return; - } - - display_opengl = 1; -} - -int gd_egl_make_current(DisplayChangeListener *dcl, - QEMUGLContext ctx) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, ctx); -} diff --git a/qemu/ui/gtk-gl-area.c b/qemu/ui/gtk-gl-area.c deleted file mode 100644 index b86ff3cbe..000000000 --- a/qemu/ui/gtk-gl-area.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * GTK UI -- glarea opengl code. - * - * Requires 3.16+ (GtkGLArea widget). - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" - -#include "trace.h" - -#include "ui/console.h" -#include "ui/gtk.h" -#include "ui/egl-helpers.h" - -#include "sysemu/sysemu.h" - -static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout) -{ - if (vc->gfx.scanout_mode == scanout) { - return; - } - - vc->gfx.scanout_mode = scanout; - if (!vc->gfx.scanout_mode) { - if (vc->gfx.fbo_id) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - glDeleteFramebuffers(1, &vc->gfx.fbo_id); - vc->gfx.fbo_id = 0; - } - if (vc->gfx.surface) { - surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); - surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); - } - } -} - -/** DisplayState Callbacks (opengl version) **/ - -void gd_gl_area_draw(VirtualConsole *vc) -{ - int ww, wh, y1, y2; - - if (!vc->gfx.gls) { - return; - } - - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area); - wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area); - - if (vc->gfx.scanout_mode) { - if (!vc->gfx.fbo_id) { - return; - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id); - /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ - - glViewport(0, 0, ww, wh); - y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; - y2 = vc->gfx.y0_top ? vc->gfx.h : 0; - glBlitFramebuffer(0, y1, vc->gfx.w, y2, - 0, 0, ww, wh, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } else { - if (!vc->gfx.ds) { - return; - } - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); - surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); - } -} - -void gd_gl_area_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - if (!vc->gfx.gls || !vc->gfx.ds) { - return; - } - - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h); - vc->gfx.glupdates++; -} - -void gd_gl_area_refresh(DisplayChangeListener *dcl) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - if (!vc->gfx.gls) { - if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { - return; - } - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - vc->gfx.gls = console_gl_init_context(); - if (vc->gfx.ds) { - surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); - } - } - - graphic_hw_update(dcl->con); - - if (vc->gfx.glupdates) { - vc->gfx.glupdates = 0; - gtk_gl_area_set_scanout_mode(vc, false); - gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); - } -} - -void gd_gl_area_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - bool resized = true; - - trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); - - if (vc->gfx.ds && - surface_width(vc->gfx.ds) == surface_width(surface) && - surface_height(vc->gfx.ds) == surface_height(surface)) { - resized = false; - } - - if (vc->gfx.gls) { - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); - surface_gl_create_texture(vc->gfx.gls, surface); - } - vc->gfx.ds = surface; - - if (resized) { - gd_update_windowsize(vc); - } -} - -QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl, - QEMUGLParams *params) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkWindow *window; - GdkGLContext *ctx; - GError *err = NULL; - - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - window = gtk_widget_get_window(vc->gfx.drawing_area); - ctx = gdk_window_create_gl_context(window, &err); - gdk_gl_context_set_required_version(ctx, - params->major_ver, - params->minor_ver); - gdk_gl_context_realize(ctx, &err); - return ctx; -} - -void gd_gl_area_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) -{ - /* FIXME */ -} - -void gd_gl_area_scanout(DisplayChangeListener *dcl, - uint32_t backing_id, bool backing_y_0_top, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - vc->gfx.x = x; - vc->gfx.y = y; - vc->gfx.w = w; - vc->gfx.h = h; - vc->gfx.tex_id = backing_id; - vc->gfx.y0_top = backing_y_0_top; - - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - - if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) { - gtk_gl_area_set_scanout_mode(vc, false); - return; - } - - gtk_gl_area_set_scanout_mode(vc, true); - if (!vc->gfx.fbo_id) { - glGenFramebuffers(1, &vc->gfx.fbo_id); - } - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, vc->gfx.tex_id, 0); -} - -void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - - gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); -} - -void gtk_gl_area_init(void) -{ - display_opengl = 1; -} - -QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl) -{ - return gdk_gl_context_get_current(); -} - -int gd_gl_area_make_current(DisplayChangeListener *dcl, - QEMUGLContext ctx) -{ - gdk_gl_context_make_current(ctx); - return 0; -} diff --git a/qemu/ui/gtk.c b/qemu/ui/gtk.c deleted file mode 100644 index f372a6d5a..000000000 --- a/qemu/ui/gtk.c +++ /dev/null @@ -1,2212 +0,0 @@ -/* - * GTK UI - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * Portions from gtk-vnc: - * - * GTK VNC Widget - * - * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> - * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.0 of the License, or (at your option) any later version. - * - * This library 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. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define GETTEXT_PACKAGE "qemu" -#define LOCALEDIR "po" - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qemu/cutils.h" - -#include "ui/console.h" -#include "ui/gtk.h" - -#include <glib/gi18n.h> -#include <locale.h> -#if defined(CONFIG_VTE) -#include <vte/vte.h> -#endif -#include <math.h> - -#include "trace.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" -#include "qmp-commands.h" -#include "x_keymap.h" -#include "keymaps.h" -#include "sysemu/char.h" -#include "qom/object.h" - -#define MAX_VCS 10 -#define VC_WINDOW_X_MIN 320 -#define VC_WINDOW_Y_MIN 240 -#define VC_TERM_X_MIN 80 -#define VC_TERM_Y_MIN 25 -#define VC_SCALE_MIN 0.25 -#define VC_SCALE_STEP 0.25 - -#if !defined(CONFIG_VTE) -# define VTE_CHECK_VERSION(a, b, c) 0 -#endif - -#if defined(CONFIG_VTE) && !GTK_CHECK_VERSION(3, 0, 0) -/* - * The gtk2 vte terminal widget seriously messes up the window resize - * for some reason. You basically can't make the qemu window smaller - * any more because the toplevel window geoemtry hints are overridden. - * - * Workaround that by hiding all vte widgets, except the one in the - * current tab. - * - * Luckily everything works smooth in gtk3. - */ -# define VTE_RESIZE_HACK 1 -#endif - -#if !GTK_CHECK_VERSION(2, 20, 0) -#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget) -#endif - -#ifndef GDK_IS_X11_DISPLAY -#define GDK_IS_X11_DISPLAY(dpy) (dpy == dpy) -#endif -#ifndef GDK_IS_WIN32_DISPLAY -#define GDK_IS_WIN32_DISPLAY(dpy) (dpy == dpy) -#endif - -#ifndef GDK_KEY_0 -#define GDK_KEY_0 GDK_0 -#define GDK_KEY_1 GDK_1 -#define GDK_KEY_2 GDK_2 -#define GDK_KEY_f GDK_f -#define GDK_KEY_g GDK_g -#define GDK_KEY_q GDK_q -#define GDK_KEY_plus GDK_plus -#define GDK_KEY_minus GDK_minus -#define GDK_KEY_Pause GDK_Pause -#endif - -/* Some older mingw versions lack this constant or have - * it conditionally defined */ -#ifdef _WIN32 -# ifndef MAPVK_VK_TO_VSC -# define MAPVK_VK_TO_VSC 0 -# endif -#endif - - -#define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) - -static const int modifier_keycode[] = { - /* shift, control, alt keys, meta keys, both left & right */ - 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8, 0xdb, 0xdd, -}; - -struct GtkDisplayState { - GtkWidget *window; - - GtkWidget *menu_bar; - - GtkAccelGroup *accel_group; - - GtkWidget *machine_menu_item; - GtkWidget *machine_menu; - GtkWidget *pause_item; - GtkWidget *reset_item; - GtkWidget *powerdown_item; - GtkWidget *quit_item; - - GtkWidget *view_menu_item; - GtkWidget *view_menu; - GtkWidget *full_screen_item; - GtkWidget *zoom_in_item; - GtkWidget *zoom_out_item; - GtkWidget *zoom_fixed_item; - GtkWidget *zoom_fit_item; - GtkWidget *grab_item; - GtkWidget *grab_on_hover_item; - - int nb_vcs; - VirtualConsole vc[MAX_VCS]; - - GtkWidget *show_tabs_item; - GtkWidget *untabify_item; - - GtkWidget *vbox; - GtkWidget *notebook; - int button_mask; - gboolean last_set; - int last_x; - int last_y; - int grab_x_root; - int grab_y_root; - VirtualConsole *kbd_owner; - VirtualConsole *ptr_owner; - - gboolean full_screen; - - GdkCursor *null_cursor; - Notifier mouse_mode_notifier; - gboolean free_scale; - - bool external_pause_update; - - bool modifier_pressed[ARRAY_SIZE(modifier_keycode)]; - bool has_evdev; - bool ignore_keys; -}; - -static void gd_grab_pointer(VirtualConsole *vc, const char *reason); -static void gd_ungrab_pointer(GtkDisplayState *s); -static void gd_grab_keyboard(VirtualConsole *vc, const char *reason); -static void gd_ungrab_keyboard(GtkDisplayState *s); - -/** Utility Functions **/ - -static VirtualConsole *gd_vc_find_by_menu(GtkDisplayState *s) -{ - VirtualConsole *vc; - gint i; - - for (i = 0; i < s->nb_vcs; i++) { - vc = &s->vc[i]; - if (gtk_check_menu_item_get_active - (GTK_CHECK_MENU_ITEM(vc->menu_item))) { - return vc; - } - } - return NULL; -} - -static VirtualConsole *gd_vc_find_by_page(GtkDisplayState *s, gint page) -{ - VirtualConsole *vc; - gint i, p; - - for (i = 0; i < s->nb_vcs; i++) { - vc = &s->vc[i]; - p = gtk_notebook_page_num(GTK_NOTEBOOK(s->notebook), vc->tab_item); - if (p == page) { - return vc; - } - } - return NULL; -} - -static VirtualConsole *gd_vc_find_current(GtkDisplayState *s) -{ - gint page; - - page = gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)); - return gd_vc_find_by_page(s, page); -} - -static bool gd_is_grab_active(GtkDisplayState *s) -{ - return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item)); -} - -static bool gd_grab_on_hover(GtkDisplayState *s) -{ - return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item)); -} - -static void gd_update_cursor(VirtualConsole *vc) -{ - GtkDisplayState *s = vc->s; - GdkWindow *window; - - if (vc->type != GD_VC_GFX || - !qemu_console_is_graphic(vc->gfx.dcl.con)) { - return; - } - - if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { - return; - } - - window = gtk_widget_get_window(GTK_WIDGET(vc->gfx.drawing_area)); - if (s->full_screen || qemu_input_is_absolute() || s->ptr_owner == vc) { - gdk_window_set_cursor(window, s->null_cursor); - } else { - gdk_window_set_cursor(window, NULL); - } -} - -static void gd_update_caption(GtkDisplayState *s) -{ - const char *status = ""; - gchar *prefix; - gchar *title; - const char *grab = ""; - bool is_paused = !runstate_is_running(); - int i; - - if (qemu_name) { - prefix = g_strdup_printf("QEMU (%s)", qemu_name); - } else { - prefix = g_strdup_printf("QEMU"); - } - - if (s->ptr_owner != NULL && - s->ptr_owner->window == NULL) { - grab = _(" - Press Ctrl+Alt+G to release grab"); - } - - if (is_paused) { - status = _(" [Paused]"); - } - s->external_pause_update = true; - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item), - is_paused); - s->external_pause_update = false; - - title = g_strdup_printf("%s%s%s", prefix, status, grab); - gtk_window_set_title(GTK_WINDOW(s->window), title); - g_free(title); - - for (i = 0; i < s->nb_vcs; i++) { - VirtualConsole *vc = &s->vc[i]; - - if (!vc->window) { - continue; - } - title = g_strdup_printf("%s: %s%s%s", prefix, vc->label, - vc == s->kbd_owner ? " +kbd" : "", - vc == s->ptr_owner ? " +ptr" : ""); - gtk_window_set_title(GTK_WINDOW(vc->window), title); - g_free(title); - } - - g_free(prefix); -} - -static void gd_update_geometry_hints(VirtualConsole *vc) -{ - GtkDisplayState *s = vc->s; - GdkWindowHints mask = 0; - GdkGeometry geo = {}; - GtkWidget *geo_widget = NULL; - GtkWindow *geo_window; - - if (vc->type == GD_VC_GFX) { - if (!vc->gfx.ds) { - return; - } - if (s->free_scale) { - geo.min_width = surface_width(vc->gfx.ds) * VC_SCALE_MIN; - geo.min_height = surface_height(vc->gfx.ds) * VC_SCALE_MIN; - mask |= GDK_HINT_MIN_SIZE; - } else { - geo.min_width = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - geo.min_height = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - mask |= GDK_HINT_MIN_SIZE; - } - geo_widget = vc->gfx.drawing_area; - gtk_widget_set_size_request(geo_widget, geo.min_width, geo.min_height); - -#if defined(CONFIG_VTE) - } else if (vc->type == GD_VC_VTE) { - VteTerminal *term = VTE_TERMINAL(vc->vte.terminal); - GtkBorder *ib; - - geo.width_inc = vte_terminal_get_char_width(term); - geo.height_inc = vte_terminal_get_char_height(term); - mask |= GDK_HINT_RESIZE_INC; - geo.base_width = geo.width_inc; - geo.base_height = geo.height_inc; - mask |= GDK_HINT_BASE_SIZE; - geo.min_width = geo.width_inc * VC_TERM_X_MIN; - geo.min_height = geo.height_inc * VC_TERM_Y_MIN; - mask |= GDK_HINT_MIN_SIZE; - gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL); - geo.base_width += ib->left + ib->right; - geo.base_height += ib->top + ib->bottom; - geo.min_width += ib->left + ib->right; - geo.min_height += ib->top + ib->bottom; - geo_widget = vc->vte.terminal; -#endif - } - - geo_window = GTK_WINDOW(vc->window ? vc->window : s->window); - gtk_window_set_geometry_hints(geo_window, geo_widget, &geo, mask); -} - -void gd_update_windowsize(VirtualConsole *vc) -{ - GtkDisplayState *s = vc->s; - - gd_update_geometry_hints(vc); - - if (vc->type == GD_VC_GFX && !s->full_screen && !s->free_scale) { - gtk_window_resize(GTK_WINDOW(vc->window ? vc->window : s->window), - VC_WINDOW_X_MIN, VC_WINDOW_Y_MIN); - } -} - -static void gd_update_full_redraw(VirtualConsole *vc) -{ - GtkWidget *area = vc->gfx.drawing_area; - int ww, wh; - gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh); -#if defined(CONFIG_GTK_GL) - if (vc->gfx.gls) { - gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); - return; - } -#endif - gtk_widget_queue_draw_area(area, 0, 0, ww, wh); -} - -static void gtk_release_modifiers(GtkDisplayState *s) -{ - VirtualConsole *vc = gd_vc_find_current(s); - int i, keycode; - - if (vc->type != GD_VC_GFX || - !qemu_console_is_graphic(vc->gfx.dcl.con)) { - return; - } - for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) { - keycode = modifier_keycode[i]; - if (!s->modifier_pressed[i]) { - continue; - } - qemu_input_event_send_key_number(vc->gfx.dcl.con, keycode, false); - s->modifier_pressed[i] = false; - } -} - -static void gd_widget_reparent(GtkWidget *from, GtkWidget *to, - GtkWidget *widget) -{ - g_object_ref(G_OBJECT(widget)); - gtk_container_remove(GTK_CONTAINER(from), widget); - gtk_container_add(GTK_CONTAINER(to), widget); - g_object_unref(G_OBJECT(widget)); -} - -/** DisplayState Callbacks **/ - -static void gd_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkWindow *win; - int x1, x2, y1, y2; - int mx, my; - int fbw, fbh; - int ww, wh; - - trace_gd_update(vc->label, x, y, w, h); - - if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { - return; - } - - if (vc->gfx.convert) { - pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image, - NULL, vc->gfx.convert, - x, y, 0, 0, x, y, w, h); - } - - x1 = floor(x * vc->gfx.scale_x); - y1 = floor(y * vc->gfx.scale_y); - - x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x); - y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y); - - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - - win = gtk_widget_get_window(vc->gfx.drawing_area); - if (!win) { - return; - } - gdk_drawable_get_size(win, &ww, &wh); - - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; - } - if (wh > fbh) { - my = (wh - fbh) / 2; - } - - gtk_widget_queue_draw_area(vc->gfx.drawing_area, - mx + x1, my + y1, (x2 - x1), (y2 - y1)); -} - -static void gd_refresh(DisplayChangeListener *dcl) -{ - graphic_hw_update(dcl->con); -} - -#if GTK_CHECK_VERSION(3, 0, 0) -static void gd_mouse_set(DisplayChangeListener *dcl, - int x, int y, int visible) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkDisplay *dpy; - GdkDeviceManager *mgr; - gint x_root, y_root; - - if (qemu_input_is_absolute()) { - return; - } - - dpy = gtk_widget_get_display(vc->gfx.drawing_area); - mgr = gdk_display_get_device_manager(dpy); - gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area), - x, y, &x_root, &y_root); - gdk_device_warp(gdk_device_manager_get_client_pointer(mgr), - gtk_widget_get_screen(vc->gfx.drawing_area), - x_root, y_root); - vc->s->last_x = x; - vc->s->last_y = y; -} -#else -static void gd_mouse_set(DisplayChangeListener *dcl, - int x, int y, int visible) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - gint x_root, y_root; - - if (qemu_input_is_absolute()) { - return; - } - - gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area), - x, y, &x_root, &y_root); - gdk_display_warp_pointer(gtk_widget_get_display(vc->gfx.drawing_area), - gtk_widget_get_screen(vc->gfx.drawing_area), - x_root, y_root); -} -#endif - -static void gd_cursor_define(DisplayChangeListener *dcl, - QEMUCursor *c) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - GdkPixbuf *pixbuf; - GdkCursor *cursor; - - if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { - return; - } - - pixbuf = gdk_pixbuf_new_from_data((guchar *)(c->data), - GDK_COLORSPACE_RGB, true, 8, - c->width, c->height, c->width * 4, - NULL, NULL); - cursor = gdk_cursor_new_from_pixbuf - (gtk_widget_get_display(vc->gfx.drawing_area), - pixbuf, c->hot_x, c->hot_y); - gdk_window_set_cursor(gtk_widget_get_window(vc->gfx.drawing_area), cursor); - g_object_unref(pixbuf); -#if !GTK_CHECK_VERSION(3, 0, 0) - gdk_cursor_unref(cursor); -#else - g_object_unref(cursor); -#endif -} - -static void gd_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - bool resized = true; - - trace_gd_switch(vc->label, - surface ? surface_width(surface) : 0, - surface ? surface_height(surface) : 0); - - if (vc->gfx.surface) { - cairo_surface_destroy(vc->gfx.surface); - vc->gfx.surface = NULL; - } - if (vc->gfx.convert) { - pixman_image_unref(vc->gfx.convert); - vc->gfx.convert = NULL; - } - - if (vc->gfx.ds && surface && - surface_width(vc->gfx.ds) == surface_width(surface) && - surface_height(vc->gfx.ds) == surface_height(surface)) { - resized = false; - } - vc->gfx.ds = surface; - - if (!surface) { - return; - } - - if (surface->format == PIXMAN_x8r8g8b8) { - /* - * PIXMAN_x8r8g8b8 == CAIRO_FORMAT_RGB24 - * - * No need to convert, use surface directly. Should be the - * common case as this is qemu_default_pixelformat(32) too. - */ - vc->gfx.surface = cairo_image_surface_create_for_data - (surface_data(surface), - CAIRO_FORMAT_RGB24, - surface_width(surface), - surface_height(surface), - surface_stride(surface)); - } else { - /* Must convert surface, use pixman to do it. */ - vc->gfx.convert = pixman_image_create_bits(PIXMAN_x8r8g8b8, - surface_width(surface), - surface_height(surface), - NULL, 0); - vc->gfx.surface = cairo_image_surface_create_for_data - ((void *)pixman_image_get_data(vc->gfx.convert), - CAIRO_FORMAT_RGB24, - pixman_image_get_width(vc->gfx.convert), - pixman_image_get_height(vc->gfx.convert), - pixman_image_get_stride(vc->gfx.convert)); - pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image, - NULL, vc->gfx.convert, - 0, 0, 0, 0, 0, 0, - pixman_image_get_width(vc->gfx.convert), - pixman_image_get_height(vc->gfx.convert)); - } - - if (resized) { - gd_update_windowsize(vc); - } else { - gd_update_full_redraw(vc); - } -} - -static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "gtk", - .dpy_gfx_update = gd_update, - .dpy_gfx_switch = gd_switch, - .dpy_gfx_check_format = qemu_pixman_check_format, - .dpy_refresh = gd_refresh, - .dpy_mouse_set = gd_mouse_set, - .dpy_cursor_define = gd_cursor_define, -}; - - -#if defined(CONFIG_OPENGL) - -/** DisplayState Callbacks (opengl version) **/ - -#if defined(CONFIG_GTK_GL) - -static const DisplayChangeListenerOps dcl_gl_area_ops = { - .dpy_name = "gtk-egl", - .dpy_gfx_update = gd_gl_area_update, - .dpy_gfx_switch = gd_gl_area_switch, - .dpy_gfx_check_format = console_gl_check_format, - .dpy_refresh = gd_gl_area_refresh, - .dpy_mouse_set = gd_mouse_set, - .dpy_cursor_define = gd_cursor_define, - - .dpy_gl_ctx_create = gd_gl_area_create_context, - .dpy_gl_ctx_destroy = gd_gl_area_destroy_context, - .dpy_gl_ctx_make_current = gd_gl_area_make_current, - .dpy_gl_ctx_get_current = gd_gl_area_get_current_context, - .dpy_gl_scanout = gd_gl_area_scanout, - .dpy_gl_update = gd_gl_area_scanout_flush, -}; - -#else - -static const DisplayChangeListenerOps dcl_egl_ops = { - .dpy_name = "gtk-egl", - .dpy_gfx_update = gd_egl_update, - .dpy_gfx_switch = gd_egl_switch, - .dpy_gfx_check_format = console_gl_check_format, - .dpy_refresh = gd_egl_refresh, - .dpy_mouse_set = gd_mouse_set, - .dpy_cursor_define = gd_cursor_define, - - .dpy_gl_ctx_create = gd_egl_create_context, - .dpy_gl_ctx_destroy = qemu_egl_destroy_context, - .dpy_gl_ctx_make_current = gd_egl_make_current, - .dpy_gl_ctx_get_current = qemu_egl_get_current_context, - .dpy_gl_scanout = gd_egl_scanout, - .dpy_gl_update = gd_egl_scanout_flush, -}; - -#endif /* CONFIG_GTK_GL */ -#endif /* CONFIG_OPENGL */ - -/** QEMU Events **/ - -static void gd_change_runstate(void *opaque, int running, RunState state) -{ - GtkDisplayState *s = opaque; - - gd_update_caption(s); -} - -static void gd_mouse_mode_change(Notifier *notify, void *data) -{ - GtkDisplayState *s; - int i; - - s = container_of(notify, GtkDisplayState, mouse_mode_notifier); - /* release the grab at switching to absolute mode */ - if (qemu_input_is_absolute() && gd_is_grab_active(s)) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); - } - for (i = 0; i < s->nb_vcs; i++) { - VirtualConsole *vc = &s->vc[i]; - gd_update_cursor(vc); - } -} - -/** GTK Events **/ - -static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, - void *opaque) -{ - GtkDisplayState *s = opaque; - int i; - - if (!no_quit) { - for (i = 0; i < s->nb_vcs; i++) { - if (s->vc[i].type != GD_VC_GFX) { - continue; - } - unregister_displaychangelistener(&s->vc[i].gfx.dcl); - } - qmp_quit(NULL); - return FALSE; - } - - return TRUE; -} - -static void gd_set_ui_info(VirtualConsole *vc, gint width, gint height) -{ - QemuUIInfo info; - - memset(&info, 0, sizeof(info)); - info.width = width; - info.height = height; - dpy_set_ui_info(vc->gfx.dcl.con, &info); -} - -#if defined(CONFIG_GTK_GL) - -static gboolean gd_render_event(GtkGLArea *area, GdkGLContext *context, - void *opaque) -{ - VirtualConsole *vc = opaque; - - if (vc->gfx.gls) { - gd_gl_area_draw(vc); - } - return TRUE; -} - -static void gd_resize_event(GtkGLArea *area, - gint width, gint height, gpointer *opaque) -{ - VirtualConsole *vc = (void *)opaque; - - gd_set_ui_info(vc, width, height); -} - -#endif - -static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - int mx, my; - int ww, wh; - int fbw, fbh; - -#if defined(CONFIG_OPENGL) - if (vc->gfx.gls) { -#if defined(CONFIG_GTK_GL) - /* invoke render callback please */ - return FALSE; -#else - gd_egl_draw(vc); - return TRUE; -#endif - } -#endif - - if (!gtk_widget_get_realized(widget)) { - return FALSE; - } - if (!vc->gfx.ds) { - return FALSE; - } - - fbw = surface_width(vc->gfx.ds); - fbh = surface_height(vc->gfx.ds); - - gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh); - - if (s->full_screen) { - vc->gfx.scale_x = (double)ww / fbw; - vc->gfx.scale_y = (double)wh / fbh; - } else if (s->free_scale) { - double sx, sy; - - sx = (double)ww / fbw; - sy = (double)wh / fbh; - - vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); - } - - fbw *= vc->gfx.scale_x; - fbh *= vc->gfx.scale_y; - - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; - } - if (wh > fbh) { - my = (wh - fbh) / 2; - } - - cairo_rectangle(cr, 0, 0, ww, wh); - - /* Optionally cut out the inner area where the pixmap - will be drawn. This avoids 'flashing' since we're - not double-buffering. Note we're using the undocumented - behaviour of drawing the rectangle from right to left - to cut out the whole */ - cairo_rectangle(cr, mx + fbw, my, - -1 * fbw, fbh); - cairo_fill(cr); - - cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y); - cairo_set_source_surface(cr, vc->gfx.surface, - mx / vc->gfx.scale_x, my / vc->gfx.scale_y); - cairo_paint(cr); - - return TRUE; -} - -#if !GTK_CHECK_VERSION(3, 0, 0) -static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose, - void *opaque) -{ - cairo_t *cr; - gboolean ret; - - cr = gdk_cairo_create(gtk_widget_get_window(widget)); - cairo_rectangle(cr, - expose->area.x, - expose->area.y, - expose->area.width, - expose->area.height); - cairo_clip(cr); - - ret = gd_draw_event(widget, cr, opaque); - - cairo_destroy(cr); - - return ret; -} -#endif - -static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, - void *opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - int x, y; - int mx, my; - int fbh, fbw; - int ww, wh; - - if (!vc->gfx.ds) { - return TRUE; - } - - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - - gdk_drawable_get_size(gtk_widget_get_window(vc->gfx.drawing_area), - &ww, &wh); - - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; - } - if (wh > fbh) { - my = (wh - fbh) / 2; - } - - x = (motion->x - mx) / vc->gfx.scale_x; - y = (motion->y - my) / vc->gfx.scale_y; - - if (qemu_input_is_absolute()) { - if (x < 0 || y < 0 || - x >= surface_width(vc->gfx.ds) || - y >= surface_height(vc->gfx.ds)) { - return TRUE; - } - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x, - surface_width(vc->gfx.ds)); - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y, - surface_height(vc->gfx.ds)); - qemu_input_event_sync(); - } else if (s->last_set && s->ptr_owner == vc) { - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x); - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y); - qemu_input_event_sync(); - } - s->last_x = x; - s->last_y = y; - s->last_set = TRUE; - - if (!qemu_input_is_absolute() && s->ptr_owner == vc) { - GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area); - int x = (int)motion->x_root; - int y = (int)motion->y_root; - - /* In relative mode check to see if client pointer hit - * one of the screen edges, and if so move it back by - * 200 pixels. This is important because the pointer - * in the server doesn't correspond 1-for-1, and so - * may still be only half way across the screen. Without - * this warp, the server pointer would thus appear to hit - * an invisible wall */ - if (x == 0) { - x += 200; - } - if (y == 0) { - y += 200; - } - if (x == (gdk_screen_get_width(screen) - 1)) { - x -= 200; - } - if (y == (gdk_screen_get_height(screen) - 1)) { - y -= 200; - } - - if (x != (int)motion->x_root || y != (int)motion->y_root) { -#if GTK_CHECK_VERSION(3, 0, 0) - GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion); - gdk_device_warp(dev, screen, x, y); -#else - GdkDisplay *display = gtk_widget_get_display(widget); - gdk_display_warp_pointer(display, screen, x, y); -#endif - s->last_set = FALSE; - return FALSE; - } - } - return TRUE; -} - -static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, - void *opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - InputButton btn; - - /* implicitly grab the input at the first click in the relative mode */ - if (button->button == 1 && button->type == GDK_BUTTON_PRESS && - !qemu_input_is_absolute() && s->ptr_owner != vc) { - if (!vc->window) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - TRUE); - } else { - gd_grab_pointer(vc, "relative-mode-click"); - } - return TRUE; - } - - if (button->button == 1) { - btn = INPUT_BUTTON_LEFT; - } else if (button->button == 2) { - btn = INPUT_BUTTON_MIDDLE; - } else if (button->button == 3) { - btn = INPUT_BUTTON_RIGHT; - } else { - return TRUE; - } - - qemu_input_queue_btn(vc->gfx.dcl.con, btn, - button->type == GDK_BUTTON_PRESS); - qemu_input_event_sync(); - return TRUE; -} - -static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll, - void *opaque) -{ - VirtualConsole *vc = opaque; - InputButton btn; - - if (scroll->direction == GDK_SCROLL_UP) { - btn = INPUT_BUTTON_WHEEL_UP; - } else if (scroll->direction == GDK_SCROLL_DOWN) { - btn = INPUT_BUTTON_WHEEL_DOWN; - } else { - return TRUE; - } - - qemu_input_queue_btn(vc->gfx.dcl.con, btn, true); - qemu_input_event_sync(); - qemu_input_queue_btn(vc->gfx.dcl.con, btn, false); - qemu_input_event_sync(); - return TRUE; -} - -static int gd_map_keycode(GtkDisplayState *s, GdkDisplay *dpy, int gdk_keycode) -{ - int qemu_keycode; - -#ifdef GDK_WINDOWING_WIN32 - if (GDK_IS_WIN32_DISPLAY(dpy)) { - qemu_keycode = MapVirtualKey(gdk_keycode, MAPVK_VK_TO_VSC); - switch (qemu_keycode) { - case 103: /* alt gr */ - qemu_keycode = 56 | SCANCODE_GREY; - break; - } - return qemu_keycode; - } -#endif - - if (gdk_keycode < 9) { - qemu_keycode = 0; - } else if (gdk_keycode < 97) { - qemu_keycode = gdk_keycode - 8; -#ifdef GDK_WINDOWING_X11 - } else if (GDK_IS_X11_DISPLAY(dpy) && gdk_keycode < 158) { - if (s->has_evdev) { - qemu_keycode = translate_evdev_keycode(gdk_keycode - 97); - } else { - qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97); - } -#endif - } else if (gdk_keycode == 208) { /* Hiragana_Katakana */ - qemu_keycode = 0x70; - } else if (gdk_keycode == 211) { /* backslash */ - qemu_keycode = 0x73; - } else { - qemu_keycode = 0; - } - - return qemu_keycode; -} - -static gboolean gd_text_key_down(GtkWidget *widget, - GdkEventKey *key, void *opaque) -{ - VirtualConsole *vc = opaque; - QemuConsole *con = vc->gfx.dcl.con; - - if (key->length) { - kbd_put_string_console(con, key->string, key->length); - } else { - int num = gd_map_keycode(vc->s, gtk_widget_get_display(widget), - key->hardware_keycode); - int qcode = qemu_input_key_number_to_qcode(num); - kbd_put_qcode_console(con, qcode); - } - return TRUE; -} - -static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - int gdk_keycode = key->hardware_keycode; - int qemu_keycode; - int i; - - if (s->ignore_keys) { - s->ignore_keys = (key->type == GDK_KEY_PRESS); - return TRUE; - } - - if (key->keyval == GDK_KEY_Pause) { - qemu_input_event_send_key_qcode(vc->gfx.dcl.con, Q_KEY_CODE_PAUSE, - key->type == GDK_KEY_PRESS); - return TRUE; - } - - qemu_keycode = gd_map_keycode(s, gtk_widget_get_display(widget), - gdk_keycode); - - trace_gd_key_event(vc->label, gdk_keycode, qemu_keycode, - (key->type == GDK_KEY_PRESS) ? "down" : "up"); - - for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) { - if (qemu_keycode == modifier_keycode[i]) { - s->modifier_pressed[i] = (key->type == GDK_KEY_PRESS); - } - } - - qemu_input_event_send_key_number(vc->gfx.dcl.con, qemu_keycode, - key->type == GDK_KEY_PRESS); - - return TRUE; -} - -static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque) -{ - if (event->type == GDK_MOTION_NOTIFY) { - return gd_motion_event(widget, &event->motion, opaque); - } - return FALSE; -} - -/** Window Menu Actions **/ - -static void gd_menu_pause(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - - if (s->external_pause_update) { - return; - } - if (runstate_is_running()) { - qmp_stop(NULL); - } else { - qmp_cont(NULL); - } -} - -static void gd_menu_reset(GtkMenuItem *item, void *opaque) -{ - qmp_system_reset(NULL); -} - -static void gd_menu_powerdown(GtkMenuItem *item, void *opaque) -{ - qmp_system_powerdown(NULL); -} - -static void gd_menu_quit(GtkMenuItem *item, void *opaque) -{ - qmp_quit(NULL); -} - -static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_by_menu(s); - GtkNotebook *nb = GTK_NOTEBOOK(s->notebook); - gint page; - - gtk_release_modifiers(s); - if (vc) { - page = gtk_notebook_page_num(nb, vc->tab_item); - gtk_notebook_set_current_page(nb, page); - gtk_widget_grab_focus(vc->focus); - } - s->ignore_keys = false; -} - -static void gd_accel_switch_vc(void *opaque) -{ - VirtualConsole *vc = opaque; - - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE); -#if !GTK_CHECK_VERSION(3, 0, 0) - /* GTK2 sends the accel key to the target console - ignore this until */ - vc->s->ignore_keys = true; -#endif -} - -static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) { - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE); - } else { - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); - } - gd_update_windowsize(vc); -} - -static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event, - void *opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - - gtk_widget_set_sensitive(vc->menu_item, true); - gd_widget_reparent(vc->window, s->notebook, vc->tab_item); - gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook), - vc->tab_item, vc->label); - gtk_widget_destroy(vc->window); - vc->window = NULL; - return TRUE; -} - -static gboolean gd_win_grab(void *opaque) -{ - VirtualConsole *vc = opaque; - - fprintf(stderr, "%s: %s\n", __func__, vc->label); - if (vc->s->ptr_owner) { - gd_ungrab_pointer(vc->s); - } else { - gd_grab_pointer(vc, "user-request-detached-tab"); - } - return TRUE; -} - -static void gd_menu_untabify(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - if (vc->type == GD_VC_GFX && - qemu_console_is_graphic(vc->gfx.dcl.con)) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); - } - if (!vc->window) { - gtk_widget_set_sensitive(vc->menu_item, false); - vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gd_widget_reparent(s->notebook, vc->window, vc->tab_item); - - g_signal_connect(vc->window, "delete-event", - G_CALLBACK(gd_tab_window_close), vc); - gtk_widget_show_all(vc->window); - - if (qemu_console_is_graphic(vc->gfx.dcl.con)) { - GtkAccelGroup *ag = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag); - - GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), - vc, NULL); - gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb); - } - - gd_update_geometry_hints(vc); - gd_update_caption(s); - } -} - -static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - if (!s->full_screen) { - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); - gtk_widget_hide(s->menu_bar); - if (vc->type == GD_VC_GFX) { - gtk_widget_set_size_request(vc->gfx.drawing_area, -1, -1); - } - gtk_window_fullscreen(GTK_WINDOW(s->window)); - s->full_screen = TRUE; - } else { - gtk_window_unfullscreen(GTK_WINDOW(s->window)); - gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s); - gtk_widget_show(s->menu_bar); - s->full_screen = FALSE; - if (vc->type == GD_VC_GFX) { - vc->gfx.scale_x = 1.0; - vc->gfx.scale_y = 1.0; - gd_update_windowsize(vc); - } - } - - gd_update_cursor(vc); -} - -static void gd_accel_full_screen(void *opaque) -{ - GtkDisplayState *s = opaque; - gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); -} - -static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), - FALSE); - - vc->gfx.scale_x += VC_SCALE_STEP; - vc->gfx.scale_y += VC_SCALE_STEP; - - gd_update_windowsize(vc); -} - -static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), - FALSE); - - vc->gfx.scale_x -= VC_SCALE_STEP; - vc->gfx.scale_y -= VC_SCALE_STEP; - - vc->gfx.scale_x = MAX(vc->gfx.scale_x, VC_SCALE_MIN); - vc->gfx.scale_y = MAX(vc->gfx.scale_y, VC_SCALE_MIN); - - gd_update_windowsize(vc); -} - -static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - vc->gfx.scale_x = 1.0; - vc->gfx.scale_y = 1.0; - - gd_update_windowsize(vc); -} - -static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) { - s->free_scale = TRUE; - } else { - s->free_scale = FALSE; - vc->gfx.scale_x = 1.0; - vc->gfx.scale_y = 1.0; - } - - gd_update_windowsize(vc); - gd_update_full_redraw(vc); -} - -#if GTK_CHECK_VERSION(3, 0, 0) -static void gd_grab_devices(VirtualConsole *vc, bool grab, - GdkInputSource source, GdkEventMask mask, - GdkCursor *cursor) -{ - GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); - GdkDeviceManager *mgr = gdk_display_get_device_manager(display); - GList *devs = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER); - GList *tmp = devs; - - for (tmp = devs; tmp; tmp = tmp->next) { - GdkDevice *dev = tmp->data; - if (gdk_device_get_source(dev) != source) { - continue; - } - if (grab) { - GdkWindow *win = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_device_grab(dev, win, GDK_OWNERSHIP_NONE, FALSE, - mask, cursor, GDK_CURRENT_TIME); - } else { - gdk_device_ungrab(dev, GDK_CURRENT_TIME); - } - } - g_list_free(devs); -} -#endif - -static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) -{ - if (vc->s->kbd_owner) { - if (vc->s->kbd_owner == vc) { - return; - } else { - gd_ungrab_keyboard(vc->s); - } - } - -#if GTK_CHECK_VERSION(3, 0, 0) - gd_grab_devices(vc, true, GDK_SOURCE_KEYBOARD, - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, - NULL); -#else - gdk_keyboard_grab(gtk_widget_get_window(vc->gfx.drawing_area), - FALSE, - GDK_CURRENT_TIME); -#endif - vc->s->kbd_owner = vc; - gd_update_caption(vc->s); - trace_gd_grab(vc->label, "kbd", reason); -} - -static void gd_ungrab_keyboard(GtkDisplayState *s) -{ - VirtualConsole *vc = s->kbd_owner; - - if (vc == NULL) { - return; - } - s->kbd_owner = NULL; - -#if GTK_CHECK_VERSION(3, 0, 0) - gd_grab_devices(vc, false, GDK_SOURCE_KEYBOARD, 0, NULL); -#else - gdk_keyboard_ungrab(GDK_CURRENT_TIME); -#endif - gd_update_caption(s); - trace_gd_ungrab(vc->label, "kbd"); -} - -static void gd_grab_pointer(VirtualConsole *vc, const char *reason) -{ - GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); - - if (vc->s->ptr_owner) { - if (vc->s->ptr_owner == vc) { - return; - } else { - gd_ungrab_pointer(vc->s); - } - } - -#if GTK_CHECK_VERSION(3, 0, 0) - GdkDeviceManager *mgr = gdk_display_get_device_manager(display); - gd_grab_devices(vc, true, GDK_SOURCE_MOUSE, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - vc->s->null_cursor); - gdk_device_get_position(gdk_device_manager_get_client_pointer(mgr), - NULL, &vc->s->grab_x_root, &vc->s->grab_y_root); -#else - gdk_pointer_grab(gtk_widget_get_window(vc->gfx.drawing_area), - FALSE, /* All events to come to our window directly */ - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - NULL, /* Allow cursor to move over entire desktop */ - vc->s->null_cursor, - GDK_CURRENT_TIME); - gdk_display_get_pointer(display, NULL, - &vc->s->grab_x_root, &vc->s->grab_y_root, NULL); -#endif - vc->s->ptr_owner = vc; - gd_update_caption(vc->s); - trace_gd_grab(vc->label, "ptr", reason); -} - -static void gd_ungrab_pointer(GtkDisplayState *s) -{ - VirtualConsole *vc = s->ptr_owner; - - if (vc == NULL) { - return; - } - s->ptr_owner = NULL; - - GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); -#if GTK_CHECK_VERSION(3, 0, 0) - GdkDeviceManager *mgr = gdk_display_get_device_manager(display); - gd_grab_devices(vc, false, GDK_SOURCE_MOUSE, 0, NULL); - gdk_device_warp(gdk_device_manager_get_client_pointer(mgr), - gtk_widget_get_screen(vc->gfx.drawing_area), - vc->s->grab_x_root, vc->s->grab_y_root); -#else - gdk_pointer_ungrab(GDK_CURRENT_TIME); - gdk_display_warp_pointer(display, - gtk_widget_get_screen(vc->gfx.drawing_area), - vc->s->grab_x_root, vc->s->grab_y_root); -#endif - gd_update_caption(s); - trace_gd_ungrab(vc->label, "ptr"); -} - -static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) -{ - GtkDisplayState *s = opaque; - VirtualConsole *vc = gd_vc_find_current(s); - - if (gd_is_grab_active(s)) { - gd_grab_keyboard(vc, "user-request-main-window"); - gd_grab_pointer(vc, "user-request-main-window"); - } else { - gd_ungrab_keyboard(s); - gd_ungrab_pointer(s); - } - - gd_update_cursor(vc); -} - -static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, - gpointer data) -{ - GtkDisplayState *s = data; - VirtualConsole *vc; - gboolean on_vga; - - if (!gtk_widget_get_realized(s->notebook)) { - return; - } - -#ifdef VTE_RESIZE_HACK - vc = gd_vc_find_current(s); - if (vc && vc->type == GD_VC_VTE) { - gtk_widget_hide(vc->vte.terminal); - } -#endif - vc = gd_vc_find_by_page(s, arg2); - if (!vc) { - return; - } -#ifdef VTE_RESIZE_HACK - if (vc->type == GD_VC_VTE) { - gtk_widget_show(vc->vte.terminal); - } -#endif - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), - TRUE); - on_vga = (vc->type == GD_VC_GFX && - qemu_console_is_graphic(vc->gfx.dcl.con)); - if (!on_vga) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); - } else if (s->full_screen) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - TRUE); - } - gtk_widget_set_sensitive(s->grab_item, on_vga); - - gd_update_windowsize(vc); - gd_update_cursor(vc); -} - -static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, - gpointer opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - - if (gd_grab_on_hover(s)) { - gd_grab_keyboard(vc, "grab-on-hover"); - } - return TRUE; -} - -static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, - gpointer opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - - if (gd_grab_on_hover(s)) { - gd_ungrab_keyboard(s); - } - return TRUE; -} - -static gboolean gd_focus_out_event(GtkWidget *widget, - GdkEventCrossing *crossing, gpointer opaque) -{ - VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; - - gtk_release_modifiers(s); - return TRUE; -} - -static gboolean gd_configure(GtkWidget *widget, - GdkEventConfigure *cfg, gpointer opaque) -{ - VirtualConsole *vc = opaque; - - gd_set_ui_info(vc, cfg->width, cfg->height); - return FALSE; -} - -/** Virtual Console Callbacks **/ - -static GSList *gd_vc_menu_init(GtkDisplayState *s, VirtualConsole *vc, - int idx, GSList *group, GtkWidget *view_menu) -{ - vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, vc->label); - gtk_accel_group_connect(s->accel_group, GDK_KEY_1 + idx, - HOTKEY_MODIFIERS, 0, - g_cclosure_new_swap(G_CALLBACK(gd_accel_switch_vc), vc, NULL)); -#if GTK_CHECK_VERSION(3, 8, 0) - gtk_accel_label_set_accel( - GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(vc->menu_item))), - GDK_KEY_1 + idx, HOTKEY_MODIFIERS); -#endif - - g_signal_connect(vc->menu_item, "activate", - G_CALLBACK(gd_menu_switch_vc), s); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item); - - group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item)); - return group; -} - -#if defined(CONFIG_VTE) -static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque) -{ - VirtualConsole *vc = opaque; - - if (gtk_adjustment_get_upper(adjustment) > - gtk_adjustment_get_page_size(adjustment)) { - gtk_widget_show(vc->vte.scrollbar); - } else { - gtk_widget_hide(vc->vte.scrollbar); - } -} - -static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - VirtualConsole *vc = chr->opaque; - - vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len); - return len; -} - -static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo) -{ - VirtualConsole *vc = chr->opaque; - - vc->vte.echo = echo; -} - -static int nb_vcs; -static CharDriverState *vcs[MAX_VCS]; - -static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp) -{ - ChardevCommon *common = qapi_ChardevVC_base(vc); - CharDriverState *chr; - - chr = qemu_chr_alloc(common, errp); - if (!chr) { - return NULL; - } - - chr->chr_write = gd_vc_chr_write; - chr->chr_set_echo = gd_vc_chr_set_echo; - - /* Temporary, until gd_vc_vte_init runs. */ - chr->opaque = g_new0(VirtualConsole, 1); - - /* defer OPENED events until our vc is fully initialized */ - chr->explicit_be_open = true; - - vcs[nb_vcs++] = chr; - - return chr; -} - -static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size, - gpointer user_data) -{ - VirtualConsole *vc = user_data; - - if (vc->vte.echo) { - VteTerminal *term = VTE_TERMINAL(vc->vte.terminal); - int i; - for (i = 0; i < size; i++) { - uint8_t c = text[i]; - if (c >= 128 || isprint(c)) { - /* 8-bit characters are considered printable. */ - vte_terminal_feed(term, &text[i], 1); - } else if (c == '\r' || c == '\n') { - vte_terminal_feed(term, "\r\n", 2); - } else { - char ctrl[2] = { '^', 0}; - ctrl[1] = text[i] ^ 64; - vte_terminal_feed(term, ctrl, 2); - } - } - } - - qemu_chr_be_write(vc->vte.chr, (uint8_t *)text, (unsigned int)size); - return TRUE; -} - -static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc, - CharDriverState *chr, int idx, - GSList *group, GtkWidget *view_menu) -{ - char buffer[32]; - GtkWidget *box; - GtkWidget *scrollbar; - GtkAdjustment *vadjustment; - VirtualConsole *tmp_vc = chr->opaque; - - vc->s = s; - vc->vte.echo = tmp_vc->vte.echo; - - vc->vte.chr = chr; - chr->opaque = vc; - g_free(tmp_vc); - - snprintf(buffer, sizeof(buffer), "vc%d", idx); - vc->label = g_strdup_printf("%s", vc->vte.chr->label - ? vc->vte.chr->label : buffer); - group = gd_vc_menu_init(s, vc, idx, group, view_menu); - - vc->vte.terminal = vte_terminal_new(); - g_signal_connect(vc->vte.terminal, "commit", G_CALLBACK(gd_vc_in), vc); - - /* The documentation says that the default is UTF-8, but actually it is - * 7-bit ASCII at least in VTE 0.38. - */ -#if VTE_CHECK_VERSION(0, 40, 0) - vte_terminal_set_encoding(VTE_TERMINAL(vc->vte.terminal), "UTF-8", NULL); -#else - vte_terminal_set_encoding(VTE_TERMINAL(vc->vte.terminal), "UTF-8"); -#endif - - vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->vte.terminal), -1); - vte_terminal_set_size(VTE_TERMINAL(vc->vte.terminal), - VC_TERM_X_MIN, VC_TERM_Y_MIN); - -#if VTE_CHECK_VERSION(0, 28, 0) && GTK_CHECK_VERSION(3, 0, 0) - vadjustment = gtk_scrollable_get_vadjustment - (GTK_SCROLLABLE(vc->vte.terminal)); -#else - vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->vte.terminal)); -#endif - -#if GTK_CHECK_VERSION(3, 0, 0) - box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); - scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, vadjustment); -#else - box = gtk_hbox_new(false, 2); - scrollbar = gtk_vscrollbar_new(vadjustment); -#endif - - gtk_box_pack_start(GTK_BOX(box), vc->vte.terminal, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box), scrollbar, FALSE, FALSE, 0); - - vc->vte.box = box; - vc->vte.scrollbar = scrollbar; - - g_signal_connect(vadjustment, "changed", - G_CALLBACK(gd_vc_adjustment_changed), vc); - - vc->type = GD_VC_VTE; - vc->tab_item = box; - vc->focus = vc->vte.terminal; - gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item, - gtk_label_new(vc->label)); - - qemu_chr_be_generic_open(vc->vte.chr); - if (vc->vte.chr->init) { - vc->vte.chr->init(vc->vte.chr); - } - - return group; -} - -static void gd_vcs_init(GtkDisplayState *s, GSList *group, - GtkWidget *view_menu) -{ - int i; - - for (i = 0; i < nb_vcs; i++) { - VirtualConsole *vc = &s->vc[s->nb_vcs]; - group = gd_vc_vte_init(s, vc, vcs[i], s->nb_vcs, group, view_menu); - s->nb_vcs++; - } -} -#endif /* CONFIG_VTE */ - -/** Window Creation **/ - -static void gd_connect_vc_gfx_signals(VirtualConsole *vc) -{ -#if GTK_CHECK_VERSION(3, 0, 0) - g_signal_connect(vc->gfx.drawing_area, "draw", - G_CALLBACK(gd_draw_event), vc); -#if defined(CONFIG_GTK_GL) - if (display_opengl) { - /* wire up GtkGlArea events */ - g_signal_connect(vc->gfx.drawing_area, "render", - G_CALLBACK(gd_render_event), vc); - g_signal_connect(vc->gfx.drawing_area, "resize", - G_CALLBACK(gd_resize_event), vc); - } -#endif -#else - g_signal_connect(vc->gfx.drawing_area, "expose-event", - G_CALLBACK(gd_expose_event), vc); -#endif - if (qemu_console_is_graphic(vc->gfx.dcl.con)) { - g_signal_connect(vc->gfx.drawing_area, "event", - G_CALLBACK(gd_event), vc); - g_signal_connect(vc->gfx.drawing_area, "button-press-event", - G_CALLBACK(gd_button_event), vc); - g_signal_connect(vc->gfx.drawing_area, "button-release-event", - G_CALLBACK(gd_button_event), vc); - g_signal_connect(vc->gfx.drawing_area, "scroll-event", - G_CALLBACK(gd_scroll_event), vc); - g_signal_connect(vc->gfx.drawing_area, "key-press-event", - G_CALLBACK(gd_key_event), vc); - g_signal_connect(vc->gfx.drawing_area, "key-release-event", - G_CALLBACK(gd_key_event), vc); - - g_signal_connect(vc->gfx.drawing_area, "enter-notify-event", - G_CALLBACK(gd_enter_event), vc); - g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", - G_CALLBACK(gd_leave_event), vc); - g_signal_connect(vc->gfx.drawing_area, "focus-out-event", - G_CALLBACK(gd_focus_out_event), vc); - g_signal_connect(vc->gfx.drawing_area, "configure-event", - G_CALLBACK(gd_configure), vc); - } else { - g_signal_connect(vc->gfx.drawing_area, "key-press-event", - G_CALLBACK(gd_text_key_down), vc); - } -} - -static void gd_connect_signals(GtkDisplayState *s) -{ - g_signal_connect(s->show_tabs_item, "activate", - G_CALLBACK(gd_menu_show_tabs), s); - g_signal_connect(s->untabify_item, "activate", - G_CALLBACK(gd_menu_untabify), s); - - g_signal_connect(s->window, "delete-event", - G_CALLBACK(gd_window_close), s); - - g_signal_connect(s->pause_item, "activate", - G_CALLBACK(gd_menu_pause), s); - g_signal_connect(s->reset_item, "activate", - G_CALLBACK(gd_menu_reset), s); - g_signal_connect(s->powerdown_item, "activate", - G_CALLBACK(gd_menu_powerdown), s); - g_signal_connect(s->quit_item, "activate", - G_CALLBACK(gd_menu_quit), s); - g_signal_connect(s->full_screen_item, "activate", - G_CALLBACK(gd_menu_full_screen), s); - g_signal_connect(s->zoom_in_item, "activate", - G_CALLBACK(gd_menu_zoom_in), s); - g_signal_connect(s->zoom_out_item, "activate", - G_CALLBACK(gd_menu_zoom_out), s); - g_signal_connect(s->zoom_fixed_item, "activate", - G_CALLBACK(gd_menu_zoom_fixed), s); - g_signal_connect(s->zoom_fit_item, "activate", - G_CALLBACK(gd_menu_zoom_fit), s); - g_signal_connect(s->grab_item, "activate", - G_CALLBACK(gd_menu_grab_input), s); - g_signal_connect(s->notebook, "switch-page", - G_CALLBACK(gd_change_page), s); -} - -static GtkWidget *gd_create_menu_machine(GtkDisplayState *s) -{ - GtkWidget *machine_menu; - GtkWidget *separator; - - machine_menu = gtk_menu_new(); - gtk_menu_set_accel_group(GTK_MENU(machine_menu), s->accel_group); - - s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause")); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->pause_item); - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), separator); - - s->reset_item = gtk_menu_item_new_with_mnemonic(_("_Reset")); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->reset_item); - - s->powerdown_item = gtk_menu_item_new_with_mnemonic(_("Power _Down")); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->powerdown_item); - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), separator); - - s->quit_item = gtk_menu_item_new_with_mnemonic(_("_Quit")); - gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item), - "<QEMU>/Machine/Quit"); - gtk_accel_map_add_entry("<QEMU>/Machine/Quit", - GDK_KEY_q, HOTKEY_MODIFIERS); - gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->quit_item); - - return machine_menu; -} - -static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, - QemuConsole *con, int idx, - GSList *group, GtkWidget *view_menu) -{ - vc->label = qemu_console_get_label(con); - vc->s = s; - vc->gfx.scale_x = 1.0; - vc->gfx.scale_y = 1.0; - -#if defined(CONFIG_OPENGL) - if (display_opengl) { -#if defined(CONFIG_GTK_GL) - vc->gfx.drawing_area = gtk_gl_area_new(); - vc->gfx.dcl.ops = &dcl_gl_area_ops; -#else - vc->gfx.drawing_area = gtk_drawing_area_new(); - /* - * gtk_widget_set_double_buffered() was deprecated in 3.14. - * It is required for opengl rendering on X11 though. A - * proper replacement (native opengl support) is only - * available in 3.16+. Silence the warning if possible. - */ -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE); -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE -#pragma GCC diagnostic pop -#endif - vc->gfx.dcl.ops = &dcl_egl_ops; -#endif /* CONFIG_GTK_GL */ - } else -#endif - { - vc->gfx.drawing_area = gtk_drawing_area_new(); - vc->gfx.dcl.ops = &dcl_ops; - } - - - gtk_widget_add_events(vc->gfx.drawing_area, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_SCROLL_MASK | - GDK_KEY_PRESS_MASK); - gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE); - - vc->type = GD_VC_GFX; - vc->tab_item = vc->gfx.drawing_area; - vc->focus = vc->gfx.drawing_area; - gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), - vc->tab_item, gtk_label_new(vc->label)); - - vc->gfx.dcl.con = con; - register_displaychangelistener(&vc->gfx.dcl); - - gd_connect_vc_gfx_signals(vc); - group = gd_vc_menu_init(s, vc, idx, group, view_menu); - - if (dpy_ui_info_supported(vc->gfx.dcl.con)) { - gtk_menu_item_activate(GTK_MENU_ITEM(s->zoom_fit_item)); - s->free_scale = true; - } - - return group; -} - -static GtkWidget *gd_create_menu_view(GtkDisplayState *s) -{ - GSList *group = NULL; - GtkWidget *view_menu; - GtkWidget *separator; - QemuConsole *con; - int vc; - - view_menu = gtk_menu_new(); - gtk_menu_set_accel_group(GTK_MENU(view_menu), s->accel_group); - - s->full_screen_item = gtk_menu_item_new_with_mnemonic(_("_Fullscreen")); - - gtk_accel_group_connect(s->accel_group, GDK_KEY_f, HOTKEY_MODIFIERS, 0, - g_cclosure_new_swap(G_CALLBACK(gd_accel_full_screen), s, NULL)); -#if GTK_CHECK_VERSION(3, 8, 0) - gtk_accel_label_set_accel( - GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(s->full_screen_item))), - GDK_KEY_f, HOTKEY_MODIFIERS); -#endif - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->full_screen_item); - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator); - - s->zoom_in_item = gtk_menu_item_new_with_mnemonic(_("Zoom _In")); - gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item), - "<QEMU>/View/Zoom In"); - gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, - HOTKEY_MODIFIERS); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_in_item); - - s->zoom_out_item = gtk_menu_item_new_with_mnemonic(_("Zoom _Out")); - gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item), - "<QEMU>/View/Zoom Out"); - gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, - HOTKEY_MODIFIERS); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_out_item); - - s->zoom_fixed_item = gtk_menu_item_new_with_mnemonic(_("Best _Fit")); - gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item), - "<QEMU>/View/Zoom Fixed"); - gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, - HOTKEY_MODIFIERS); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_fixed_item); - - s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit")); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_fit_item); - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator); - - s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover")); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->grab_on_hover_item); - - s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input")); - gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item), - "<QEMU>/View/Grab Input"); - gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, - HOTKEY_MODIFIERS); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->grab_item); - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator); - - /* gfx */ - for (vc = 0;; vc++) { - con = qemu_console_lookup_by_index(vc); - if (!con) { - break; - } - group = gd_vc_gfx_init(s, &s->vc[vc], con, - vc, group, view_menu); - s->nb_vcs++; - } - -#if defined(CONFIG_VTE) - /* vte */ - gd_vcs_init(s, group, view_menu); -#endif - - separator = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator); - - s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs")); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->show_tabs_item); - - s->untabify_item = gtk_menu_item_new_with_mnemonic(_("Detach Tab")); - gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->untabify_item); - - return view_menu; -} - -static void gd_create_menus(GtkDisplayState *s) -{ - s->accel_group = gtk_accel_group_new(); - s->machine_menu = gd_create_menu_machine(s); - s->view_menu = gd_create_menu_view(s); - - s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item), - s->machine_menu); - gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->machine_menu_item); - - s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View")); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu); - gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item); - - g_object_set_data(G_OBJECT(s->window), "accel_group", s->accel_group); - gtk_window_add_accel_group(GTK_WINDOW(s->window), s->accel_group); -} - -static void gd_set_keycode_type(GtkDisplayState *s) -{ -#ifdef GDK_WINDOWING_X11 - GdkDisplay *display = gtk_widget_get_display(s->window); - if (GDK_IS_X11_DISPLAY(display)) { - Display *x11_display = gdk_x11_display_get_xdisplay(display); - XkbDescPtr desc = XkbGetKeyboard(x11_display, XkbGBN_AllComponentsMask, - XkbUseCoreKbd); - char *keycodes = NULL; - - if (desc && desc->names) { - keycodes = XGetAtomName(x11_display, desc->names->keycodes); - } - if (keycodes == NULL) { - fprintf(stderr, "could not lookup keycode name\n"); - } else if (strstart(keycodes, "evdev", NULL)) { - s->has_evdev = true; - } 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); - } - } -#endif -} - -static gboolean gtkinit; - -void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover) -{ - GtkDisplayState *s = g_malloc0(sizeof(*s)); - char *filename; - GdkDisplay *window_display; - - if (!gtkinit) { - fprintf(stderr, "gtk initialization failed\n"); - exit(1); - } - - s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); -#if GTK_CHECK_VERSION(3, 2, 0) - s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); -#else - s->vbox = gtk_vbox_new(FALSE, 0); -#endif - s->notebook = gtk_notebook_new(); - s->menu_bar = gtk_menu_bar_new(); - - s->free_scale = FALSE; - - /* LC_MESSAGES only. See early_gtk_display_init() for details */ - setlocale(LC_MESSAGES, ""); - bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR); - textdomain("qemu"); - - window_display = gtk_widget_get_display(s->window); - s->null_cursor = gdk_cursor_new_for_display(window_display, - GDK_BLANK_CURSOR); - - s->mouse_mode_notifier.notify = gd_mouse_mode_change; - qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier); - qemu_add_vm_change_state_handler(gd_change_runstate, s); - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu_logo_no_text.svg"); - if (filename) { - GError *error = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error); - if (pixbuf) { - gtk_window_set_icon(GTK_WINDOW(s->window), pixbuf); - } else { - g_error_free(error); - } - g_free(filename); - } - - gd_create_menus(s); - - gd_connect_signals(s); - - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); - gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE); - - gd_update_caption(s); - - gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(s->window), s->vbox); - - gtk_widget_show_all(s->window); - -#ifdef VTE_RESIZE_HACK - { - VirtualConsole *cur = gd_vc_find_current(s); - if (cur) { - int i; - - for (i = 0; i < s->nb_vcs; i++) { - VirtualConsole *vc = &s->vc[i]; - if (vc && vc->type == GD_VC_VTE && vc != cur) { - gtk_widget_hide(vc->vte.terminal); - } - } - gd_update_windowsize(cur); - } - } -#endif - - if (full_screen) { - gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); - } - if (grab_on_hover) { - gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item)); - } - - gd_set_keycode_type(s); -} - -void early_gtk_display_init(int opengl) -{ - /* The QEMU code relies on the assumption that it's always run in - * the C locale. Therefore it is not prepared to deal with - * operations that produce different results depending on the - * locale, such as printf's formatting of decimal numbers, and - * possibly others. - * - * Since GTK+ calls setlocale() by default -importing the locale - * settings from the environment- we must prevent it from doing so - * using gtk_disable_setlocale(). - * - * QEMU's GTK+ UI, however, _does_ have translations for some of - * the menu items. As a trade-off between a functionally correct - * QEMU and a fully internationalized UI we support importing - * LC_MESSAGES from the environment (see the setlocale() call - * earlier in this file). This allows us to display translated - * messages leaving everything else untouched. - */ - gtk_disable_setlocale(); - gtkinit = gtk_init_check(NULL, NULL); - if (!gtkinit) { - /* don't exit yet, that'll break -help */ - return; - } - - switch (opengl) { - case -1: /* default */ - case 0: /* off */ - break; - case 1: /* on */ -#if defined(CONFIG_OPENGL) -#if defined(CONFIG_GTK_GL) - gtk_gl_area_init(); -#else - gtk_egl_init(); -#endif -#endif - break; - default: - g_assert_not_reached(); - break; - } - -#if defined(CONFIG_VTE) - register_vc_handler(gd_vc_handler); -#endif -} diff --git a/qemu/ui/input-keymap.c b/qemu/ui/input-keymap.c deleted file mode 100644 index f1e700d72..000000000 --- a/qemu/ui/input-keymap.c +++ /dev/null @@ -1,203 +0,0 @@ -#include "qemu/osdep.h" -#include "sysemu/sysemu.h" -#include "ui/keymaps.h" -#include "ui/input.h" - -static const int qcode_to_number[] = { - [Q_KEY_CODE_SHIFT] = 0x2a, - [Q_KEY_CODE_SHIFT_R] = 0x36, - - [Q_KEY_CODE_ALT] = 0x38, - [Q_KEY_CODE_ALT_R] = 0xb8, - [Q_KEY_CODE_ALTGR] = 0x64, - [Q_KEY_CODE_ALTGR_R] = 0xe4, - [Q_KEY_CODE_CTRL] = 0x1d, - [Q_KEY_CODE_CTRL_R] = 0x9d, - - [Q_KEY_CODE_META_L] = 0xdb, - [Q_KEY_CODE_META_R] = 0xdc, - [Q_KEY_CODE_MENU] = 0xdd, - - [Q_KEY_CODE_ESC] = 0x01, - - [Q_KEY_CODE_1] = 0x02, - [Q_KEY_CODE_2] = 0x03, - [Q_KEY_CODE_3] = 0x04, - [Q_KEY_CODE_4] = 0x05, - [Q_KEY_CODE_5] = 0x06, - [Q_KEY_CODE_6] = 0x07, - [Q_KEY_CODE_7] = 0x08, - [Q_KEY_CODE_8] = 0x09, - [Q_KEY_CODE_9] = 0x0a, - [Q_KEY_CODE_0] = 0x0b, - [Q_KEY_CODE_MINUS] = 0x0c, - [Q_KEY_CODE_EQUAL] = 0x0d, - [Q_KEY_CODE_BACKSPACE] = 0x0e, - - [Q_KEY_CODE_TAB] = 0x0f, - [Q_KEY_CODE_Q] = 0x10, - [Q_KEY_CODE_W] = 0x11, - [Q_KEY_CODE_E] = 0x12, - [Q_KEY_CODE_R] = 0x13, - [Q_KEY_CODE_T] = 0x14, - [Q_KEY_CODE_Y] = 0x15, - [Q_KEY_CODE_U] = 0x16, - [Q_KEY_CODE_I] = 0x17, - [Q_KEY_CODE_O] = 0x18, - [Q_KEY_CODE_P] = 0x19, - [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, - [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, - [Q_KEY_CODE_RET] = 0x1c, - - [Q_KEY_CODE_A] = 0x1e, - [Q_KEY_CODE_S] = 0x1f, - [Q_KEY_CODE_D] = 0x20, - [Q_KEY_CODE_F] = 0x21, - [Q_KEY_CODE_G] = 0x22, - [Q_KEY_CODE_H] = 0x23, - [Q_KEY_CODE_J] = 0x24, - [Q_KEY_CODE_K] = 0x25, - [Q_KEY_CODE_L] = 0x26, - [Q_KEY_CODE_SEMICOLON] = 0x27, - [Q_KEY_CODE_APOSTROPHE] = 0x28, - [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, - - [Q_KEY_CODE_BACKSLASH] = 0x2b, - [Q_KEY_CODE_Z] = 0x2c, - [Q_KEY_CODE_X] = 0x2d, - [Q_KEY_CODE_C] = 0x2e, - [Q_KEY_CODE_V] = 0x2f, - [Q_KEY_CODE_B] = 0x30, - [Q_KEY_CODE_N] = 0x31, - [Q_KEY_CODE_M] = 0x32, - [Q_KEY_CODE_COMMA] = 0x33, - [Q_KEY_CODE_DOT] = 0x34, - [Q_KEY_CODE_SLASH] = 0x35, - - [Q_KEY_CODE_ASTERISK] = 0x37, - - [Q_KEY_CODE_SPC] = 0x39, - [Q_KEY_CODE_CAPS_LOCK] = 0x3a, - [Q_KEY_CODE_F1] = 0x3b, - [Q_KEY_CODE_F2] = 0x3c, - [Q_KEY_CODE_F3] = 0x3d, - [Q_KEY_CODE_F4] = 0x3e, - [Q_KEY_CODE_F5] = 0x3f, - [Q_KEY_CODE_F6] = 0x40, - [Q_KEY_CODE_F7] = 0x41, - [Q_KEY_CODE_F8] = 0x42, - [Q_KEY_CODE_F9] = 0x43, - [Q_KEY_CODE_F10] = 0x44, - [Q_KEY_CODE_NUM_LOCK] = 0x45, - [Q_KEY_CODE_SCROLL_LOCK] = 0x46, - - [Q_KEY_CODE_KP_DIVIDE] = 0xb5, - [Q_KEY_CODE_KP_MULTIPLY] = 0x37, - [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, - [Q_KEY_CODE_KP_ADD] = 0x4e, - [Q_KEY_CODE_KP_ENTER] = 0x9c, - [Q_KEY_CODE_KP_DECIMAL] = 0x53, - [Q_KEY_CODE_SYSRQ] = 0x54, - - [Q_KEY_CODE_KP_0] = 0x52, - [Q_KEY_CODE_KP_1] = 0x4f, - [Q_KEY_CODE_KP_2] = 0x50, - [Q_KEY_CODE_KP_3] = 0x51, - [Q_KEY_CODE_KP_4] = 0x4b, - [Q_KEY_CODE_KP_5] = 0x4c, - [Q_KEY_CODE_KP_6] = 0x4d, - [Q_KEY_CODE_KP_7] = 0x47, - [Q_KEY_CODE_KP_8] = 0x48, - [Q_KEY_CODE_KP_9] = 0x49, - - [Q_KEY_CODE_LESS] = 0x56, - - [Q_KEY_CODE_F11] = 0x57, - [Q_KEY_CODE_F12] = 0x58, - - [Q_KEY_CODE_PRINT] = 0xb7, - - [Q_KEY_CODE_HOME] = 0xc7, - [Q_KEY_CODE_PGUP] = 0xc9, - [Q_KEY_CODE_PGDN] = 0xd1, - [Q_KEY_CODE_END] = 0xcf, - - [Q_KEY_CODE_LEFT] = 0xcb, - [Q_KEY_CODE_UP] = 0xc8, - [Q_KEY_CODE_DOWN] = 0xd0, - [Q_KEY_CODE_RIGHT] = 0xcd, - - [Q_KEY_CODE_INSERT] = 0xd2, - [Q_KEY_CODE_DELETE] = 0xd3, - - [Q_KEY_CODE_RO] = 0x73, - [Q_KEY_CODE_KP_COMMA] = 0x7e, - - [Q_KEY_CODE__MAX] = 0, -}; - -static int number_to_qcode[0x100]; - -int qemu_input_key_value_to_number(const KeyValue *value) -{ - if (value->type == KEY_VALUE_KIND_QCODE) { - return qcode_to_number[value->u.qcode.data]; - } else { - assert(value->type == KEY_VALUE_KIND_NUMBER); - return value->u.number.data; - } -} - -int qemu_input_key_number_to_qcode(uint8_t nr) -{ - static int first = true; - - if (first) { - int qcode, number; - first = false; - for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) { - number = qcode_to_number[qcode]; - assert(number < ARRAY_SIZE(number_to_qcode)); - number_to_qcode[number] = qcode; - } - } - - return number_to_qcode[nr]; -} - -int qemu_input_key_value_to_qcode(const KeyValue *value) -{ - if (value->type == KEY_VALUE_KIND_QCODE) { - return value->u.qcode.data; - } else { - assert(value->type == KEY_VALUE_KIND_NUMBER); - return qemu_input_key_number_to_qcode(value->u.number.data); - } -} - -int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, - int *codes) -{ - int keycode = qemu_input_key_value_to_number(value); - int count = 0; - - if (value->type == KEY_VALUE_KIND_QCODE && - value->u.qcode.data == Q_KEY_CODE_PAUSE) { - /* specific case */ - int v = down ? 0 : 0x80; - codes[count++] = 0xe1; - codes[count++] = 0x1d | v; - codes[count++] = 0x45 | v; - return count; - } - if (keycode & SCANCODE_GREY) { - codes[count++] = SCANCODE_EMUL0; - keycode &= ~SCANCODE_GREY; - } - if (!down) { - keycode |= SCANCODE_UP; - } - codes[count++] = keycode; - - return count; -} diff --git a/qemu/ui/input-legacy.c b/qemu/ui/input-legacy.c deleted file mode 100644 index 715974740..000000000 --- a/qemu/ui/input-legacy.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 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/osdep.h" -#include "sysemu/sysemu.h" -#include "ui/console.h" -#include "qmp-commands.h" -#include "qapi-types.h" -#include "ui/keymaps.h" -#include "ui/input.h" - -struct QEMUPutMouseEntry { - QEMUPutMouseEvent *qemu_put_mouse_event; - void *qemu_put_mouse_event_opaque; - int qemu_put_mouse_event_absolute; - - /* new input core */ - QemuInputHandler h; - QemuInputHandlerState *s; - int axis[INPUT_AXIS__MAX]; - int buttons; -}; - -struct QEMUPutKbdEntry { - QEMUPutKBDEvent *put_kbd; - void *opaque; - QemuInputHandlerState *s; -}; - -struct QEMUPutLEDEntry { - QEMUPutLEDEvent *put_led; - void *opaque; - QTAILQ_ENTRY(QEMUPutLEDEntry) next; -}; - -static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = - QTAILQ_HEAD_INITIALIZER(led_handlers); - -int index_from_key(const char *key, size_t key_length) -{ - int i; - - for (i = 0; QKeyCode_lookup[i] != NULL; i++) { - if (!strncmp(key, QKeyCode_lookup[i], key_length) && - !QKeyCode_lookup[i][key_length]) { - break; - } - } - - /* Return Q_KEY_CODE__MAX if the key is invalid */ - return i; -} - -static KeyValue *copy_key_value(KeyValue *src) -{ - KeyValue *dst = g_new(KeyValue, 1); - memcpy(dst, src, sizeof(*src)); - return dst; -} - -void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, - Error **errp) -{ - KeyValueList *p; - KeyValue **up = NULL; - int count = 0; - - if (!has_hold_time) { - hold_time = 0; /* use default */ - } - - for (p = keys; p != NULL; p = p->next) { - qemu_input_event_send_key(NULL, copy_key_value(p->value), true); - qemu_input_event_send_key_delay(hold_time); - up = g_realloc(up, sizeof(*up) * (count+1)); - up[count] = copy_key_value(p->value); - count++; - } - while (count) { - count--; - qemu_input_event_send_key(NULL, up[count], false); - qemu_input_event_send_key_delay(hold_time); - } - g_free(up); -} - -static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; - int scancodes[3], i, count; - InputKeyEvent *key = evt->u.key.data; - - if (!entry || !entry->put_kbd) { - return; - } - count = qemu_input_key_value_to_scancode(key->key, - key->down, - scancodes); - for (i = 0; i < count; i++) { - entry->put_kbd(entry->opaque, scancodes[i]); - } -} - -static QemuInputHandler legacy_kbd_handler = { - .name = "legacy-kbd", - .mask = INPUT_EVENT_MASK_KEY, - .event = legacy_kbd_event, -}; - -QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) -{ - QEMUPutKbdEntry *entry; - - entry = g_new0(QEMUPutKbdEntry, 1); - entry->put_kbd = func; - entry->opaque = opaque; - entry->s = qemu_input_handler_register((DeviceState *)entry, - &legacy_kbd_handler); - qemu_input_handler_activate(entry->s); - return entry; -} - -static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - static const int bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, - [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, - [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, - }; - QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; - InputBtnEvent *btn; - InputMoveEvent *move; - - switch (evt->type) { - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - if (btn->down) { - s->buttons |= bmap[btn->button]; - } else { - s->buttons &= ~bmap[btn->button]; - } - if (btn->down && btn->button == INPUT_BUTTON_WHEEL_UP) { - s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, - s->axis[INPUT_AXIS_X], - s->axis[INPUT_AXIS_Y], - -1, - s->buttons); - } - if (btn->down && btn->button == INPUT_BUTTON_WHEEL_DOWN) { - s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, - s->axis[INPUT_AXIS_X], - s->axis[INPUT_AXIS_Y], - 1, - s->buttons); - } - break; - case INPUT_EVENT_KIND_ABS: - move = evt->u.abs.data; - s->axis[move->axis] = move->value; - break; - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - s->axis[move->axis] += move->value; - break; - default: - break; - } -} - -static void legacy_mouse_sync(DeviceState *dev) -{ - QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; - - s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, - s->axis[INPUT_AXIS_X], - s->axis[INPUT_AXIS_Y], - 0, - s->buttons); - - if (!s->qemu_put_mouse_event_absolute) { - s->axis[INPUT_AXIS_X] = 0; - s->axis[INPUT_AXIS_Y] = 0; - } -} - -QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, - void *opaque, int absolute, - const char *name) -{ - QEMUPutMouseEntry *s; - - s = g_new0(QEMUPutMouseEntry, 1); - - s->qemu_put_mouse_event = func; - s->qemu_put_mouse_event_opaque = opaque; - s->qemu_put_mouse_event_absolute = absolute; - - s->h.name = name; - s->h.mask = INPUT_EVENT_MASK_BTN | - (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL); - s->h.event = legacy_mouse_event; - s->h.sync = legacy_mouse_sync; - s->s = qemu_input_handler_register((DeviceState *)s, - &s->h); - - return s; -} - -void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) -{ - qemu_input_handler_activate(entry->s); -} - -void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) -{ - qemu_input_handler_unregister(entry->s); - - g_free(entry); -} - -QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, - void *opaque) -{ - QEMUPutLEDEntry *s; - - s = g_new0(QEMUPutLEDEntry, 1); - - s->put_led = func; - s->opaque = opaque; - QTAILQ_INSERT_TAIL(&led_handlers, s, next); - return s; -} - -void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) -{ - if (entry == NULL) - return; - QTAILQ_REMOVE(&led_handlers, entry, next); - g_free(entry); -} - -void kbd_put_ledstate(int ledstate) -{ - QEMUPutLEDEntry *cursor; - - QTAILQ_FOREACH(cursor, &led_handlers, next) { - cursor->put_led(cursor->opaque, ledstate); - } -} diff --git a/qemu/ui/input-linux.c b/qemu/ui/input-linux.c deleted file mode 100644 index 1d33b5c12..000000000 --- a/qemu/ui/input-linux.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/config-file.h" -#include "qemu/sockets.h" -#include "sysemu/sysemu.h" -#include "ui/input.h" -#include "qom/object_interfaces.h" - -#include <sys/ioctl.h> -#include "standard-headers/linux/input.h" - -static int linux_to_qcode[KEY_CNT] = { - [KEY_ESC] = Q_KEY_CODE_ESC, - [KEY_1] = Q_KEY_CODE_1, - [KEY_2] = Q_KEY_CODE_2, - [KEY_3] = Q_KEY_CODE_3, - [KEY_4] = Q_KEY_CODE_4, - [KEY_5] = Q_KEY_CODE_5, - [KEY_6] = Q_KEY_CODE_6, - [KEY_7] = Q_KEY_CODE_7, - [KEY_8] = Q_KEY_CODE_8, - [KEY_9] = Q_KEY_CODE_9, - [KEY_0] = Q_KEY_CODE_0, - [KEY_MINUS] = Q_KEY_CODE_MINUS, - [KEY_EQUAL] = Q_KEY_CODE_EQUAL, - [KEY_BACKSPACE] = Q_KEY_CODE_BACKSPACE, - [KEY_TAB] = Q_KEY_CODE_TAB, - [KEY_Q] = Q_KEY_CODE_Q, - [KEY_W] = Q_KEY_CODE_W, - [KEY_E] = Q_KEY_CODE_E, - [KEY_R] = Q_KEY_CODE_R, - [KEY_T] = Q_KEY_CODE_T, - [KEY_Y] = Q_KEY_CODE_Y, - [KEY_U] = Q_KEY_CODE_U, - [KEY_I] = Q_KEY_CODE_I, - [KEY_O] = Q_KEY_CODE_O, - [KEY_P] = Q_KEY_CODE_P, - [KEY_LEFTBRACE] = Q_KEY_CODE_BRACKET_LEFT, - [KEY_RIGHTBRACE] = Q_KEY_CODE_BRACKET_RIGHT, - [KEY_ENTER] = Q_KEY_CODE_RET, - [KEY_LEFTCTRL] = Q_KEY_CODE_CTRL, - [KEY_A] = Q_KEY_CODE_A, - [KEY_S] = Q_KEY_CODE_S, - [KEY_D] = Q_KEY_CODE_D, - [KEY_F] = Q_KEY_CODE_F, - [KEY_G] = Q_KEY_CODE_G, - [KEY_H] = Q_KEY_CODE_H, - [KEY_J] = Q_KEY_CODE_J, - [KEY_K] = Q_KEY_CODE_K, - [KEY_L] = Q_KEY_CODE_L, - [KEY_SEMICOLON] = Q_KEY_CODE_SEMICOLON, - [KEY_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE, - [KEY_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT, - [KEY_LEFTSHIFT] = Q_KEY_CODE_SHIFT, - [KEY_BACKSLASH] = Q_KEY_CODE_BACKSLASH, - [KEY_102ND] = Q_KEY_CODE_LESS, - [KEY_Z] = Q_KEY_CODE_Z, - [KEY_X] = Q_KEY_CODE_X, - [KEY_C] = Q_KEY_CODE_C, - [KEY_V] = Q_KEY_CODE_V, - [KEY_B] = Q_KEY_CODE_B, - [KEY_N] = Q_KEY_CODE_N, - [KEY_M] = Q_KEY_CODE_M, - [KEY_COMMA] = Q_KEY_CODE_COMMA, - [KEY_DOT] = Q_KEY_CODE_DOT, - [KEY_SLASH] = Q_KEY_CODE_SLASH, - [KEY_RIGHTSHIFT] = Q_KEY_CODE_SHIFT_R, - [KEY_LEFTALT] = Q_KEY_CODE_ALT, - [KEY_SPACE] = Q_KEY_CODE_SPC, - [KEY_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK, - [KEY_F1] = Q_KEY_CODE_F1, - [KEY_F2] = Q_KEY_CODE_F2, - [KEY_F3] = Q_KEY_CODE_F3, - [KEY_F4] = Q_KEY_CODE_F4, - [KEY_F5] = Q_KEY_CODE_F5, - [KEY_F6] = Q_KEY_CODE_F6, - [KEY_F7] = Q_KEY_CODE_F7, - [KEY_F8] = Q_KEY_CODE_F8, - [KEY_F9] = Q_KEY_CODE_F9, - [KEY_F10] = Q_KEY_CODE_F10, - [KEY_NUMLOCK] = Q_KEY_CODE_NUM_LOCK, - [KEY_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK, - [KEY_KP0] = Q_KEY_CODE_KP_0, - [KEY_KP1] = Q_KEY_CODE_KP_1, - [KEY_KP2] = Q_KEY_CODE_KP_2, - [KEY_KP3] = Q_KEY_CODE_KP_3, - [KEY_KP4] = Q_KEY_CODE_KP_4, - [KEY_KP5] = Q_KEY_CODE_KP_5, - [KEY_KP6] = Q_KEY_CODE_KP_6, - [KEY_KP7] = Q_KEY_CODE_KP_7, - [KEY_KP8] = Q_KEY_CODE_KP_8, - [KEY_KP9] = Q_KEY_CODE_KP_9, - [KEY_KPMINUS] = Q_KEY_CODE_KP_SUBTRACT, - [KEY_KPPLUS] = Q_KEY_CODE_KP_ADD, - [KEY_KPDOT] = Q_KEY_CODE_KP_DECIMAL, - [KEY_KPENTER] = Q_KEY_CODE_KP_ENTER, - [KEY_KPSLASH] = Q_KEY_CODE_KP_DIVIDE, - [KEY_KPASTERISK] = Q_KEY_CODE_KP_MULTIPLY, - [KEY_F11] = Q_KEY_CODE_F11, - [KEY_F12] = Q_KEY_CODE_F12, - [KEY_RIGHTCTRL] = Q_KEY_CODE_CTRL_R, - [KEY_SYSRQ] = Q_KEY_CODE_SYSRQ, - [KEY_RIGHTALT] = Q_KEY_CODE_ALT_R, - [KEY_HOME] = Q_KEY_CODE_HOME, - [KEY_UP] = Q_KEY_CODE_UP, - [KEY_PAGEUP] = Q_KEY_CODE_PGUP, - [KEY_LEFT] = Q_KEY_CODE_LEFT, - [KEY_RIGHT] = Q_KEY_CODE_RIGHT, - [KEY_END] = Q_KEY_CODE_END, - [KEY_DOWN] = Q_KEY_CODE_DOWN, - [KEY_PAGEDOWN] = Q_KEY_CODE_PGDN, - [KEY_INSERT] = Q_KEY_CODE_INSERT, - [KEY_DELETE] = Q_KEY_CODE_DELETE, - [KEY_LEFTMETA] = Q_KEY_CODE_META_L, - [KEY_RIGHTMETA] = Q_KEY_CODE_META_R, - [KEY_MENU] = Q_KEY_CODE_MENU, -}; - -static int qemu_input_linux_to_qcode(unsigned int lnx) -{ - assert(lnx < KEY_CNT); - return linux_to_qcode[lnx]; -} - -#define TYPE_INPUT_LINUX "input-linux" -#define INPUT_LINUX(obj) \ - OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX) -#define INPUT_LINUX_GET_CLASS(obj) \ - OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX) -#define INPUT_LINUX_CLASS(klass) \ - OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX) - -typedef struct InputLinux InputLinux; -typedef struct InputLinuxClass InputLinuxClass; - -struct InputLinux { - Object parent; - - char *evdev; - int fd; - bool repeat; - bool grab_request; - bool grab_active; - bool grab_all; - bool keydown[KEY_CNT]; - int keycount; - int wheel; - bool initialized; - QTAILQ_ENTRY(InputLinux) next; -}; - -struct InputLinuxClass { - ObjectClass parent_class; -}; - -static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs); - -static void input_linux_toggle_grab(InputLinux *il) -{ - intptr_t request = !il->grab_active; - InputLinux *item; - int rc; - - rc = ioctl(il->fd, EVIOCGRAB, request); - if (rc < 0) { - return; - } - il->grab_active = !il->grab_active; - - if (!il->grab_all) { - return; - } - QTAILQ_FOREACH(item, &inputs, next) { - if (item == il || item->grab_all) { - /* avoid endless loops */ - continue; - } - if (item->grab_active != il->grab_active) { - input_linux_toggle_grab(item); - } - } -} - -static void input_linux_event_keyboard(void *opaque) -{ - InputLinux *il = opaque; - struct input_event event; - int rc; - - for (;;) { - rc = read(il->fd, &event, sizeof(event)); - if (rc != sizeof(event)) { - if (rc < 0 && errno != EAGAIN) { - fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); - qemu_set_fd_handler(il->fd, NULL, NULL, NULL); - close(il->fd); - } - break; - } - - switch (event.type) { - case EV_KEY: - if (event.value > 2 || (event.value > 1 && !il->repeat)) { - /* - * ignore autorepeat + unknown key events - * 0 == up, 1 == down, 2 == autorepeat, other == undefined - */ - continue; - } - if (event.code >= KEY_CNT) { - /* - * Should not happen. But better safe than sorry, - * and we make Coverity happy too. - */ - continue; - } - /* keep track of key state */ - if (!il->keydown[event.code] && event.value) { - il->keydown[event.code] = true; - il->keycount++; - } - if (il->keydown[event.code] && !event.value) { - il->keydown[event.code] = false; - il->keycount--; - } - - /* send event to guest when grab is active */ - if (il->grab_active) { - int qcode = qemu_input_linux_to_qcode(event.code); - qemu_input_event_send_key_qcode(NULL, qcode, event.value); - } - - /* hotkey -> record switch request ... */ - if (il->keydown[KEY_LEFTCTRL] && - il->keydown[KEY_RIGHTCTRL]) { - il->grab_request = true; - } - - /* - * ... and do the switch when all keys are lifted, so we - * confuse neither guest nor host with keys which seem to - * be stuck due to missing key-up events. - */ - if (il->grab_request && !il->keycount) { - il->grab_request = false; - input_linux_toggle_grab(il); - } - break; - } - } -} - -static void input_linux_event_mouse_button(int button) -{ - qemu_input_queue_btn(NULL, button, true); - qemu_input_event_sync(); - qemu_input_queue_btn(NULL, button, false); - qemu_input_event_sync(); -} - -static void input_linux_event_mouse(void *opaque) -{ - InputLinux *il = opaque; - struct input_event event; - int rc; - - for (;;) { - rc = read(il->fd, &event, sizeof(event)); - if (rc != sizeof(event)) { - if (rc < 0 && errno != EAGAIN) { - fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); - qemu_set_fd_handler(il->fd, NULL, NULL, NULL); - close(il->fd); - } - break; - } - - /* only send event to guest when grab is active */ - if (!il->grab_active) { - continue; - } - - switch (event.type) { - case EV_KEY: - switch (event.code) { - case BTN_LEFT: - qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event.value); - break; - case BTN_RIGHT: - qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event.value); - break; - case BTN_MIDDLE: - qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event.value); - break; - case BTN_GEAR_UP: - qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event.value); - break; - case BTN_GEAR_DOWN: - qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN, - event.value); - break; - }; - break; - case EV_REL: - switch (event.code) { - case REL_X: - qemu_input_queue_rel(NULL, INPUT_AXIS_X, event.value); - break; - case REL_Y: - qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event.value); - break; - case REL_WHEEL: - il->wheel = event.value; - break; - } - break; - case EV_SYN: - qemu_input_event_sync(); - if (il->wheel != 0) { - input_linux_event_mouse_button((il->wheel > 0) - ? INPUT_BUTTON_WHEEL_UP - : INPUT_BUTTON_WHEEL_DOWN); - il->wheel = 0; - } - break; - } - } -} - -static void input_linux_complete(UserCreatable *uc, Error **errp) -{ - InputLinux *il = INPUT_LINUX(uc); - uint32_t evtmap, relmap, absmap; - int rc, ver; - - if (!il->evdev) { - error_setg(errp, "no input device specified"); - return; - } - - il->fd = open(il->evdev, O_RDWR); - if (il->fd < 0) { - error_setg_file_open(errp, errno, il->evdev); - return; - } - qemu_set_nonblock(il->fd); - - rc = ioctl(il->fd, EVIOCGVERSION, &ver); - if (rc < 0) { - error_setg(errp, "%s: is not an evdev device", il->evdev); - goto err_close; - } - - rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); - if (rc < 0) { - error_setg(errp, "%s: failed to read event bits", il->evdev); - goto err_close; - } - - if (evtmap & (1 << EV_REL)) { - rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); - if (rc < 0) { - relmap = 0; - } - } - - if (evtmap & (1 << EV_ABS)) { - ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); - if (rc < 0) { - absmap = 0; - } - } - - if ((evtmap & (1 << EV_REL)) && - (relmap & (1 << REL_X))) { - /* has relative x axis -> assume mouse */ - qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il); - } else if ((evtmap & (1 << EV_ABS)) && - (absmap & (1 << ABS_X))) { - /* has absolute x axis -> not supported */ - error_setg(errp, "tablet/touchscreen not supported"); - goto err_close; - } else if (evtmap & (1 << EV_KEY)) { - /* has keys/buttons (and no x axis) -> assume keyboard */ - qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il); - } else { - /* Huh? What is this? */ - error_setg(errp, "unknown kind of input device"); - goto err_close; - } - input_linux_toggle_grab(il); - QTAILQ_INSERT_TAIL(&inputs, il, next); - il->initialized = true; - return; - -err_close: - close(il->fd); - return; -} - -static void input_linux_instance_finalize(Object *obj) -{ - InputLinux *il = INPUT_LINUX(obj); - - if (il->initialized) { - QTAILQ_REMOVE(&inputs, il, next); - close(il->fd); - } - g_free(il->evdev); -} - -static char *input_linux_get_evdev(Object *obj, Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - return g_strdup(il->evdev); -} - -static void input_linux_set_evdev(Object *obj, const char *value, - Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - if (il->evdev) { - error_setg(errp, "evdev property already set"); - return; - } - il->evdev = g_strdup(value); -} - -static bool input_linux_get_grab_all(Object *obj, Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - return il->grab_all; -} - -static void input_linux_set_grab_all(Object *obj, bool value, - Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - il->grab_all = value; -} - -static bool input_linux_get_repeat(Object *obj, Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - return il->repeat; -} - -static void input_linux_set_repeat(Object *obj, bool value, - Error **errp) -{ - InputLinux *il = INPUT_LINUX(obj); - - il->repeat = value; -} - -static void input_linux_instance_init(Object *obj) -{ - object_property_add_str(obj, "evdev", - input_linux_get_evdev, - input_linux_set_evdev, NULL); - object_property_add_bool(obj, "grab_all", - input_linux_get_grab_all, - input_linux_set_grab_all, NULL); - object_property_add_bool(obj, "repeat", - input_linux_get_repeat, - input_linux_set_repeat, NULL); -} - -static void input_linux_class_init(ObjectClass *oc, void *data) -{ - UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); - - ucc->complete = input_linux_complete; -} - -static const TypeInfo input_linux_info = { - .name = TYPE_INPUT_LINUX, - .parent = TYPE_OBJECT, - .class_size = sizeof(InputLinuxClass), - .class_init = input_linux_class_init, - .instance_size = sizeof(InputLinux), - .instance_init = input_linux_instance_init, - .instance_finalize = input_linux_instance_finalize, - .interfaces = (InterfaceInfo[]) { - { TYPE_USER_CREATABLE }, - { } - } -}; - -static void register_types(void) -{ - type_register_static(&input_linux_info); -} - -type_init(register_types); diff --git a/qemu/ui/input.c b/qemu/ui/input.c deleted file mode 100644 index ed88cda6d..000000000 --- a/qemu/ui/input.c +++ /dev/null @@ -1,574 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/qdev.h" -#include "sysemu/sysemu.h" -#include "qapi-types.h" -#include "qemu/error-report.h" -#include "qmp-commands.h" -#include "trace.h" -#include "ui/input.h" -#include "ui/console.h" -#include "sysemu/replay.h" - -struct QemuInputHandlerState { - DeviceState *dev; - QemuInputHandler *handler; - int id; - int events; - QemuConsole *con; - QTAILQ_ENTRY(QemuInputHandlerState) node; -}; - -typedef struct QemuInputEventQueue QemuInputEventQueue; -struct QemuInputEventQueue { - enum { - QEMU_INPUT_QUEUE_DELAY = 1, - QEMU_INPUT_QUEUE_EVENT, - QEMU_INPUT_QUEUE_SYNC, - } type; - QEMUTimer *timer; - uint32_t delay_ms; - QemuConsole *src; - InputEvent *evt; - QTAILQ_ENTRY(QemuInputEventQueue) node; -}; - -static QTAILQ_HEAD(, QemuInputHandlerState) handlers = - QTAILQ_HEAD_INITIALIZER(handlers); -static NotifierList mouse_mode_notifiers = - NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); - -static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue = - QTAILQ_HEAD_INITIALIZER(kbd_queue); -static QEMUTimer *kbd_timer; -static uint32_t kbd_default_delay_ms = 10; - -QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, - QemuInputHandler *handler) -{ - QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1); - static int id = 1; - - s->dev = dev; - s->handler = handler; - s->id = id++; - QTAILQ_INSERT_TAIL(&handlers, s, node); - - qemu_input_check_mode_change(); - return s; -} - -void qemu_input_handler_activate(QemuInputHandlerState *s) -{ - QTAILQ_REMOVE(&handlers, s, node); - QTAILQ_INSERT_HEAD(&handlers, s, node); - qemu_input_check_mode_change(); -} - -void qemu_input_handler_deactivate(QemuInputHandlerState *s) -{ - QTAILQ_REMOVE(&handlers, s, node); - QTAILQ_INSERT_TAIL(&handlers, s, node); - qemu_input_check_mode_change(); -} - -void qemu_input_handler_unregister(QemuInputHandlerState *s) -{ - QTAILQ_REMOVE(&handlers, s, node); - g_free(s); - qemu_input_check_mode_change(); -} - -void qemu_input_handler_bind(QemuInputHandlerState *s, - const char *device_id, int head, - Error **errp) -{ - QemuConsole *con; - Error *err = NULL; - - con = qemu_console_lookup_by_device_name(device_id, head, &err); - if (err) { - error_propagate(errp, err); - return; - } - - s->con = con; -} - -static QemuInputHandlerState* -qemu_input_find_handler(uint32_t mask, QemuConsole *con) -{ - QemuInputHandlerState *s; - - QTAILQ_FOREACH(s, &handlers, node) { - if (s->con == NULL || s->con != con) { - continue; - } - if (mask & s->handler->mask) { - return s; - } - } - - QTAILQ_FOREACH(s, &handlers, node) { - if (s->con != NULL) { - continue; - } - if (mask & s->handler->mask) { - return s; - } - } - return NULL; -} - -void qmp_input_send_event(bool has_device, const char *device, - bool has_head, int64_t head, - InputEventList *events, Error **errp) -{ - InputEventList *e; - QemuConsole *con; - Error *err = NULL; - - con = NULL; - if (has_device) { - if (!has_head) { - head = 0; - } - con = qemu_console_lookup_by_device_name(device, head, &err); - if (err) { - error_propagate(errp, err); - return; - } - } - - if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { - error_setg(errp, "VM not running"); - return; - } - - for (e = events; e != NULL; e = e->next) { - InputEvent *event = e->value; - - if (!qemu_input_find_handler(1 << event->type, con)) { - error_setg(errp, "Input handler not found for " - "event type %s", - InputEventKind_lookup[event->type]); - return; - } - } - - for (e = events; e != NULL; e = e->next) { - InputEvent *event = e->value; - - qemu_input_event_send(con, event); - } - - qemu_input_event_sync(); -} - -static void qemu_input_transform_abs_rotate(InputEvent *evt) -{ - InputMoveEvent *move = evt->u.abs.data; - switch (graphic_rotate) { - case 90: - if (move->axis == INPUT_AXIS_X) { - move->axis = INPUT_AXIS_Y; - } else if (move->axis == INPUT_AXIS_Y) { - move->axis = INPUT_AXIS_X; - move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; - } - break; - case 180: - move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; - break; - case 270: - if (move->axis == INPUT_AXIS_X) { - move->axis = INPUT_AXIS_Y; - move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; - } else if (move->axis == INPUT_AXIS_Y) { - move->axis = INPUT_AXIS_X; - } - break; - } -} - -static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) -{ - const char *name; - int qcode, idx = -1; - InputKeyEvent *key; - InputBtnEvent *btn; - InputMoveEvent *move; - - if (src) { - idx = qemu_console_get_index(src); - } - switch (evt->type) { - case INPUT_EVENT_KIND_KEY: - key = evt->u.key.data; - switch (key->key->type) { - case KEY_VALUE_KIND_NUMBER: - qcode = qemu_input_key_number_to_qcode(key->key->u.number.data); - name = QKeyCode_lookup[qcode]; - trace_input_event_key_number(idx, key->key->u.number.data, - name, key->down); - break; - case KEY_VALUE_KIND_QCODE: - name = QKeyCode_lookup[key->key->u.qcode.data]; - trace_input_event_key_qcode(idx, name, key->down); - break; - case KEY_VALUE_KIND__MAX: - /* keep gcc happy */ - break; - } - break; - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - name = InputButton_lookup[btn->button]; - trace_input_event_btn(idx, name, btn->down); - break; - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - name = InputAxis_lookup[move->axis]; - trace_input_event_rel(idx, name, move->value); - break; - case INPUT_EVENT_KIND_ABS: - move = evt->u.abs.data; - name = InputAxis_lookup[move->axis]; - trace_input_event_abs(idx, name, move->value); - break; - case INPUT_EVENT_KIND__MAX: - /* keep gcc happy */ - break; - } -} - -static void qemu_input_queue_process(void *opaque) -{ - struct QemuInputEventQueueHead *queue = opaque; - QemuInputEventQueue *item; - - g_assert(!QTAILQ_EMPTY(queue)); - item = QTAILQ_FIRST(queue); - g_assert(item->type == QEMU_INPUT_QUEUE_DELAY); - QTAILQ_REMOVE(queue, item, node); - g_free(item); - - while (!QTAILQ_EMPTY(queue)) { - item = QTAILQ_FIRST(queue); - switch (item->type) { - case QEMU_INPUT_QUEUE_DELAY: - timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) - + item->delay_ms); - return; - case QEMU_INPUT_QUEUE_EVENT: - qemu_input_event_send(item->src, item->evt); - qapi_free_InputEvent(item->evt); - break; - case QEMU_INPUT_QUEUE_SYNC: - qemu_input_event_sync(); - break; - } - QTAILQ_REMOVE(queue, item, node); - g_free(item); - } -} - -static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue, - QEMUTimer *timer, uint32_t delay_ms) -{ - QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); - bool start_timer = QTAILQ_EMPTY(queue); - - item->type = QEMU_INPUT_QUEUE_DELAY; - item->delay_ms = delay_ms; - item->timer = timer; - QTAILQ_INSERT_TAIL(queue, item, node); - - if (start_timer) { - timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) - + item->delay_ms); - } -} - -static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue, - QemuConsole *src, InputEvent *evt) -{ - QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); - - item->type = QEMU_INPUT_QUEUE_EVENT; - item->src = src; - item->evt = evt; - QTAILQ_INSERT_TAIL(queue, item, node); -} - -static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue) -{ - QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); - - item->type = QEMU_INPUT_QUEUE_SYNC; - QTAILQ_INSERT_TAIL(queue, item, node); -} - -void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt) -{ - QemuInputHandlerState *s; - - qemu_input_event_trace(src, evt); - - /* pre processing */ - if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) { - qemu_input_transform_abs_rotate(evt); - } - - /* send event */ - s = qemu_input_find_handler(1 << evt->type, src); - if (!s) { - return; - } - s->handler->event(s->dev, src, evt); - s->events++; -} - -void qemu_input_event_send(QemuConsole *src, InputEvent *evt) -{ - if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { - return; - } - - replay_input_event(src, evt); -} - -void qemu_input_event_sync_impl(void) -{ - QemuInputHandlerState *s; - - trace_input_event_sync(); - - QTAILQ_FOREACH(s, &handlers, node) { - if (!s->events) { - continue; - } - if (s->handler->sync) { - s->handler->sync(s->dev); - } - s->events = 0; - } -} - -void qemu_input_event_sync(void) -{ - if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { - return; - } - - replay_input_sync_event(); -} - -InputEvent *qemu_input_event_new_key(KeyValue *key, bool down) -{ - InputEvent *evt = g_new0(InputEvent, 1); - evt->u.key.data = g_new0(InputKeyEvent, 1); - evt->type = INPUT_EVENT_KIND_KEY; - evt->u.key.data->key = key; - evt->u.key.data->down = down; - return evt; -} - -void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down) -{ - InputEvent *evt; - evt = qemu_input_event_new_key(key, down); - if (QTAILQ_EMPTY(&kbd_queue)) { - qemu_input_event_send(src, evt); - qemu_input_event_sync(); - qapi_free_InputEvent(evt); - } else { - qemu_input_queue_event(&kbd_queue, src, evt); - qemu_input_queue_sync(&kbd_queue); - } -} - -void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down) -{ - KeyValue *key = g_new0(KeyValue, 1); - key->type = KEY_VALUE_KIND_NUMBER; - key->u.number.data = num; - qemu_input_event_send_key(src, key, down); -} - -void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down) -{ - KeyValue *key = g_new0(KeyValue, 1); - key->type = KEY_VALUE_KIND_QCODE; - key->u.qcode.data = q; - qemu_input_event_send_key(src, key, down); -} - -void qemu_input_event_send_key_delay(uint32_t delay_ms) -{ - if (!kbd_timer) { - kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process, - &kbd_queue); - } - qemu_input_queue_delay(&kbd_queue, kbd_timer, - delay_ms ? delay_ms : kbd_default_delay_ms); -} - -InputEvent *qemu_input_event_new_btn(InputButton btn, bool down) -{ - InputEvent *evt = g_new0(InputEvent, 1); - evt->u.btn.data = g_new0(InputBtnEvent, 1); - evt->type = INPUT_EVENT_KIND_BTN; - evt->u.btn.data->button = btn; - evt->u.btn.data->down = down; - return evt; -} - -void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down) -{ - InputEvent *evt; - evt = qemu_input_event_new_btn(btn, down); - qemu_input_event_send(src, evt); - qapi_free_InputEvent(evt); -} - -void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, - uint32_t button_old, uint32_t button_new) -{ - InputButton btn; - uint32_t mask; - - for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) { - mask = button_map[btn]; - if ((button_old & mask) == (button_new & mask)) { - continue; - } - qemu_input_queue_btn(src, btn, button_new & mask); - } -} - -bool qemu_input_is_absolute(void) -{ - QemuInputHandlerState *s; - - s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS, - NULL); - return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); -} - -int qemu_input_scale_axis(int value, int size_in, int size_out) -{ - if (size_in < 2) { - return size_out / 2; - } - return (int64_t)value * (size_out - 1) / (size_in - 1); -} - -InputEvent *qemu_input_event_new_move(InputEventKind kind, - InputAxis axis, int value) -{ - InputEvent *evt = g_new0(InputEvent, 1); - InputMoveEvent *move = g_new0(InputMoveEvent, 1); - - evt->type = kind; - evt->u.rel.data = move; /* evt->u.rel is the same as evt->u.abs */ - move->axis = axis; - move->value = value; - return evt; -} - -void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value) -{ - InputEvent *evt; - evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value); - qemu_input_event_send(src, evt); - qapi_free_InputEvent(evt); -} - -void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size) -{ - InputEvent *evt; - int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE); - evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled); - qemu_input_event_send(src, evt); - qapi_free_InputEvent(evt); -} - -void qemu_input_check_mode_change(void) -{ - static int current_is_absolute; - int is_absolute; - - is_absolute = qemu_input_is_absolute(); - - if (is_absolute != current_is_absolute) { - trace_input_mouse_mode(is_absolute); - notifier_list_notify(&mouse_mode_notifiers, NULL); - } - - current_is_absolute = is_absolute; -} - -void qemu_add_mouse_mode_change_notifier(Notifier *notify) -{ - notifier_list_add(&mouse_mode_notifiers, notify); -} - -void qemu_remove_mouse_mode_change_notifier(Notifier *notify) -{ - notifier_remove(notify); -} - -MouseInfoList *qmp_query_mice(Error **errp) -{ - MouseInfoList *mice_list = NULL; - MouseInfoList *info; - QemuInputHandlerState *s; - bool current = true; - - QTAILQ_FOREACH(s, &handlers, node) { - if (!(s->handler->mask & - (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) { - continue; - } - - info = g_new0(MouseInfoList, 1); - info->value = g_new0(MouseInfo, 1); - info->value->index = s->id; - info->value->name = g_strdup(s->handler->name); - info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS; - info->value->current = current; - - current = false; - info->next = mice_list; - mice_list = info; - } - - return mice_list; -} - -void hmp_mouse_set(Monitor *mon, const QDict *qdict) -{ - QemuInputHandlerState *s; - int index = qdict_get_int(qdict, "index"); - int found = 0; - - QTAILQ_FOREACH(s, &handlers, node) { - if (s->id != index) { - continue; - } - if (!(s->handler->mask & (INPUT_EVENT_MASK_REL | - INPUT_EVENT_MASK_ABS))) { - error_report("Input device '%s' is not a mouse", s->handler->name); - return; - } - found = 1; - qemu_input_handler_activate(s); - break; - } - - if (!found) { - error_report("Mouse at index '%d' not found", index); - } - - qemu_input_check_mode_change(); -} diff --git a/qemu/ui/keymaps.c b/qemu/ui/keymaps.c deleted file mode 100644 index 8899a0b31..000000000 --- a/qemu/ui/keymaps.c +++ /dev/null @@ -1,241 +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 "qemu/osdep.h" -#include "keymaps.h" -#include "sysemu/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; - } - } - if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */ - char *end; - int ret = (int)strtoul(name + 1, &end, 16); - if (*end == '\0' && ret > 0) { - return ret; - } - } - 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 = g_malloc0(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); - f = filename ? fopen(filename, "r") : NULL; - g_free(filename); - if (!f) { - fprintf(stderr, "Could not read keymap file: '%s'\n", language); - return NULL; - } - - if (!k) { - k = g_new0(kbd_layout_t, 1); - } - - 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; - int keycode = strtol(rest, NULL, 0); - - if (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 (strstr(rest, "shift")) { - keycode |= SCANCODE_SHIFT; - } - if (strstr(rest, "altgr")) { - keycode |= SCANCODE_ALTGR; - } - if (strstr(rest, "ctrl")) { - keycode |= SCANCODE_CTRL; - } - - add_keysym(line, keysym, keycode, k); - - if (strstr(rest, "addupper")) { - char *c; - for (c = line; *c; c++) { - *c = qemu_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/qemu/ui/keymaps.h b/qemu/ui/keymaps.h deleted file mode 100644 index a7600d575..000000000 --- a/qemu/ui/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/qemu/ui/qemu-pixman.c b/qemu/ui/qemu-pixman.c deleted file mode 100644 index c9f8dce7f..000000000 --- a/qemu/ui/qemu-pixman.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" - -PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format) -{ - PixelFormat pf; - uint8_t bpp; - - bpp = pf.bits_per_pixel = PIXMAN_FORMAT_BPP(format); - pf.bytes_per_pixel = PIXMAN_FORMAT_BPP(format) / 8; - pf.depth = PIXMAN_FORMAT_DEPTH(format); - - pf.abits = PIXMAN_FORMAT_A(format); - pf.rbits = PIXMAN_FORMAT_R(format); - pf.gbits = PIXMAN_FORMAT_G(format); - pf.bbits = PIXMAN_FORMAT_B(format); - - switch (PIXMAN_FORMAT_TYPE(format)) { - case PIXMAN_TYPE_ARGB: - pf.ashift = pf.bbits + pf.gbits + pf.rbits; - pf.rshift = pf.bbits + pf.gbits; - pf.gshift = pf.bbits; - pf.bshift = 0; - break; - case PIXMAN_TYPE_ABGR: - pf.ashift = pf.rbits + pf.gbits + pf.bbits; - pf.bshift = pf.rbits + pf.gbits; - pf.gshift = pf.rbits; - pf.rshift = 0; - break; - case PIXMAN_TYPE_BGRA: - pf.bshift = bpp - pf.bbits; - pf.gshift = bpp - (pf.bbits + pf.gbits); - pf.rshift = bpp - (pf.bbits + pf.gbits + pf.rbits); - pf.ashift = 0; - break; - case PIXMAN_TYPE_RGBA: - pf.rshift = bpp - pf.rbits; - pf.gshift = bpp - (pf.rbits + pf.gbits); - pf.bshift = bpp - (pf.rbits + pf.gbits + pf.bbits); - pf.ashift = 0; - break; - default: - g_assert_not_reached(); - break; - } - - pf.amax = (1 << pf.abits) - 1; - pf.rmax = (1 << pf.rbits) - 1; - pf.gmax = (1 << pf.gbits) - 1; - pf.bmax = (1 << pf.bbits) - 1; - pf.amask = pf.amax << pf.ashift; - pf.rmask = pf.rmax << pf.rshift; - pf.gmask = pf.gmax << pf.gshift; - pf.bmask = pf.bmax << pf.bshift; - - return pf; -} - -pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian) -{ - if (native_endian) { - switch (bpp) { - case 15: - return PIXMAN_x1r5g5b5; - case 16: - return PIXMAN_r5g6b5; - case 24: - return PIXMAN_r8g8b8; - case 32: - return PIXMAN_x8r8g8b8; - } - } else { - switch (bpp) { - case 24: - return PIXMAN_b8g8r8; - case 32: - return PIXMAN_b8g8r8x8; - break; - } - } - return 0; -} - -int qemu_pixman_get_type(int rshift, int gshift, int bshift) -{ - int type = PIXMAN_TYPE_OTHER; - - if (rshift > gshift && gshift > bshift) { - if (bshift == 0) { - type = PIXMAN_TYPE_ARGB; - } else { -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8) - type = PIXMAN_TYPE_RGBA; -#endif - } - } else if (rshift < gshift && gshift < bshift) { - if (rshift == 0) { - type = PIXMAN_TYPE_ABGR; - } else { -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 16, 0) - type = PIXMAN_TYPE_BGRA; -#endif - } - } - return type; -} - -pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf) -{ - pixman_format_code_t format; - int type; - - type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift); - format = PIXMAN_FORMAT(pf->bits_per_pixel, type, - pf->abits, pf->rbits, pf->gbits, pf->bbits); - if (!pixman_format_supported_source(format)) { - return 0; - } - return format; -} - -/* - * Return true for known-good pixman conversions. - * - * UIs using pixman for format conversion can hook this into - * DisplayChangeListenerOps->dpy_gfx_check_format - */ -bool qemu_pixman_check_format(DisplayChangeListener *dcl, - pixman_format_code_t format) -{ - switch (format) { - /* 32 bpp */ - case PIXMAN_x8r8g8b8: - case PIXMAN_a8r8g8b8: - case PIXMAN_b8g8r8x8: - case PIXMAN_b8g8r8a8: - /* 24 bpp */ - case PIXMAN_r8g8b8: - case PIXMAN_b8g8r8: - /* 16 bpp */ - case PIXMAN_x1r5g5b5: - case PIXMAN_r5g6b5: - return true; - default: - return false; - } -} - -pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, - int width) -{ - pixman_image_t *image = pixman_image_create_bits(format, width, 1, NULL, 0); - assert(image != NULL); - return image; -} - -/* fill linebuf from framebuffer */ -void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, - int width, int x, int y) -{ - pixman_image_composite(PIXMAN_OP_SRC, fb, NULL, linebuf, - x, y, 0, 0, 0, 0, width, 1); -} - -/* copy linebuf to framebuffer */ -void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y, - pixman_image_t *linebuf) -{ - pixman_image_composite(PIXMAN_OP_SRC, linebuf, NULL, fb, - 0, 0, 0, 0, x, y, width, 1); -} - -pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, - pixman_image_t *image) -{ - pixman_image_t *mirror; - - mirror = pixman_image_create_bits(format, - pixman_image_get_width(image), - pixman_image_get_height(image), - NULL, - pixman_image_get_stride(image)); - return mirror; -} - -void qemu_pixman_image_unref(pixman_image_t *image) -{ - if (image == NULL) { - return; - } - pixman_image_unref(image); -} - -pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color) -{ - pixman_color_t c; - - c.red = ((color & pf->rmask) >> pf->rshift) << (16 - pf->rbits); - c.green = ((color & pf->gmask) >> pf->gshift) << (16 - pf->gbits); - c.blue = ((color & pf->bmask) >> pf->bshift) << (16 - pf->bbits); - c.alpha = ((color & pf->amask) >> pf->ashift) << (16 - pf->abits); - return c; -} - -pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font, - unsigned int ch) -{ - pixman_image_t *glyph; - uint8_t *data; - bool bit; - int x, y; - - glyph = pixman_image_create_bits(PIXMAN_a8, 8, height, - NULL, 0); - data = (uint8_t *)pixman_image_get_data(glyph); - - font += height * ch; - for (y = 0; y < height; y++, font++) { - for (x = 0; x < 8; x++, data++) { - bit = (*font) & (1 << (7-x)); - *data = bit ? 0xff : 0x00; - } - } - return glyph; -} - -void qemu_pixman_glyph_render(pixman_image_t *glyph, - pixman_image_t *surface, - pixman_color_t *fgcol, - pixman_color_t *bgcol, - int x, int y, int cw, int ch) -{ - pixman_image_t *ifg = pixman_image_create_solid_fill(fgcol); - pixman_image_t *ibg = pixman_image_create_solid_fill(bgcol); - - pixman_image_composite(PIXMAN_OP_SRC, ibg, NULL, surface, - 0, 0, 0, 0, - cw * x, ch * y, - cw, ch); - pixman_image_composite(PIXMAN_OP_OVER, ifg, glyph, surface, - 0, 0, 0, 0, - cw * x, ch * y, - cw, ch); - pixman_image_unref(ifg); - pixman_image_unref(ibg); -} diff --git a/qemu/ui/qemu-x509.h b/qemu/ui/qemu-x509.h deleted file mode 100644 index 095aec161..000000000 --- a/qemu/ui/qemu-x509.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef QEMU_X509_H -#define QEMU_X509_H - -#define X509_CA_CERT_FILE "ca-cert.pem" -#define X509_CA_CRL_FILE "ca-crl.pem" -#define X509_SERVER_KEY_FILE "server-key.pem" -#define X509_SERVER_CERT_FILE "server-cert.pem" - -#endif /* QEMU_X509_H */ diff --git a/qemu/ui/sdl.c b/qemu/ui/sdl.c deleted file mode 100644 index d8cf5bcf7..000000000 --- a/qemu/ui/sdl.c +++ /dev/null @@ -1,1027 +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. - */ - -/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */ -#undef WIN32_LEAN_AND_MEAN - -#include "qemu/osdep.h" -#include <SDL.h> -#include <SDL_syswm.h> - -#include "qemu-common.h" -#include "qemu/cutils.h" -#include "ui/console.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" -#include "x_keymap.h" -#include "sdl_zoom.h" - -static DisplayChangeListener *dcl; -static DisplaySurface *surface; -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 bool gui_saved_scaling; -static int gui_saved_width; -static int gui_saved_height; -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_grab_code = KMOD_LALT | KMOD_LCTRL; -static uint8_t modifiers_state[256]; -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 SDL_PixelFormat host_format; -static int scaling_active = 0; -static Notifier mouse_mode_notifier; -static int idle_counter; - -#define SDL_REFRESH_INTERVAL_BUSY 10 -#define SDL_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \ - / SDL_REFRESH_INTERVAL_BUSY + 1) - -#if 0 -#define DEBUG_SDL -#endif - -static void sdl_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - SDL_Rect rec; - rec.x = x; - rec.y = y; - rec.w = w; - rec.h = h; - -#ifdef DEBUG_SDL - printf("SDL: Updating x=%d y=%d w=%d h=%d (scaling: %d)\n", - x, y, w, h, scaling_active); -#endif - - 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 do_sdl_resize(int width, int height, int bpp) -{ - int flags; - SDL_Surface *tmp_screen; - -#ifdef DEBUG_SDL - printf("SDL: Resizing to %dx%d bpp %d\n", width, height, bpp); -#endif - - flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; - if (gui_fullscreen) { - flags |= SDL_FULLSCREEN; - } else { - flags |= SDL_RESIZABLE; - } - if (gui_noframe) - flags |= SDL_NOFRAME; - - tmp_screen = SDL_SetVideoMode(width, height, bpp, flags); - if (!real_screen) { - if (!tmp_screen) { - fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", - width, height, bpp, SDL_GetError()); - exit(1); - } - } else { - /* - * Revert to the previous video mode if the change of resizing or - * resolution failed. - */ - if (!tmp_screen) { - fprintf(stderr, "Failed to set SDL display (%dx%dx%d): %s\n", - width, height, bpp, SDL_GetError()); - return; - } - } - - real_screen = tmp_screen; -} - -static void sdl_switch(DisplayChangeListener *dcl, - DisplaySurface *new_surface) -{ - PixelFormat pf; - - /* temporary hack: allows to call sdl_switch to handle scaling changes */ - if (new_surface) { - surface = new_surface; - } - pf = qemu_pixelformat_from_pixman(surface->format); - - if (!scaling_active) { - do_sdl_resize(surface_width(surface), surface_height(surface), 0); - } else if (real_screen->format->BitsPerPixel != - surface_bits_per_pixel(surface)) { - do_sdl_resize(real_screen->w, real_screen->h, - surface_bits_per_pixel(surface)); - } - - if (guest_screen != NULL) { - SDL_FreeSurface(guest_screen); - } - -#ifdef DEBUG_SDL - printf("SDL: Creating surface with masks: %08x %08x %08x %08x\n", - pf.rmask, pf.gmask, pf.bmask, pf.amask); -#endif - - guest_screen = SDL_CreateRGBSurfaceFrom - (surface_data(surface), - surface_width(surface), surface_height(surface), - surface_bits_per_pixel(surface), surface_stride(surface), - pf.rmask, pf.gmask, - pf.bmask, pf.amask); -} - -static bool sdl_check_format(DisplayChangeListener *dcl, - pixman_format_code_t format) -{ - /* - * We let SDL convert for us a few more formats than, - * the native ones. Thes are the ones I have tested. - */ - return (format == PIXMAN_x8r8g8b8 || - format == PIXMAN_b8g8r8x8 || - format == PIXMAN_x1r5g5b5 || - format == PIXMAN_r5g6b5); -} - -/* 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]) { - qemu_input_event_send_key_number(dcl->con, i, false); - modifiers_state[i] = 0; - } - } -} - -static void sdl_process_key(SDL_KeyboardEvent *ev) -{ - int keycode; - - if (ev->keysym.sym == SDLK_PAUSE) { - /* specific case */ - qemu_input_event_send_key_qcode(dcl->con, Q_KEY_CODE_PAUSE, - ev->type == SDL_KEYDOWN); - 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; -#define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION) -#if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14 - /* SDL versions before 1.2.14 don't support key up for caps/num lock. */ - case 0x45: /* num lock */ - case 0x3a: /* caps lock */ - /* SDL does not send the key up event, so we generate it */ - qemu_input_event_send_key_number(dcl->con, keycode, true); - qemu_input_event_send_key_number(dcl->con, keycode, false); - return; -#endif - } - - /* now send the key code */ - qemu_input_event_send_key_number(dcl->con, keycode, - ev->type == SDL_KEYDOWN); -} - -static void sdl_update_caption(void) -{ - char win_title[1024]; - char icon_title[1024]; - const char *status = ""; - - if (!runstate_is_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 (qemu_input_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 (!qemu_input_is_absolute() || !qemu_console_is_graphic(NULL)) { - SDL_ShowCursor(1); - if (guest_cursor && - (gui_grab || qemu_input_is_absolute() || absolute_enabled)) - SDL_SetCursor(guest_sprite); - else - SDL_SetCursor(sdl_cursor_normal); - } -} - -static void sdl_grab_start(void) -{ - /* - * If the application is not active, do not try to enter grab state. This - * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the - * application (SDL bug). - */ - if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) { - return; - } - if (guest_cursor) { - SDL_SetCursor(guest_sprite); - if (!qemu_input_is_absolute() && !absolute_enabled) { - SDL_WarpMouse(guest_x, guest_y); - } - } else - sdl_hide_cursor(); - SDL_WM_GrabInput(SDL_GRAB_ON); - gui_grab = 1; - sdl_update_caption(); -} - -static void sdl_grab_end(void) -{ - SDL_WM_GrabInput(SDL_GRAB_OFF); - gui_grab = 0; - sdl_show_cursor(); - sdl_update_caption(); -} - -static void absolute_mouse_grab(void) -{ - int mouse_x, mouse_y; - - SDL_GetMouseState(&mouse_x, &mouse_y); - if (mouse_x > 0 && mouse_x < real_screen->w - 1 && - mouse_y > 0 && mouse_y < real_screen->h - 1) { - sdl_grab_start(); - } -} - -static void sdl_mouse_mode_change(Notifier *notify, void *data) -{ - if (qemu_input_is_absolute()) { - if (!absolute_enabled) { - absolute_enabled = 1; - if (qemu_console_is_graphic(NULL)) { - absolute_mouse_grab(); - } - } - } else if (absolute_enabled) { - if (!gui_fullscreen) { - sdl_grab_end(); - } - absolute_enabled = 0; - } -} - -static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state) -{ - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT), - [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE), - [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT), - [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP), - [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN), - }; - static uint32_t prev_state; - - if (prev_state != state) { - qemu_input_update_buttons(dcl->con, bmap, prev_state, state); - prev_state = state; - } - - if (qemu_input_is_absolute()) { - qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x, - real_screen->w); - qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y, - real_screen->h); - } else { - if (guest_cursor) { - x -= guest_x; - y -= guest_y; - guest_x += x; - guest_y += y; - dx = x; - dy = y; - } - qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, dx); - qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, dy); - } - qemu_input_event_sync(); -} - -static void sdl_scale(int width, int height) -{ - int bpp = real_screen->format->BitsPerPixel; - -#ifdef DEBUG_SDL - printf("SDL: Scaling to %dx%d bpp %d\n", width, height, bpp); -#endif - - if (bpp != 16 && bpp != 32) { - bpp = 32; - } - do_sdl_resize(width, height, bpp); - scaling_active = 1; -} - -static void toggle_full_screen(void) -{ - int width = surface_width(surface); - int height = surface_height(surface); - int bpp = surface_bits_per_pixel(surface); - - gui_fullscreen = !gui_fullscreen; - if (gui_fullscreen) { - gui_saved_width = real_screen->w; - gui_saved_height = real_screen->h; - gui_saved_scaling = scaling_active; - - do_sdl_resize(width, height, bpp); - scaling_active = 0; - - gui_saved_grab = gui_grab; - sdl_grab_start(); - } else { - if (gui_saved_scaling) { - sdl_scale(gui_saved_width, gui_saved_height); - } else { - do_sdl_resize(width, height, 0); - } - if (!gui_saved_grab || !qemu_console_is_graphic(NULL)) { - sdl_grab_end(); - } - } - graphic_hw_invalidate(NULL); - graphic_hw_update(NULL); -} - -static void handle_keydown(SDL_Event *ev) -{ - int mod_state; - int keycode; - - 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) { - keycode = sdl_keyevent_to_keycode(&ev->key); - switch (keycode) { - case 0x21: /* 'f' key on US keyboard */ - toggle_full_screen(); - gui_keysym = 1; - break; - case 0x16: /* 'u' key on US keyboard */ - if (scaling_active) { - scaling_active = 0; - sdl_switch(dcl, NULL); - graphic_hw_invalidate(NULL); - graphic_hw_update(NULL); - } - gui_keysym = 1; - break; - case 0x02 ... 0x0a: /* '1' to '9' keys */ - /* Reset the modifiers sent to the current console */ - reset_keys(); - console_select(keycode - 0x02); - gui_keysym = 1; - if (gui_fullscreen) { - break; - } - if (!qemu_console_is_graphic(NULL)) { - /* release grab if going to a text console */ - if (gui_grab) { - sdl_grab_end(); - } else if (absolute_enabled) { - sdl_show_cursor(); - } - } else if (absolute_enabled) { - sdl_hide_cursor(); - absolute_mouse_grab(); - } - break; - case 0x1b: /* '+' */ - case 0x35: /* '-' */ - if (!gui_fullscreen) { - int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50), - 160); - int height = (surface_height(surface) * width) / - surface_width(surface); - - sdl_scale(width, height); - graphic_hw_invalidate(NULL); - graphic_hw_update(NULL); - gui_keysym = 1; - } - default: - break; - } - } else if (!qemu_console_is_graphic(NULL)) { - int 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); - } - } - if (qemu_console_is_graphic(NULL) && !gui_keysym) { - sdl_process_key(&ev->key); - } -} - -static void handle_keyup(SDL_Event *ev) -{ - int mod_state; - - 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 && gui_key_modifier_pressed) { - gui_key_modifier_pressed = 0; - if (gui_keysym == 0) { - /* exit/enter grab if pressing Ctrl-Alt */ - if (!gui_grab) { - if (qemu_console_is_graphic(NULL)) { - sdl_grab_start(); - } - } else if (!gui_fullscreen) { - sdl_grab_end(); - } - /* SDL does not send back all the modifiers key, so we must - * correct it. */ - reset_keys(); - return; - } - gui_keysym = 0; - } - if (qemu_console_is_graphic(NULL) && !gui_keysym) { - sdl_process_key(&ev->key); - } -} - -static void handle_mousemotion(SDL_Event *ev) -{ - int max_x, max_y; - - if (qemu_console_is_graphic(NULL) && - (qemu_input_is_absolute() || absolute_enabled)) { - max_x = real_screen->w - 1; - max_y = real_screen->h - 1; - if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 || - ev->motion.x == max_x || ev->motion.y == max_y)) { - sdl_grab_end(); - } - if (!gui_grab && - (ev->motion.x > 0 && ev->motion.x < max_x && - ev->motion.y > 0 && ev->motion.y < max_y)) { - sdl_grab_start(); - } - } - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, - ev->motion.x, ev->motion.y, ev->motion.state); - } -} - -static void handle_mousebutton(SDL_Event *ev) -{ - int buttonstate = SDL_GetMouseState(NULL, NULL); - SDL_MouseButtonEvent *bev; - - if (!qemu_console_is_graphic(NULL)) { - return; - } - - bev = &ev->button; - if (!gui_grab && !qemu_input_is_absolute()) { - if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { - /* start grabbing all events */ - sdl_grab_start(); - } - } else { - if (ev->type == SDL_MOUSEBUTTONDOWN) { - buttonstate |= SDL_BUTTON(bev->button); - } else { - buttonstate &= ~SDL_BUTTON(bev->button); - } - sdl_send_mouse_event(0, 0, bev->x, bev->y, buttonstate); - } -} - -static void handle_activation(SDL_Event *ev) -{ -#ifdef _WIN32 - /* Disable grab if the window no longer has the focus - * (Windows-only workaround) */ - if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS && - !ev->active.gain && !gui_fullscreen) { - sdl_grab_end(); - } -#endif - if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) && - (qemu_input_is_absolute() || absolute_enabled)) { - absolute_mouse_grab(); - } - if (ev->active.state & SDL_APPACTIVE) { - if (ev->active.gain) { - /* Back to default interval */ - update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT); - } else { - /* Sleeping interval. Not using the long default here as - * sdl_refresh does not only update the guest screen, but - * also checks for gui events. */ - update_displaychangelistener(dcl, 500); - } - } -} - -static void sdl_refresh(DisplayChangeListener *dcl) -{ - SDL_Event ev1, *ev = &ev1; - int idle = 1; - - if (last_vm_running != runstate_is_running()) { - last_vm_running = runstate_is_running(); - sdl_update_caption(); - } - - graphic_hw_update(NULL); - SDL_EnableUNICODE(!qemu_console_is_graphic(NULL)); - - while (SDL_PollEvent(ev)) { - switch (ev->type) { - case SDL_VIDEOEXPOSE: - sdl_update(dcl, 0, 0, real_screen->w, real_screen->h); - break; - case SDL_KEYDOWN: - idle = 0; - handle_keydown(ev); - break; - case SDL_KEYUP: - idle = 0; - handle_keyup(ev); - break; - case SDL_QUIT: - if (!no_quit) { - no_shutdown = 0; - qemu_system_shutdown_request(); - } - break; - case SDL_MOUSEMOTION: - idle = 0; - handle_mousemotion(ev); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - idle = 0; - handle_mousebutton(ev); - break; - case SDL_ACTIVEEVENT: - handle_activation(ev); - break; - case SDL_VIDEORESIZE: - sdl_scale(ev->resize.w, ev->resize.h); - graphic_hw_invalidate(NULL); - graphic_hw_update(NULL); - break; - default: - break; - } - } - - if (idle) { - if (idle_counter < SDL_MAX_IDLE_COUNT) { - idle_counter++; - if (idle_counter >= SDL_MAX_IDLE_COUNT) { - dcl->update_interval = GUI_REFRESH_INTERVAL_DEFAULT; - } - } - } else { - idle_counter = 0; - dcl->update_interval = SDL_REFRESH_INTERVAL_BUSY; - } -} - -static void sdl_mouse_warp(DisplayChangeListener *dcl, - int x, int y, int on) -{ - if (on) { - if (!guest_cursor) - sdl_show_cursor(); - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { - SDL_SetCursor(guest_sprite); - if (!qemu_input_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(DisplayChangeListener *dcl, - QEMUCursor *c) -{ - uint8_t *image, *mask; - int bpl; - - if (guest_sprite) - SDL_FreeCursor(guest_sprite); - - bpl = cursor_get_mono_bpl(c); - image = g_malloc0(bpl * c->height); - mask = g_malloc0(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); - g_free(image); - g_free(mask); - - if (guest_cursor && - (gui_grab || qemu_input_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); -} - -static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "sdl", - .dpy_gfx_update = sdl_update, - .dpy_gfx_switch = sdl_switch, - .dpy_gfx_check_format = sdl_check_format, - .dpy_refresh = sdl_refresh, - .dpy_mouse_set = sdl_mouse_warp, - .dpy_cursor_define = sdl_mouse_define, -}; - -void sdl_display_early_init(int opengl) -{ - if (opengl == 1 /* on */) { - fprintf(stderr, - "SDL1 display code has no opengl support.\n" - "Please recompile qemu with SDL2, using\n" - "./configure --enable-sdl --with-sdlabi=2.0\n"); - } -} - -void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) -{ - int flags; - uint8_t data = 0; - const SDL_VideoInfo *vi; - char *filename; - -#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); - } -#ifdef __linux__ - /* on Linux, SDL may use fbcon|directfb|svgalib when run without - * accessible $DISPLAY to open X11 window. This is often the case - * when qemu is run using sudo. But in this case, and when actually - * run in X11 environment, SDL fights with X11 for the video card, - * making current display unavailable, often until reboot. - * So make x11 the default SDL video driver if this variable is unset. - * This is a bit hackish but saves us from bigger problem. - * Maybe it's a good idea to fix this in SDL instead. - */ - setenv("SDL_VIDEODRIVER", "x11", 0); -#endif - - /* Enable normal up/down events for Caps-Lock and Num-Lock keys. - * This requires SDL >= 1.2.14. */ - setenv("SDL_DISABLE_LOCK_KEYS", "1", 1); - - 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); - - /* Load a 32x32x4 image. White pixels are transparent. */ - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); - if (filename) { - SDL_Surface *image = SDL_LoadBMP(filename); - if (image) { - uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255); - SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey); - SDL_WM_SetIcon(image, NULL); - } - g_free(filename); - } - - if (full_screen) { - gui_fullscreen = 1; - sdl_grab_start(); - } - - dcl = g_new0(DisplayChangeListener, 1); - dcl->ops = &dcl_ops; - register_displaychangelistener(dcl); - - 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); -} diff --git a/qemu/ui/sdl2-2d.c b/qemu/ui/sdl2-2d.c deleted file mode 100644 index 95930061e..000000000 --- a/qemu/ui/sdl2-2d.c +++ /dev/null @@ -1,161 +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. - */ -/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "ui/sdl2.h" -#include "sysemu/sysemu.h" - -void sdl2_2d_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - DisplaySurface *surf = qemu_console_surface(dcl->con); - SDL_Rect rect; - - assert(!scon->opengl); - - if (!surf) { - return; - } - if (!scon->texture) { - return; - } - - /* - * SDL2 seems to do some double-buffering, and trying to only - * update the changed areas results in only one of the two buffers - * being updated. Which flickers alot. So lets not try to be - * clever do a full update every time ... - */ -#if 0 - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = h; -#else - rect.x = 0; - rect.y = 0; - rect.w = surface_width(surf); - rect.h = surface_height(surf); -#endif - - SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), - surface_stride(surf)); - SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect); - SDL_RenderPresent(scon->real_renderer); -} - -void sdl2_2d_switch(DisplayChangeListener *dcl, - DisplaySurface *new_surface) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - DisplaySurface *old_surface = scon->surface; - int format = 0; - - assert(!scon->opengl); - - scon->surface = new_surface; - - if (scon->texture) { - SDL_DestroyTexture(scon->texture); - scon->texture = NULL; - } - - if (!new_surface) { - sdl2_window_destroy(scon); - return; - } - - if (!scon->real_window) { - sdl2_window_create(scon); - } else if (old_surface && - ((surface_width(old_surface) != surface_width(new_surface)) || - (surface_height(old_surface) != surface_height(new_surface)))) { - sdl2_window_resize(scon); - } - - SDL_RenderSetLogicalSize(scon->real_renderer, - surface_width(new_surface), - surface_height(new_surface)); - - switch (surface_format(scon->surface)) { - case PIXMAN_x1r5g5b5: - format = SDL_PIXELFORMAT_ARGB1555; - break; - case PIXMAN_r5g6b5: - format = SDL_PIXELFORMAT_RGB565; - break; - case PIXMAN_x8r8g8b8: - format = SDL_PIXELFORMAT_ARGB8888; - break; - case PIXMAN_r8g8b8x8: - format = SDL_PIXELFORMAT_RGBA8888; - break; - default: - g_assert_not_reached(); - } - scon->texture = SDL_CreateTexture(scon->real_renderer, format, - SDL_TEXTUREACCESS_STREAMING, - surface_width(new_surface), - surface_height(new_surface)); - sdl2_2d_redraw(scon); -} - -void sdl2_2d_refresh(DisplayChangeListener *dcl) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - - assert(!scon->opengl); - graphic_hw_update(dcl->con); - sdl2_poll_events(scon); -} - -void sdl2_2d_redraw(struct sdl2_console *scon) -{ - assert(!scon->opengl); - - if (!scon->surface) { - return; - } - sdl2_2d_update(&scon->dcl, 0, 0, - surface_width(scon->surface), - surface_height(scon->surface)); -} - -bool sdl2_2d_check_format(DisplayChangeListener *dcl, - pixman_format_code_t format) -{ - /* - * We let SDL convert for us a few more formats than, - * the native ones. Thes are the ones I have tested. - */ - return (format == PIXMAN_x8r8g8b8 || - format == PIXMAN_b8g8r8x8 || - format == PIXMAN_x1r5g5b5 || - format == PIXMAN_r5g6b5); -} diff --git a/qemu/ui/sdl2-gl.c b/qemu/ui/sdl2-gl.c deleted file mode 100644 index a324ecaca..000000000 --- a/qemu/ui/sdl2-gl.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * QEMU SDL display driver -- opengl support - * - * Copyright (c) 2014 Red Hat - * - * Authors: - * Gerd Hoffmann <kraxel@redhat.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/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "ui/sdl2.h" -#include "sysemu/sysemu.h" - -#include <epoxy/gl.h> - -static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout) -{ - if (scon->scanout_mode == scanout) { - return; - } - - scon->scanout_mode = scanout; - if (!scon->scanout_mode) { - if (scon->fbo_id) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, 0, 0); - glDeleteFramebuffers(1, &scon->fbo_id); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - scon->fbo_id = 0; - } - if (scon->surface) { - surface_gl_destroy_texture(scon->gls, scon->surface); - surface_gl_create_texture(scon->gls, scon->surface); - } - } -} - -static void sdl2_gl_render_surface(struct sdl2_console *scon) -{ - int ww, wh; - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - sdl2_set_scanout_mode(scon, false); - - SDL_GetWindowSize(scon->real_window, &ww, &wh); - surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh); - - surface_gl_render_texture(scon->gls, scon->surface); - SDL_GL_SwapWindow(scon->real_window); -} - -void sdl2_gl_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - - assert(scon->opengl); - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h); - scon->updates++; -} - -void sdl2_gl_switch(DisplayChangeListener *dcl, - DisplaySurface *new_surface) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - DisplaySurface *old_surface = scon->surface; - - assert(scon->opengl); - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - surface_gl_destroy_texture(scon->gls, scon->surface); - - scon->surface = new_surface; - - if (!new_surface) { - console_gl_fini_context(scon->gls); - scon->gls = NULL; - sdl2_window_destroy(scon); - return; - } - - if (!scon->real_window) { - sdl2_window_create(scon); - scon->gls = console_gl_init_context(); - } else if (old_surface && - ((surface_width(old_surface) != surface_width(new_surface)) || - (surface_height(old_surface) != surface_height(new_surface)))) { - sdl2_window_resize(scon); - } - - surface_gl_create_texture(scon->gls, scon->surface); -} - -void sdl2_gl_refresh(DisplayChangeListener *dcl) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - - assert(scon->opengl); - - graphic_hw_update(dcl->con); - if (scon->updates && scon->surface) { - scon->updates = 0; - sdl2_gl_render_surface(scon); - } - sdl2_poll_events(scon); -} - -void sdl2_gl_redraw(struct sdl2_console *scon) -{ - assert(scon->opengl); - - if (scon->surface) { - sdl2_gl_render_surface(scon); - } -} - -QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl, - QEMUGLParams *params) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - SDL_GLContext ctx; - - assert(scon->opengl); - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, - SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver); - - ctx = SDL_GL_CreateContext(scon->real_window); - return (QEMUGLContext)ctx; -} - -void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) -{ - SDL_GLContext sdlctx = (SDL_GLContext)ctx; - - SDL_GL_DeleteContext(sdlctx); -} - -int sdl2_gl_make_context_current(DisplayChangeListener *dcl, - QEMUGLContext ctx) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - SDL_GLContext sdlctx = (SDL_GLContext)ctx; - - assert(scon->opengl); - - return SDL_GL_MakeCurrent(scon->real_window, sdlctx); -} - -QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl) -{ - SDL_GLContext sdlctx; - - sdlctx = SDL_GL_GetCurrentContext(); - return (QEMUGLContext)sdlctx; -} - -void sdl2_gl_scanout(DisplayChangeListener *dcl, - uint32_t backing_id, bool backing_y_0_top, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - - assert(scon->opengl); - scon->x = x; - scon->y = y; - scon->w = w; - scon->h = h; - scon->tex_id = backing_id; - scon->y0_top = backing_y_0_top; - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - - if (scon->tex_id == 0 || scon->w == 0 || scon->h == 0) { - sdl2_set_scanout_mode(scon, false); - return; - } - - sdl2_set_scanout_mode(scon, true); - if (!scon->fbo_id) { - glGenFramebuffers(1, &scon->fbo_id); - } - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, scon->tex_id, 0); -} - -void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - int ww, wh, y1, y2; - - assert(scon->opengl); - if (!scon->scanout_mode) { - return; - } - if (!scon->fbo_id) { - return; - } - - SDL_GL_MakeCurrent(scon->real_window, scon->winctx); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - SDL_GetWindowSize(scon->real_window, &ww, &wh); - glViewport(0, 0, ww, wh); - y1 = scon->y0_top ? 0 : scon->h; - y2 = scon->y0_top ? scon->h : 0; - glBlitFramebuffer(0, y1, scon->w, y2, - 0, 0, ww, wh, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id); - - SDL_GL_SwapWindow(scon->real_window); -} diff --git a/qemu/ui/sdl2-input.c b/qemu/ui/sdl2-input.c deleted file mode 100644 index 6e315ae80..000000000 --- a/qemu/ui/sdl2-input.c +++ /dev/null @@ -1,101 +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. - */ -/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "ui/sdl2.h" -#include "sysemu/sysemu.h" - -#include "sdl2-keymap.h" - -static uint8_t modifiers_state[SDL_NUM_SCANCODES]; - -void sdl2_reset_keys(struct sdl2_console *scon) -{ - QemuConsole *con = scon ? scon->dcl.con : NULL; - int i; - - for (i = 0; i < SDL_NUM_SCANCODES; i++) { - if (modifiers_state[i]) { - int qcode = sdl2_scancode_to_qcode[i]; - qemu_input_event_send_key_qcode(con, qcode, false); - modifiers_state[i] = 0; - } - } -} - -void sdl2_process_key(struct sdl2_console *scon, - SDL_KeyboardEvent *ev) -{ - int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode]; - QemuConsole *con = scon ? scon->dcl.con : NULL; - - if (!qemu_console_is_graphic(con)) { - if (ev->type == SDL_KEYDOWN) { - switch (ev->keysym.scancode) { - case SDL_SCANCODE_RETURN: - kbd_put_keysym_console(con, '\n'); - break; - case SDL_SCANCODE_BACKSPACE: - kbd_put_keysym_console(con, QEMU_KEY_BACKSPACE); - break; - default: - kbd_put_qcode_console(con, qcode); - break; - } - } - return; - } - - switch (ev->keysym.scancode) { -#if 0 - case SDL_SCANCODE_NUMLOCKCLEAR: - case SDL_SCANCODE_CAPSLOCK: - /* SDL does not send the key up event, so we generate it */ - qemu_input_event_send_key_qcode(con, qcode, true); - qemu_input_event_send_key_qcode(con, qcode, false); - return; -#endif - case SDL_SCANCODE_LCTRL: - case SDL_SCANCODE_LSHIFT: - case SDL_SCANCODE_LALT: - case SDL_SCANCODE_LGUI: - case SDL_SCANCODE_RCTRL: - case SDL_SCANCODE_RSHIFT: - case SDL_SCANCODE_RALT: - case SDL_SCANCODE_RGUI: - if (ev->type == SDL_KEYUP) { - modifiers_state[ev->keysym.scancode] = 0; - } else { - modifiers_state[ev->keysym.scancode] = 1; - } - /* fall though */ - default: - qemu_input_event_send_key_qcode(con, qcode, - ev->type == SDL_KEYDOWN); - } -} diff --git a/qemu/ui/sdl2-keymap.h b/qemu/ui/sdl2-keymap.h deleted file mode 100644 index cbedaa477..000000000 --- a/qemu/ui/sdl2-keymap.h +++ /dev/null @@ -1,267 +0,0 @@ - -/* map SDL2 scancodes to QKeyCode */ - -static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = { - [SDL_SCANCODE_A] = Q_KEY_CODE_A, - [SDL_SCANCODE_B] = Q_KEY_CODE_B, - [SDL_SCANCODE_C] = Q_KEY_CODE_C, - [SDL_SCANCODE_D] = Q_KEY_CODE_D, - [SDL_SCANCODE_E] = Q_KEY_CODE_E, - [SDL_SCANCODE_F] = Q_KEY_CODE_F, - [SDL_SCANCODE_G] = Q_KEY_CODE_G, - [SDL_SCANCODE_H] = Q_KEY_CODE_H, - [SDL_SCANCODE_I] = Q_KEY_CODE_I, - [SDL_SCANCODE_J] = Q_KEY_CODE_J, - [SDL_SCANCODE_K] = Q_KEY_CODE_K, - [SDL_SCANCODE_L] = Q_KEY_CODE_L, - [SDL_SCANCODE_M] = Q_KEY_CODE_M, - [SDL_SCANCODE_N] = Q_KEY_CODE_N, - [SDL_SCANCODE_O] = Q_KEY_CODE_O, - [SDL_SCANCODE_P] = Q_KEY_CODE_P, - [SDL_SCANCODE_Q] = Q_KEY_CODE_Q, - [SDL_SCANCODE_R] = Q_KEY_CODE_R, - [SDL_SCANCODE_S] = Q_KEY_CODE_S, - [SDL_SCANCODE_T] = Q_KEY_CODE_T, - [SDL_SCANCODE_U] = Q_KEY_CODE_U, - [SDL_SCANCODE_V] = Q_KEY_CODE_V, - [SDL_SCANCODE_W] = Q_KEY_CODE_W, - [SDL_SCANCODE_X] = Q_KEY_CODE_X, - [SDL_SCANCODE_Y] = Q_KEY_CODE_Y, - [SDL_SCANCODE_Z] = Q_KEY_CODE_Z, - - [SDL_SCANCODE_1] = Q_KEY_CODE_1, - [SDL_SCANCODE_2] = Q_KEY_CODE_2, - [SDL_SCANCODE_3] = Q_KEY_CODE_3, - [SDL_SCANCODE_4] = Q_KEY_CODE_4, - [SDL_SCANCODE_5] = Q_KEY_CODE_5, - [SDL_SCANCODE_6] = Q_KEY_CODE_6, - [SDL_SCANCODE_7] = Q_KEY_CODE_7, - [SDL_SCANCODE_8] = Q_KEY_CODE_8, - [SDL_SCANCODE_9] = Q_KEY_CODE_9, - [SDL_SCANCODE_0] = Q_KEY_CODE_0, - - [SDL_SCANCODE_RETURN] = Q_KEY_CODE_RET, - [SDL_SCANCODE_ESCAPE] = Q_KEY_CODE_ESC, - [SDL_SCANCODE_BACKSPACE] = Q_KEY_CODE_BACKSPACE, - [SDL_SCANCODE_TAB] = Q_KEY_CODE_TAB, - [SDL_SCANCODE_SPACE] = Q_KEY_CODE_SPC, - [SDL_SCANCODE_MINUS] = Q_KEY_CODE_MINUS, - [SDL_SCANCODE_EQUALS] = Q_KEY_CODE_EQUAL, - [SDL_SCANCODE_LEFTBRACKET] = Q_KEY_CODE_BRACKET_LEFT, - [SDL_SCANCODE_RIGHTBRACKET] = Q_KEY_CODE_BRACKET_RIGHT, - [SDL_SCANCODE_BACKSLASH] = Q_KEY_CODE_BACKSLASH, -#if 0 - [SDL_SCANCODE_NONUSHASH] = Q_KEY_CODE_NONUSHASH, -#endif - [SDL_SCANCODE_SEMICOLON] = Q_KEY_CODE_SEMICOLON, - [SDL_SCANCODE_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE, - [SDL_SCANCODE_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT, - [SDL_SCANCODE_COMMA] = Q_KEY_CODE_COMMA, - [SDL_SCANCODE_PERIOD] = Q_KEY_CODE_DOT, - [SDL_SCANCODE_SLASH] = Q_KEY_CODE_SLASH, - [SDL_SCANCODE_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK, - - [SDL_SCANCODE_F1] = Q_KEY_CODE_F1, - [SDL_SCANCODE_F2] = Q_KEY_CODE_F2, - [SDL_SCANCODE_F3] = Q_KEY_CODE_F3, - [SDL_SCANCODE_F4] = Q_KEY_CODE_F4, - [SDL_SCANCODE_F5] = Q_KEY_CODE_F5, - [SDL_SCANCODE_F6] = Q_KEY_CODE_F6, - [SDL_SCANCODE_F7] = Q_KEY_CODE_F7, - [SDL_SCANCODE_F8] = Q_KEY_CODE_F8, - [SDL_SCANCODE_F9] = Q_KEY_CODE_F9, - [SDL_SCANCODE_F10] = Q_KEY_CODE_F10, - [SDL_SCANCODE_F11] = Q_KEY_CODE_F11, - [SDL_SCANCODE_F12] = Q_KEY_CODE_F12, - - [SDL_SCANCODE_PRINTSCREEN] = Q_KEY_CODE_PRINT, - [SDL_SCANCODE_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK, - [SDL_SCANCODE_PAUSE] = Q_KEY_CODE_PAUSE, - [SDL_SCANCODE_INSERT] = Q_KEY_CODE_INSERT, - [SDL_SCANCODE_HOME] = Q_KEY_CODE_HOME, - [SDL_SCANCODE_PAGEUP] = Q_KEY_CODE_PGUP, - [SDL_SCANCODE_DELETE] = Q_KEY_CODE_DELETE, - [SDL_SCANCODE_END] = Q_KEY_CODE_END, - [SDL_SCANCODE_PAGEDOWN] = Q_KEY_CODE_PGDN, - [SDL_SCANCODE_RIGHT] = Q_KEY_CODE_RIGHT, - [SDL_SCANCODE_LEFT] = Q_KEY_CODE_LEFT, - [SDL_SCANCODE_DOWN] = Q_KEY_CODE_DOWN, - [SDL_SCANCODE_UP] = Q_KEY_CODE_UP, - [SDL_SCANCODE_NUMLOCKCLEAR] = Q_KEY_CODE_NUM_LOCK, - - [SDL_SCANCODE_KP_DIVIDE] = Q_KEY_CODE_KP_DIVIDE, - [SDL_SCANCODE_KP_MULTIPLY] = Q_KEY_CODE_KP_MULTIPLY, - [SDL_SCANCODE_KP_MINUS] = Q_KEY_CODE_KP_SUBTRACT, - [SDL_SCANCODE_KP_PLUS] = Q_KEY_CODE_KP_ADD, - [SDL_SCANCODE_KP_ENTER] = Q_KEY_CODE_KP_ENTER, - [SDL_SCANCODE_KP_1] = Q_KEY_CODE_KP_1, - [SDL_SCANCODE_KP_2] = Q_KEY_CODE_KP_2, - [SDL_SCANCODE_KP_3] = Q_KEY_CODE_KP_3, - [SDL_SCANCODE_KP_4] = Q_KEY_CODE_KP_4, - [SDL_SCANCODE_KP_5] = Q_KEY_CODE_KP_5, - [SDL_SCANCODE_KP_6] = Q_KEY_CODE_KP_6, - [SDL_SCANCODE_KP_7] = Q_KEY_CODE_KP_7, - [SDL_SCANCODE_KP_8] = Q_KEY_CODE_KP_8, - [SDL_SCANCODE_KP_9] = Q_KEY_CODE_KP_9, - [SDL_SCANCODE_KP_0] = Q_KEY_CODE_KP_0, - [SDL_SCANCODE_KP_PERIOD] = Q_KEY_CODE_KP_DECIMAL, - - [SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_LESS, - [SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_MENU, -#if 0 - [SDL_SCANCODE_POWER] = Q_KEY_CODE_POWER, - [SDL_SCANCODE_KP_EQUALS] = Q_KEY_CODE_KP_EQUALS, - - [SDL_SCANCODE_F13] = Q_KEY_CODE_F13, - [SDL_SCANCODE_F14] = Q_KEY_CODE_F14, - [SDL_SCANCODE_F15] = Q_KEY_CODE_F15, - [SDL_SCANCODE_F16] = Q_KEY_CODE_F16, - [SDL_SCANCODE_F17] = Q_KEY_CODE_F17, - [SDL_SCANCODE_F18] = Q_KEY_CODE_F18, - [SDL_SCANCODE_F19] = Q_KEY_CODE_F19, - [SDL_SCANCODE_F20] = Q_KEY_CODE_F20, - [SDL_SCANCODE_F21] = Q_KEY_CODE_F21, - [SDL_SCANCODE_F22] = Q_KEY_CODE_F22, - [SDL_SCANCODE_F23] = Q_KEY_CODE_F23, - [SDL_SCANCODE_F24] = Q_KEY_CODE_F24, - - [SDL_SCANCODE_EXECUTE] = Q_KEY_CODE_EXECUTE, -#endif - [SDL_SCANCODE_HELP] = Q_KEY_CODE_HELP, - [SDL_SCANCODE_MENU] = Q_KEY_CODE_MENU, -#if 0 - [SDL_SCANCODE_SELECT] = Q_KEY_CODE_SELECT, -#endif - [SDL_SCANCODE_STOP] = Q_KEY_CODE_STOP, - [SDL_SCANCODE_AGAIN] = Q_KEY_CODE_AGAIN, - [SDL_SCANCODE_UNDO] = Q_KEY_CODE_UNDO, - [SDL_SCANCODE_CUT] = Q_KEY_CODE_CUT, - [SDL_SCANCODE_COPY] = Q_KEY_CODE_COPY, - [SDL_SCANCODE_PASTE] = Q_KEY_CODE_PASTE, - [SDL_SCANCODE_FIND] = Q_KEY_CODE_FIND, -#if 0 - [SDL_SCANCODE_MUTE] = Q_KEY_CODE_MUTE, - [SDL_SCANCODE_VOLUMEUP] = Q_KEY_CODE_VOLUMEUP, - [SDL_SCANCODE_VOLUMEDOWN] = Q_KEY_CODE_VOLUMEDOWN, - - [SDL_SCANCODE_KP_COMMA] = Q_KEY_CODE_KP_COMMA, - [SDL_SCANCODE_KP_EQUALSAS400] = Q_KEY_CODE_KP_EQUALSAS400, - - [SDL_SCANCODE_INTERNATIONAL1] = Q_KEY_CODE_INTERNATIONAL1, - [SDL_SCANCODE_INTERNATIONAL2] = Q_KEY_CODE_INTERNATIONAL2, - [SDL_SCANCODE_INTERNATIONAL3] = Q_KEY_CODE_INTERNATIONAL3, - [SDL_SCANCODE_INTERNATIONAL4] = Q_KEY_CODE_INTERNATIONAL4, - [SDL_SCANCODE_INTERNATIONAL5] = Q_KEY_CODE_INTERNATIONAL5, - [SDL_SCANCODE_INTERNATIONAL6] = Q_KEY_CODE_INTERNATIONAL6, - [SDL_SCANCODE_INTERNATIONAL7] = Q_KEY_CODE_INTERNATIONAL7, - [SDL_SCANCODE_INTERNATIONAL8] = Q_KEY_CODE_INTERNATIONAL8, - [SDL_SCANCODE_INTERNATIONAL9] = Q_KEY_CODE_INTERNATIONAL9, - [SDL_SCANCODE_LANG1] = Q_KEY_CODE_LANG1, - [SDL_SCANCODE_LANG2] = Q_KEY_CODE_LANG2, - [SDL_SCANCODE_LANG3] = Q_KEY_CODE_LANG3, - [SDL_SCANCODE_LANG4] = Q_KEY_CODE_LANG4, - [SDL_SCANCODE_LANG5] = Q_KEY_CODE_LANG5, - [SDL_SCANCODE_LANG6] = Q_KEY_CODE_LANG6, - [SDL_SCANCODE_LANG7] = Q_KEY_CODE_LANG7, - [SDL_SCANCODE_LANG8] = Q_KEY_CODE_LANG8, - [SDL_SCANCODE_LANG9] = Q_KEY_CODE_LANG9, - [SDL_SCANCODE_ALTERASE] = Q_KEY_CODE_ALTERASE, -#endif - [SDL_SCANCODE_SYSREQ] = Q_KEY_CODE_SYSRQ, -#if 0 - [SDL_SCANCODE_CANCEL] = Q_KEY_CODE_CANCEL, - [SDL_SCANCODE_CLEAR] = Q_KEY_CODE_CLEAR, - [SDL_SCANCODE_PRIOR] = Q_KEY_CODE_PRIOR, - [SDL_SCANCODE_RETURN2] = Q_KEY_CODE_RETURN2, - [SDL_SCANCODE_SEPARATOR] = Q_KEY_CODE_SEPARATOR, - [SDL_SCANCODE_OUT] = Q_KEY_CODE_OUT, - [SDL_SCANCODE_OPER] = Q_KEY_CODE_OPER, - [SDL_SCANCODE_CLEARAGAIN] = Q_KEY_CODE_CLEARAGAIN, - [SDL_SCANCODE_CRSEL] = Q_KEY_CODE_CRSEL, - [SDL_SCANCODE_EXSEL] = Q_KEY_CODE_EXSEL, - [SDL_SCANCODE_KP_00] = Q_KEY_CODE_KP_00, - [SDL_SCANCODE_KP_000] = Q_KEY_CODE_KP_000, - [SDL_SCANCODE_THOUSANDSSEPARATOR] = Q_KEY_CODE_THOUSANDSSEPARATOR, - [SDL_SCANCODE_DECIMALSEPARATOR] = Q_KEY_CODE_DECIMALSEPARATOR, - [SDL_SCANCODE_CURRENCYUNIT] = Q_KEY_CODE_CURRENCYUNIT, - [SDL_SCANCODE_CURRENCYSUBUNIT] = Q_KEY_CODE_CURRENCYSUBUNIT, - [SDL_SCANCODE_KP_LEFTPAREN] = Q_KEY_CODE_KP_LEFTPAREN, - [SDL_SCANCODE_KP_RIGHTPAREN] = Q_KEY_CODE_KP_RIGHTPAREN, - [SDL_SCANCODE_KP_LEFTBRACE] = Q_KEY_CODE_KP_LEFTBRACE, - [SDL_SCANCODE_KP_RIGHTBRACE] = Q_KEY_CODE_KP_RIGHTBRACE, - [SDL_SCANCODE_KP_TAB] = Q_KEY_CODE_KP_TAB, - [SDL_SCANCODE_KP_BACKSPACE] = Q_KEY_CODE_KP_BACKSPACE, - [SDL_SCANCODE_KP_A] = Q_KEY_CODE_KP_A, - [SDL_SCANCODE_KP_B] = Q_KEY_CODE_KP_B, - [SDL_SCANCODE_KP_C] = Q_KEY_CODE_KP_C, - [SDL_SCANCODE_KP_D] = Q_KEY_CODE_KP_D, - [SDL_SCANCODE_KP_E] = Q_KEY_CODE_KP_E, - [SDL_SCANCODE_KP_F] = Q_KEY_CODE_KP_F, - [SDL_SCANCODE_KP_XOR] = Q_KEY_CODE_KP_XOR, - [SDL_SCANCODE_KP_POWER] = Q_KEY_CODE_KP_POWER, - [SDL_SCANCODE_KP_PERCENT] = Q_KEY_CODE_KP_PERCENT, - [SDL_SCANCODE_KP_LESS] = Q_KEY_CODE_KP_LESS, - [SDL_SCANCODE_KP_GREATER] = Q_KEY_CODE_KP_GREATER, - [SDL_SCANCODE_KP_AMPERSAND] = Q_KEY_CODE_KP_AMPERSAND, - [SDL_SCANCODE_KP_DBLAMPERSAND] = Q_KEY_CODE_KP_DBLAMPERSAND, - [SDL_SCANCODE_KP_VERTICALBAR] = Q_KEY_CODE_KP_VERTICALBAR, - [SDL_SCANCODE_KP_DBLVERTICALBAR] = Q_KEY_CODE_KP_DBLVERTICALBAR, - [SDL_SCANCODE_KP_COLON] = Q_KEY_CODE_KP_COLON, - [SDL_SCANCODE_KP_HASH] = Q_KEY_CODE_KP_HASH, - [SDL_SCANCODE_KP_SPACE] = Q_KEY_CODE_KP_SPACE, - [SDL_SCANCODE_KP_AT] = Q_KEY_CODE_KP_AT, - [SDL_SCANCODE_KP_EXCLAM] = Q_KEY_CODE_KP_EXCLAM, - [SDL_SCANCODE_KP_MEMSTORE] = Q_KEY_CODE_KP_MEMSTORE, - [SDL_SCANCODE_KP_MEMRECALL] = Q_KEY_CODE_KP_MEMRECALL, - [SDL_SCANCODE_KP_MEMCLEAR] = Q_KEY_CODE_KP_MEMCLEAR, - [SDL_SCANCODE_KP_MEMADD] = Q_KEY_CODE_KP_MEMADD, - [SDL_SCANCODE_KP_MEMSUBTRACT] = Q_KEY_CODE_KP_MEMSUBTRACT, - [SDL_SCANCODE_KP_MEMMULTIPLY] = Q_KEY_CODE_KP_MEMMULTIPLY, - [SDL_SCANCODE_KP_MEMDIVIDE] = Q_KEY_CODE_KP_MEMDIVIDE, - [SDL_SCANCODE_KP_PLUSMINUS] = Q_KEY_CODE_KP_PLUSMINUS, - [SDL_SCANCODE_KP_CLEAR] = Q_KEY_CODE_KP_CLEAR, - [SDL_SCANCODE_KP_CLEARENTRY] = Q_KEY_CODE_KP_CLEARENTRY, - [SDL_SCANCODE_KP_BINARY] = Q_KEY_CODE_KP_BINARY, - [SDL_SCANCODE_KP_OCTAL] = Q_KEY_CODE_KP_OCTAL, - [SDL_SCANCODE_KP_DECIMAL] = Q_KEY_CODE_KP_DECIMAL, - [SDL_SCANCODE_KP_HEXADECIMAL] = Q_KEY_CODE_KP_HEXADECIMAL, -#endif - [SDL_SCANCODE_LCTRL] = Q_KEY_CODE_CTRL, - [SDL_SCANCODE_LSHIFT] = Q_KEY_CODE_SHIFT, - [SDL_SCANCODE_LALT] = Q_KEY_CODE_ALT, - [SDL_SCANCODE_LGUI] = Q_KEY_CODE_META_L, - [SDL_SCANCODE_RCTRL] = Q_KEY_CODE_CTRL_R, - [SDL_SCANCODE_RSHIFT] = Q_KEY_CODE_SHIFT_R, - [SDL_SCANCODE_RALT] = Q_KEY_CODE_ALT_R, - [SDL_SCANCODE_RGUI] = Q_KEY_CODE_META_R, -#if 0 - [SDL_SCANCODE_MODE] = Q_KEY_CODE_MODE, - [SDL_SCANCODE_AUDIONEXT] = Q_KEY_CODE_AUDIONEXT, - [SDL_SCANCODE_AUDIOPREV] = Q_KEY_CODE_AUDIOPREV, - [SDL_SCANCODE_AUDIOSTOP] = Q_KEY_CODE_AUDIOSTOP, - [SDL_SCANCODE_AUDIOPLAY] = Q_KEY_CODE_AUDIOPLAY, - [SDL_SCANCODE_AUDIOMUTE] = Q_KEY_CODE_AUDIOMUTE, - [SDL_SCANCODE_MEDIASELECT] = Q_KEY_CODE_MEDIASELECT, - [SDL_SCANCODE_WWW] = Q_KEY_CODE_WWW, - [SDL_SCANCODE_MAIL] = Q_KEY_CODE_MAIL, - [SDL_SCANCODE_CALCULATOR] = Q_KEY_CODE_CALCULATOR, - [SDL_SCANCODE_COMPUTER] = Q_KEY_CODE_COMPUTER, - [SDL_SCANCODE_AC_SEARCH] = Q_KEY_CODE_AC_SEARCH, - [SDL_SCANCODE_AC_HOME] = Q_KEY_CODE_AC_HOME, - [SDL_SCANCODE_AC_BACK] = Q_KEY_CODE_AC_BACK, - [SDL_SCANCODE_AC_FORWARD] = Q_KEY_CODE_AC_FORWARD, - [SDL_SCANCODE_AC_STOP] = Q_KEY_CODE_AC_STOP, - [SDL_SCANCODE_AC_REFRESH] = Q_KEY_CODE_AC_REFRESH, - [SDL_SCANCODE_AC_BOOKMARKS] = Q_KEY_CODE_AC_BOOKMARKS, - [SDL_SCANCODE_BRIGHTNESSDOWN] = Q_KEY_CODE_BRIGHTNESSDOWN, - [SDL_SCANCODE_BRIGHTNESSUP] = Q_KEY_CODE_BRIGHTNESSUP, - [SDL_SCANCODE_DISPLAYSWITCH] = Q_KEY_CODE_DISPLAYSWITCH, - [SDL_SCANCODE_KBDILLUMTOGGLE] = Q_KEY_CODE_KBDILLUMTOGGLE, - [SDL_SCANCODE_KBDILLUMDOWN] = Q_KEY_CODE_KBDILLUMDOWN, - [SDL_SCANCODE_KBDILLUMUP] = Q_KEY_CODE_KBDILLUMUP, - [SDL_SCANCODE_EJECT] = Q_KEY_CODE_EJECT, - [SDL_SCANCODE_SLEEP] = Q_KEY_CODE_SLEEP, - [SDL_SCANCODE_APP1] = Q_KEY_CODE_APP1, - [SDL_SCANCODE_APP2] = Q_KEY_CODE_APP2, -#endif -}; diff --git a/qemu/ui/sdl2.c b/qemu/ui/sdl2.c deleted file mode 100644 index d0424421e..000000000 --- a/qemu/ui/sdl2.c +++ /dev/null @@ -1,837 +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. - */ -/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/console.h" -#include "ui/input.h" -#include "ui/sdl2.h" -#include "sysemu/sysemu.h" - -static int sdl2_num_outputs; -static struct sdl2_console *sdl2_console; - -static SDL_Surface *guest_sprite_surface; -static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ - -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_grab_code = KMOD_LALT | KMOD_LCTRL; -static SDL_Cursor *sdl_cursor_normal; -static SDL_Cursor *sdl_cursor_hidden; -static int absolute_enabled; -static int guest_cursor; -static int guest_x, guest_y; -static SDL_Cursor *guest_sprite; -static Notifier mouse_mode_notifier; - -#define SDL2_REFRESH_INTERVAL_BUSY 10 -#define SDL2_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \ - / SDL2_REFRESH_INTERVAL_BUSY + 1) - -static void sdl_update_caption(struct sdl2_console *scon); - -static struct sdl2_console *get_scon_from_window(uint32_t window_id) -{ - int i; - for (i = 0; i < sdl2_num_outputs; i++) { - if (sdl2_console[i].real_window == SDL_GetWindowFromID(window_id)) { - return &sdl2_console[i]; - } - } - return NULL; -} - -void sdl2_window_create(struct sdl2_console *scon) -{ - int flags = 0; - - if (!scon->surface) { - return; - } - assert(!scon->real_window); - - if (gui_fullscreen) { - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - } else { - flags |= SDL_WINDOW_RESIZABLE; - } - if (scon->hidden) { - flags |= SDL_WINDOW_HIDDEN; - } - - scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - surface_width(scon->surface), - surface_height(scon->surface), - flags); - scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); - if (scon->opengl) { - scon->winctx = SDL_GL_GetCurrentContext(); - } - sdl_update_caption(scon); -} - -void sdl2_window_destroy(struct sdl2_console *scon) -{ - if (!scon->real_window) { - return; - } - - SDL_DestroyRenderer(scon->real_renderer); - scon->real_renderer = NULL; - SDL_DestroyWindow(scon->real_window); - scon->real_window = NULL; -} - -void sdl2_window_resize(struct sdl2_console *scon) -{ - if (!scon->real_window) { - return; - } - - SDL_SetWindowSize(scon->real_window, - surface_width(scon->surface), - surface_height(scon->surface)); -} - -static void sdl2_redraw(struct sdl2_console *scon) -{ - if (scon->opengl) { -#ifdef CONFIG_OPENGL - sdl2_gl_redraw(scon); -#endif - } else { - sdl2_2d_redraw(scon); - } -} - -static void sdl_update_caption(struct sdl2_console *scon) -{ - char win_title[1024]; - char icon_title[1024]; - const char *status = ""; - - if (!runstate_is_running()) { - status = " [Stopped]"; - } else if (gui_grab) { - if (alt_grab) { - status = " - Press Ctrl-Alt-Shift to exit grab"; - } else if (ctrl_grab) { - status = " - Press Right-Ctrl to exit grab"; - } else { - status = " - Press Ctrl-Alt to exit grab"; - } - } - - if (qemu_name) { - snprintf(win_title, sizeof(win_title), "QEMU (%s-%d)%s", qemu_name, - scon->idx, 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"); - } - - if (scon->real_window) { - SDL_SetWindowTitle(scon->real_window, win_title); - } -} - -static void sdl_hide_cursor(void) -{ - if (!cursor_hide) { - return; - } - - if (qemu_input_is_absolute()) { - SDL_ShowCursor(1); - SDL_SetCursor(sdl_cursor_hidden); - } else { - SDL_SetRelativeMouseMode(SDL_TRUE); - } -} - -static void sdl_show_cursor(void) -{ - if (!cursor_hide) { - return; - } - - if (!qemu_input_is_absolute()) { - SDL_SetRelativeMouseMode(SDL_FALSE); - SDL_ShowCursor(1); - if (guest_cursor && - (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { - SDL_SetCursor(guest_sprite); - } else { - SDL_SetCursor(sdl_cursor_normal); - } - } -} - -static void sdl_grab_start(struct sdl2_console *scon) -{ - QemuConsole *con = scon ? scon->dcl.con : NULL; - - if (!con || !qemu_console_is_graphic(con)) { - return; - } - /* - * If the application is not active, do not try to enter grab state. This - * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the - * application (SDL bug). - */ - if (!(SDL_GetWindowFlags(scon->real_window) & SDL_WINDOW_INPUT_FOCUS)) { - return; - } - if (guest_cursor) { - SDL_SetCursor(guest_sprite); - if (!qemu_input_is_absolute() && !absolute_enabled) { - SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y); - } - } else { - sdl_hide_cursor(); - } - SDL_SetWindowGrab(scon->real_window, SDL_TRUE); - gui_grab = 1; - sdl_update_caption(scon); -} - -static void sdl_grab_end(struct sdl2_console *scon) -{ - SDL_SetWindowGrab(scon->real_window, SDL_FALSE); - gui_grab = 0; - sdl_show_cursor(); - sdl_update_caption(scon); -} - -static void absolute_mouse_grab(struct sdl2_console *scon) -{ - int mouse_x, mouse_y; - int scr_w, scr_h; - SDL_GetMouseState(&mouse_x, &mouse_y); - SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); - if (mouse_x > 0 && mouse_x < scr_w - 1 && - mouse_y > 0 && mouse_y < scr_h - 1) { - sdl_grab_start(scon); - } -} - -static void sdl_mouse_mode_change(Notifier *notify, void *data) -{ - if (qemu_input_is_absolute()) { - if (!absolute_enabled) { - absolute_enabled = 1; - absolute_mouse_grab(&sdl2_console[0]); - } - } else if (absolute_enabled) { - if (!gui_fullscreen) { - sdl_grab_end(&sdl2_console[0]); - } - absolute_enabled = 0; - } -} - -static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy, - int x, int y, int state) -{ - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT), - [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE), - [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT), - }; - static uint32_t prev_state; - - if (prev_state != state) { - qemu_input_update_buttons(scon->dcl.con, bmap, prev_state, state); - prev_state = state; - } - - if (qemu_input_is_absolute()) { - int scr_w, scr_h; - int max_w = 0, max_h = 0; - int off_x = 0, off_y = 0; - int cur_off_x = 0, cur_off_y = 0; - int i; - - for (i = 0; i < sdl2_num_outputs; i++) { - struct sdl2_console *thiscon = &sdl2_console[i]; - if (thiscon->real_window && thiscon->surface) { - SDL_GetWindowSize(thiscon->real_window, &scr_w, &scr_h); - cur_off_x = thiscon->x; - cur_off_y = thiscon->y; - if (scr_w + cur_off_x > max_w) { - max_w = scr_w + cur_off_x; - } - if (scr_h + cur_off_y > max_h) { - max_h = scr_h + cur_off_y; - } - if (i == scon->idx) { - off_x = cur_off_x; - off_y = cur_off_y; - } - } - } - qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w); - qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h); - } else { - if (guest_cursor) { - x -= guest_x; - y -= guest_y; - guest_x += x; - guest_y += y; - dx = x; - dy = y; - } - qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, dx); - qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, dy); - } - qemu_input_event_sync(); -} - -static void toggle_full_screen(struct sdl2_console *scon) -{ - gui_fullscreen = !gui_fullscreen; - if (gui_fullscreen) { - SDL_SetWindowFullscreen(scon->real_window, - SDL_WINDOW_FULLSCREEN_DESKTOP); - gui_saved_grab = gui_grab; - sdl_grab_start(scon); - } else { - if (!gui_saved_grab) { - sdl_grab_end(scon); - } - SDL_SetWindowFullscreen(scon->real_window, 0); - } - sdl2_redraw(scon); -} - -static void handle_keydown(SDL_Event *ev) -{ - int mod_state, win; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - - 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) { - switch (ev->key.keysym.scancode) { - case SDL_SCANCODE_2: - case SDL_SCANCODE_3: - case SDL_SCANCODE_4: - case SDL_SCANCODE_5: - case SDL_SCANCODE_6: - case SDL_SCANCODE_7: - case SDL_SCANCODE_8: - case SDL_SCANCODE_9: - win = ev->key.keysym.scancode - SDL_SCANCODE_1; - if (win < sdl2_num_outputs) { - sdl2_console[win].hidden = !sdl2_console[win].hidden; - if (sdl2_console[win].real_window) { - if (sdl2_console[win].hidden) { - SDL_HideWindow(sdl2_console[win].real_window); - } else { - SDL_ShowWindow(sdl2_console[win].real_window); - } - } - gui_keysym = 1; - } - break; - case SDL_SCANCODE_F: - toggle_full_screen(scon); - gui_keysym = 1; - break; - case SDL_SCANCODE_U: - sdl2_window_destroy(scon); - sdl2_window_create(scon); - if (!scon->opengl) { - /* re-create scon->texture */ - sdl2_2d_switch(&scon->dcl, scon->surface); - } - gui_keysym = 1; - break; -#if 0 - case SDL_SCANCODE_KP_PLUS: - case SDL_SCANCODE_KP_MINUS: - if (!gui_fullscreen) { - int scr_w, scr_h; - int width, height; - SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); - - width = MAX(scr_w + (ev->key.keysym.scancode == - SDL_SCANCODE_KP_PLUS ? 50 : -50), - 160); - height = (surface_height(scon->surface) * width) / - surface_width(scon->surface); - fprintf(stderr, "%s: scale to %dx%d\n", - __func__, width, height); - sdl_scale(scon, width, height); - sdl2_redraw(scon); - gui_keysym = 1; - } -#endif - default: - break; - } - } - if (!gui_keysym) { - sdl2_process_key(scon, &ev->key); - } -} - -static void handle_keyup(SDL_Event *ev) -{ - int mod_state; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - - 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 && gui_key_modifier_pressed) { - gui_key_modifier_pressed = 0; - if (gui_keysym == 0) { - /* exit/enter grab if pressing Ctrl-Alt */ - if (!gui_grab) { - sdl_grab_start(scon); - } else if (!gui_fullscreen) { - sdl_grab_end(scon); - } - /* SDL does not send back all the modifiers key, so we must - * correct it. */ - sdl2_reset_keys(scon); - return; - } - gui_keysym = 0; - } - if (!gui_keysym) { - sdl2_process_key(scon, &ev->key); - } -} - -static void handle_textinput(SDL_Event *ev) -{ - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - QemuConsole *con = scon ? scon->dcl.con : NULL; - - if (qemu_console_is_graphic(con)) { - return; - } - kbd_put_string_console(con, ev->text.text, strlen(ev->text.text)); -} - -static void handle_mousemotion(SDL_Event *ev) -{ - int max_x, max_y; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - - if (qemu_input_is_absolute() || absolute_enabled) { - int scr_w, scr_h; - SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); - max_x = scr_w - 1; - max_y = scr_h - 1; - if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 || - ev->motion.x == max_x || ev->motion.y == max_y)) { - sdl_grab_end(scon); - } - if (!gui_grab && - (ev->motion.x > 0 && ev->motion.x < max_x && - ev->motion.y > 0 && ev->motion.y < max_y)) { - sdl_grab_start(scon); - } - } - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, - ev->motion.x, ev->motion.y, ev->motion.state); - } -} - -static void handle_mousebutton(SDL_Event *ev) -{ - int buttonstate = SDL_GetMouseState(NULL, NULL); - SDL_MouseButtonEvent *bev; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - - bev = &ev->button; - if (!gui_grab && !qemu_input_is_absolute()) { - if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { - /* start grabbing all events */ - sdl_grab_start(scon); - } - } else { - if (ev->type == SDL_MOUSEBUTTONDOWN) { - buttonstate |= SDL_BUTTON(bev->button); - } else { - buttonstate &= ~SDL_BUTTON(bev->button); - } - sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate); - } -} - -static void handle_mousewheel(SDL_Event *ev) -{ - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); - SDL_MouseWheelEvent *wev = &ev->wheel; - InputButton btn; - - if (wev->y > 0) { - btn = INPUT_BUTTON_WHEEL_UP; - } else if (wev->y < 0) { - btn = INPUT_BUTTON_WHEEL_DOWN; - } else { - return; - } - - qemu_input_queue_btn(scon->dcl.con, btn, true); - qemu_input_event_sync(); - qemu_input_queue_btn(scon->dcl.con, btn, false); - qemu_input_event_sync(); -} - -static void handle_windowevent(SDL_Event *ev) -{ - struct sdl2_console *scon = get_scon_from_window(ev->window.windowID); - - if (!scon) { - return; - } - - switch (ev->window.event) { - case SDL_WINDOWEVENT_RESIZED: - { - QemuUIInfo info; - memset(&info, 0, sizeof(info)); - info.width = ev->window.data1; - info.height = ev->window.data2; - dpy_set_ui_info(scon->dcl.con, &info); - } - sdl2_redraw(scon); - break; - case SDL_WINDOWEVENT_EXPOSED: - sdl2_redraw(scon); - break; - case SDL_WINDOWEVENT_FOCUS_GAINED: - case SDL_WINDOWEVENT_ENTER: - if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { - absolute_mouse_grab(scon); - } - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - if (gui_grab && !gui_fullscreen) { - sdl_grab_end(scon); - } - break; - case SDL_WINDOWEVENT_RESTORED: - update_displaychangelistener(&scon->dcl, GUI_REFRESH_INTERVAL_DEFAULT); - break; - case SDL_WINDOWEVENT_MINIMIZED: - update_displaychangelistener(&scon->dcl, 500); - break; - case SDL_WINDOWEVENT_CLOSE: - if (!no_quit) { - no_shutdown = 0; - qemu_system_shutdown_request(); - } - break; - case SDL_WINDOWEVENT_SHOWN: - if (scon->hidden) { - SDL_HideWindow(scon->real_window); - } - break; - case SDL_WINDOWEVENT_HIDDEN: - if (!scon->hidden) { - SDL_ShowWindow(scon->real_window); - } - break; - } -} - -void sdl2_poll_events(struct sdl2_console *scon) -{ - SDL_Event ev1, *ev = &ev1; - int idle = 1; - - if (scon->last_vm_running != runstate_is_running()) { - scon->last_vm_running = runstate_is_running(); - sdl_update_caption(scon); - } - - while (SDL_PollEvent(ev)) { - switch (ev->type) { - case SDL_KEYDOWN: - idle = 0; - handle_keydown(ev); - break; - case SDL_KEYUP: - idle = 0; - handle_keyup(ev); - break; - case SDL_TEXTINPUT: - idle = 0; - handle_textinput(ev); - break; - case SDL_QUIT: - if (!no_quit) { - no_shutdown = 0; - qemu_system_shutdown_request(); - } - break; - case SDL_MOUSEMOTION: - idle = 0; - handle_mousemotion(ev); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - idle = 0; - handle_mousebutton(ev); - break; - case SDL_MOUSEWHEEL: - idle = 0; - handle_mousewheel(ev); - break; - case SDL_WINDOWEVENT: - handle_windowevent(ev); - break; - default: - break; - } - } - - if (idle) { - if (scon->idle_counter < SDL2_MAX_IDLE_COUNT) { - scon->idle_counter++; - if (scon->idle_counter >= SDL2_MAX_IDLE_COUNT) { - scon->dcl.update_interval = GUI_REFRESH_INTERVAL_DEFAULT; - } - } - } else { - scon->idle_counter = 0; - scon->dcl.update_interval = SDL2_REFRESH_INTERVAL_BUSY; - } -} - -static void sdl_mouse_warp(DisplayChangeListener *dcl, - int x, int y, int on) -{ - struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); - if (on) { - if (!guest_cursor) { - sdl_show_cursor(); - } - if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { - SDL_SetCursor(guest_sprite); - if (!qemu_input_is_absolute() && !absolute_enabled) { - SDL_WarpMouseInWindow(scon->real_window, x, y); - } - } - } else if (gui_grab) { - sdl_hide_cursor(); - } - guest_cursor = on; - guest_x = x, guest_y = y; -} - -static void sdl_mouse_define(DisplayChangeListener *dcl, - QEMUCursor *c) -{ - - if (guest_sprite) { - SDL_FreeCursor(guest_sprite); - } - - if (guest_sprite_surface) { - SDL_FreeSurface(guest_sprite_surface); - } - - guest_sprite_surface = - SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4, - 0xff0000, 0x00ff00, 0xff, 0xff000000); - - if (!guest_sprite_surface) { - fprintf(stderr, "Failed to make rgb surface from %p\n", c); - return; - } - guest_sprite = SDL_CreateColorCursor(guest_sprite_surface, - c->hot_x, c->hot_y); - if (!guest_sprite) { - fprintf(stderr, "Failed to make color cursor from %p\n", c); - return; - } - if (guest_cursor && - (gui_grab || qemu_input_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); -} - -static const DisplayChangeListenerOps dcl_2d_ops = { - .dpy_name = "sdl2-2d", - .dpy_gfx_update = sdl2_2d_update, - .dpy_gfx_switch = sdl2_2d_switch, - .dpy_gfx_check_format = sdl2_2d_check_format, - .dpy_refresh = sdl2_2d_refresh, - .dpy_mouse_set = sdl_mouse_warp, - .dpy_cursor_define = sdl_mouse_define, -}; - -#ifdef CONFIG_OPENGL -static const DisplayChangeListenerOps dcl_gl_ops = { - .dpy_name = "sdl2-gl", - .dpy_gfx_update = sdl2_gl_update, - .dpy_gfx_switch = sdl2_gl_switch, - .dpy_gfx_check_format = console_gl_check_format, - .dpy_refresh = sdl2_gl_refresh, - .dpy_mouse_set = sdl_mouse_warp, - .dpy_cursor_define = sdl_mouse_define, - - .dpy_gl_ctx_create = sdl2_gl_create_context, - .dpy_gl_ctx_destroy = sdl2_gl_destroy_context, - .dpy_gl_ctx_make_current = sdl2_gl_make_context_current, - .dpy_gl_ctx_get_current = sdl2_gl_get_current_context, - .dpy_gl_scanout = sdl2_gl_scanout, - .dpy_gl_update = sdl2_gl_scanout_flush, -}; -#endif - -void sdl_display_early_init(int opengl) -{ - switch (opengl) { - case -1: /* default */ - case 0: /* off */ - break; - case 1: /* on */ -#ifdef CONFIG_OPENGL - display_opengl = 1; -#endif - break; - default: - g_assert_not_reached(); - break; - } -} - -void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) -{ - int flags; - uint8_t data = 0; - char *filename; - int i; - - if (no_frame) { - gui_noframe = 1; - } - -#ifdef __linux__ - /* on Linux, SDL may use fbcon|directfb|svgalib when run without - * accessible $DISPLAY to open X11 window. This is often the case - * when qemu is run using sudo. But in this case, and when actually - * run in X11 environment, SDL fights with X11 for the video card, - * making current display unavailable, often until reboot. - * So make x11 the default SDL video driver if this variable is unset. - * This is a bit hackish but saves us from bigger problem. - * Maybe it's a good idea to fix this in SDL instead. - */ - setenv("SDL_VIDEODRIVER", "x11", 0); -#endif - - flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; - if (SDL_Init(flags)) { - fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", - SDL_GetError()); - exit(1); - } - SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); - - for (i = 0;; i++) { - QemuConsole *con = qemu_console_lookup_by_index(i); - if (!con) { - break; - } - } - sdl2_num_outputs = i; - sdl2_console = g_new0(struct sdl2_console, sdl2_num_outputs); - for (i = 0; i < sdl2_num_outputs; i++) { - QemuConsole *con = qemu_console_lookup_by_index(i); - if (!qemu_console_is_graphic(con)) { - sdl2_console[i].hidden = true; - } - sdl2_console[i].idx = i; -#ifdef CONFIG_OPENGL - sdl2_console[i].opengl = display_opengl; - sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops; -#else - sdl2_console[i].opengl = 0; - sdl2_console[i].dcl.ops = &dcl_2d_ops; -#endif - sdl2_console[i].dcl.con = con; - register_displaychangelistener(&sdl2_console[i].dcl); - } - - /* Load a 32x32x4 image. White pixels are transparent. */ - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); - if (filename) { - SDL_Surface *image = SDL_LoadBMP(filename); - if (image) { - uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255); - SDL_SetColorKey(image, SDL_TRUE, colorkey); - SDL_SetWindowIcon(sdl2_console[0].real_window, image); - } - g_free(filename); - } - - if (full_screen) { - gui_fullscreen = 1; - sdl_grab_start(0); - } - - mouse_mode_notifier.notify = sdl_mouse_mode_change; - qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); - - gui_grab = 0; - - sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); - sdl_cursor_normal = SDL_GetCursor(); - - atexit(sdl_cleanup); -} diff --git a/qemu/ui/sdl_keysym.h b/qemu/ui/sdl_keysym.h deleted file mode 100644 index 599d9fc64..000000000 --- a/qemu/ui/sdl_keysym.h +++ /dev/null @@ -1,278 +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}, -#if SDL_MAJOR_VERSION == 1 -{"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}, -#endif -{NULL, 0}, -}; diff --git a/qemu/ui/sdl_zoom.c b/qemu/ui/sdl_zoom.c deleted file mode 100644 index 72622c264..000000000 --- a/qemu/ui/sdl_zoom.c +++ /dev/null @@ -1,94 +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 "qemu/osdep.h" -#include "sdl_zoom.h" -#include <glib.h> - -static void sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth, - SDL_Rect *dst_rect); -static void 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/qemu/ui/sdl_zoom.h b/qemu/ui/sdl_zoom.h deleted file mode 100644 index 74955bc94..000000000 --- a/qemu/ui/sdl_zoom.h +++ /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/qemu/ui/sdl_zoom_template.h b/qemu/ui/sdl_zoom_template.h deleted file mode 100644 index 3bb508b51..000000000 --- a/qemu/ui/sdl_zoom_template.h +++ /dev/null @@ -1,219 +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 void 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); - } - - sax = g_new(int, dst->w + 1); - say = g_new(int, dst->h + 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); - } - } - - g_free(sax); - g_free(say); -} - -#undef SDL_TYPE - diff --git a/qemu/ui/shader.c b/qemu/ui/shader.c deleted file mode 100644 index 9264009b8..000000000 --- a/qemu/ui/shader.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * QEMU opengl shader helper functions - * - * Copyright (c) 2014 Red Hat - * - * Authors: - * Gerd Hoffmann <kraxel@redhat.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/osdep.h" -#include "qemu-common.h" -#include "ui/shader.h" - -/* ---------------------------------------------------------------------- */ - -GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog) -{ - static const GLfloat in_position[] = { - -1, -1, - 1, -1, - -1, 1, - 1, 1, - }; - GLint l_position; - GLuint vao, buffer; - - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - /* this is the VBO that holds the vertex data */ - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position, - GL_STATIC_DRAW); - - l_position = glGetAttribLocation(texture_blit_prog, "in_position"); - glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(l_position); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - return vao; -} - -void qemu_gl_run_texture_blit(GLint texture_blit_prog, - GLint texture_blit_vao) -{ - glUseProgram(texture_blit_prog); - glBindVertexArray(texture_blit_vao); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -} - -/* ---------------------------------------------------------------------- */ - -GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src) -{ - GLuint shader; - GLint status, length; - char *errmsg; - - shader = glCreateShader(type); - glShaderSource(shader, 1, &src, 0); - glCompileShader(shader); - - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (!status) { - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - errmsg = malloc(length); - glGetShaderInfoLog(shader, length, &length, errmsg); - fprintf(stderr, "%s: compile %s error\n%s\n", __func__, - (type == GL_VERTEX_SHADER) ? "vertex" : "fragment", - errmsg); - free(errmsg); - return 0; - } - return shader; -} - -GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag) -{ - GLuint program; - GLint status, length; - char *errmsg; - - program = glCreateProgram(); - glAttachShader(program, vert); - glAttachShader(program, frag); - glLinkProgram(program); - - glGetProgramiv(program, GL_LINK_STATUS, &status); - if (!status) { - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); - errmsg = malloc(length); - glGetProgramInfoLog(program, length, &length, errmsg); - fprintf(stderr, "%s: link program: %s\n", __func__, errmsg); - free(errmsg); - return 0; - } - return program; -} - -GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src, - const GLchar *frag_src) -{ - GLuint vert_shader, frag_shader, program; - - vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src); - frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src); - if (!vert_shader || !frag_shader) { - return 0; - } - - program = qemu_gl_create_link_program(vert_shader, frag_shader); - glDeleteShader(vert_shader); - glDeleteShader(frag_shader); - - return program; -} diff --git a/qemu/ui/shader/texture-blit.frag b/qemu/ui/shader/texture-blit.frag deleted file mode 100644 index bfa202c22..000000000 --- a/qemu/ui/shader/texture-blit.frag +++ /dev/null @@ -1,10 +0,0 @@ - -#version 300 es - -uniform sampler2D image; -in mediump vec2 ex_tex_coord; -out mediump vec4 out_frag_color; - -void main(void) { - out_frag_color = texture(image, ex_tex_coord); -} diff --git a/qemu/ui/shader/texture-blit.vert b/qemu/ui/shader/texture-blit.vert deleted file mode 100644 index 6fe2744d6..000000000 --- a/qemu/ui/shader/texture-blit.vert +++ /dev/null @@ -1,10 +0,0 @@ - -#version 300 es - -in vec2 in_position; -out vec2 ex_tex_coord; - -void main(void) { - gl_Position = vec4(in_position, 0.0, 1.0); - ex_tex_coord = vec2(1.0 + in_position.x, 1.0 - in_position.y) * 0.5; -} diff --git a/qemu/ui/spice-core.c b/qemu/ui/spice-core.c deleted file mode 100644 index 61db3c18b..000000000 --- a/qemu/ui/spice-core.c +++ /dev/null @@ -1,953 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program 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. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include <spice.h> - -#include <netdb.h> -#include "sysemu/sysemu.h" - -#include "qemu-common.h" -#include "ui/qemu-spice.h" -#include "qemu/error-report.h" -#include "qemu/thread.h" -#include "qemu/timer.h" -#include "qemu/queue.h" -#include "qemu-x509.h" -#include "qemu/sockets.h" -#include "qmp-commands.h" -#include "qapi/qmp/qint.h" -#include "qapi/qmp/qbool.h" -#include "qapi/qmp/qstring.h" -#include "qapi/qmp/qjson.h" -#include "qemu/notify.h" -#include "migration/migration.h" -#include "hw/hw.h" -#include "ui/spice-display.h" -#include "qapi-event.h" - -/* core bits */ - -static SpiceServer *spice_server; -static Notifier migration_state; -static const char *auth = "spice"; -static char *auth_passwd; -static time_t auth_expires = TIME_MAX; -static int spice_migration_completed; -static int spice_display_is_running; -static int spice_have_target_host; -int using_spice = 0; - -static QemuThread me; - -struct SpiceTimer { - QEMUTimer *timer; - QTAILQ_ENTRY(SpiceTimer) next; -}; -static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers); - -static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque) -{ - SpiceTimer *timer; - - timer = g_malloc0(sizeof(*timer)); - timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque); - QTAILQ_INSERT_TAIL(&timers, timer, next); - return timer; -} - -static void timer_start(SpiceTimer *timer, uint32_t ms) -{ - timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms); -} - -static void timer_cancel(SpiceTimer *timer) -{ - timer_del(timer->timer); -} - -static void timer_remove(SpiceTimer *timer) -{ - timer_del(timer->timer); - timer_free(timer->timer); - QTAILQ_REMOVE(&timers, timer, next); - g_free(timer); -} - -struct SpiceWatch { - int fd; - int event_mask; - SpiceWatchFunc func; - void *opaque; - QTAILQ_ENTRY(SpiceWatch) next; -}; -static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches); - -static void watch_read(void *opaque) -{ - SpiceWatch *watch = opaque; - watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque); -} - -static void watch_write(void *opaque) -{ - SpiceWatch *watch = opaque; - watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque); -} - -static void watch_update_mask(SpiceWatch *watch, int event_mask) -{ - IOHandler *on_read = NULL; - IOHandler *on_write = NULL; - - watch->event_mask = event_mask; - if (watch->event_mask & SPICE_WATCH_EVENT_READ) { - on_read = watch_read; - } - if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) { - on_write = watch_write; - } - qemu_set_fd_handler(watch->fd, on_read, on_write, watch); -} - -static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) -{ - SpiceWatch *watch; - - watch = g_malloc0(sizeof(*watch)); - watch->fd = fd; - watch->func = func; - watch->opaque = opaque; - QTAILQ_INSERT_TAIL(&watches, watch, next); - - watch_update_mask(watch, event_mask); - return watch; -} - -static void watch_remove(SpiceWatch *watch) -{ - qemu_set_fd_handler(watch->fd, NULL, NULL, NULL); - QTAILQ_REMOVE(&watches, watch, next); - g_free(watch); -} - -typedef struct ChannelList ChannelList; -struct ChannelList { - SpiceChannelEventInfo *info; - QTAILQ_ENTRY(ChannelList) link; -}; -static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list); - -static void channel_list_add(SpiceChannelEventInfo *info) -{ - ChannelList *item; - - item = g_malloc0(sizeof(*item)); - item->info = info; - QTAILQ_INSERT_TAIL(&channel_list, item, link); -} - -static void channel_list_del(SpiceChannelEventInfo *info) -{ - ChannelList *item; - - QTAILQ_FOREACH(item, &channel_list, link) { - if (item->info != info) { - continue; - } - QTAILQ_REMOVE(&channel_list, item, link); - g_free(item); - return; - } -} - -static void add_addr_info(SpiceBasicInfo *info, struct sockaddr *addr, int len) -{ - char host[NI_MAXHOST], port[NI_MAXSERV]; - - getnameinfo(addr, len, host, sizeof(host), port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV); - - info->host = g_strdup(host); - info->port = g_strdup(port); - info->family = inet_netfamily(addr->sa_family); -} - -static void add_channel_info(SpiceChannel *sc, SpiceChannelEventInfo *info) -{ - int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS; - - sc->connection_id = info->connection_id; - sc->channel_type = info->type; - sc->channel_id = info->id; - sc->tls = !!tls; -} - -static void channel_event(int event, SpiceChannelEventInfo *info) -{ - SpiceServerInfo *server = g_malloc0(sizeof(*server)); - SpiceChannel *client = g_malloc0(sizeof(*client)); - - /* - * Spice server might have called us from spice worker thread - * context (happens on display channel disconnects). Spice should - * not do that. It isn't that easy to fix it in spice and even - * when it is fixed we still should cover the already released - * spice versions. So detect that we've been called from another - * thread and grab the iothread lock if so before calling qemu - * functions. - */ - bool need_lock = !qemu_thread_is_self(&me); - if (need_lock) { - qemu_mutex_lock_iothread(); - } - - if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { - add_addr_info(qapi_SpiceChannel_base(client), - (struct sockaddr *)&info->paddr_ext, - info->plen_ext); - add_addr_info(qapi_SpiceServerInfo_base(server), - (struct sockaddr *)&info->laddr_ext, - info->llen_ext); - } else { - error_report("spice: %s, extended address is expected", - __func__); - } - - switch (event) { - case SPICE_CHANNEL_EVENT_CONNECTED: - qapi_event_send_spice_connected(qapi_SpiceServerInfo_base(server), - qapi_SpiceChannel_base(client), - &error_abort); - break; - case SPICE_CHANNEL_EVENT_INITIALIZED: - if (auth) { - server->has_auth = true; - server->auth = g_strdup(auth); - } - add_channel_info(client, info); - channel_list_add(info); - qapi_event_send_spice_initialized(server, client, &error_abort); - break; - case SPICE_CHANNEL_EVENT_DISCONNECTED: - channel_list_del(info); - qapi_event_send_spice_disconnected(qapi_SpiceServerInfo_base(server), - qapi_SpiceChannel_base(client), - &error_abort); - break; - default: - break; - } - - if (need_lock) { - qemu_mutex_unlock_iothread(); - } - - qapi_free_SpiceServerInfo(server); - qapi_free_SpiceChannel(client); -} - -static SpiceCoreInterface core_interface = { - .base.type = SPICE_INTERFACE_CORE, - .base.description = "qemu core services", - .base.major_version = SPICE_INTERFACE_CORE_MAJOR, - .base.minor_version = SPICE_INTERFACE_CORE_MINOR, - - .timer_add = timer_add, - .timer_start = timer_start, - .timer_cancel = timer_cancel, - .timer_remove = timer_remove, - - .watch_add = watch_add, - .watch_update_mask = watch_update_mask, - .watch_remove = watch_remove, - - .channel_event = channel_event, -}; - -static void migrate_connect_complete_cb(SpiceMigrateInstance *sin); -static void migrate_end_complete_cb(SpiceMigrateInstance *sin); - -static const SpiceMigrateInterface migrate_interface = { - .base.type = SPICE_INTERFACE_MIGRATION, - .base.description = "migration", - .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR, - .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR, - .migrate_connect_complete = migrate_connect_complete_cb, - .migrate_end_complete = migrate_end_complete_cb, -}; - -static SpiceMigrateInstance spice_migrate; - -static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) -{ - /* nothing, but libspice-server expects this cb being present. */ -} - -static void migrate_end_complete_cb(SpiceMigrateInstance *sin) -{ - qapi_event_send_spice_migrate_completed(&error_abort); - spice_migration_completed = true; -} - -/* config string parsing */ - -static int name2enum(const char *string, const char *table[], int entries) -{ - int i; - - if (string) { - for (i = 0; i < entries; i++) { - if (!table[i]) { - continue; - } - if (strcmp(string, table[i]) != 0) { - continue; - } - return i; - } - } - return -1; -} - -static int parse_name(const char *string, const char *optname, - const char *table[], int entries) -{ - int value = name2enum(string, table, entries); - - if (value != -1) { - return value; - } - error_report("spice: invalid %s: %s", optname, string); - exit(1); -} - -static const char *stream_video_names[] = { - [ SPICE_STREAM_VIDEO_OFF ] = "off", - [ SPICE_STREAM_VIDEO_ALL ] = "all", - [ SPICE_STREAM_VIDEO_FILTER ] = "filter", -}; -#define parse_stream_video(_name) \ - parse_name(_name, "stream video control", \ - stream_video_names, ARRAY_SIZE(stream_video_names)) - -static const char *compression_names[] = { - [ SPICE_IMAGE_COMPRESS_OFF ] = "off", - [ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz", - [ SPICE_IMAGE_COMPRESS_AUTO_LZ ] = "auto_lz", - [ SPICE_IMAGE_COMPRESS_QUIC ] = "quic", - [ SPICE_IMAGE_COMPRESS_GLZ ] = "glz", - [ SPICE_IMAGE_COMPRESS_LZ ] = "lz", -}; -#define parse_compression(_name) \ - parse_name(_name, "image compression", \ - compression_names, ARRAY_SIZE(compression_names)) - -static const char *wan_compression_names[] = { - [ SPICE_WAN_COMPRESSION_AUTO ] = "auto", - [ SPICE_WAN_COMPRESSION_NEVER ] = "never", - [ SPICE_WAN_COMPRESSION_ALWAYS ] = "always", -}; -#define parse_wan_compression(_name) \ - parse_name(_name, "wan compression", \ - wan_compression_names, ARRAY_SIZE(wan_compression_names)) - -/* functions for the rest of qemu */ - -static SpiceChannelList *qmp_query_spice_channels(void) -{ - SpiceChannelList *cur_item = NULL, *head = NULL; - ChannelList *item; - - QTAILQ_FOREACH(item, &channel_list, link) { - SpiceChannelList *chan; - char host[NI_MAXHOST], port[NI_MAXSERV]; - struct sockaddr *paddr; - socklen_t plen; - - assert(item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT); - - chan = g_malloc0(sizeof(*chan)); - chan->value = g_malloc0(sizeof(*chan->value)); - - paddr = (struct sockaddr *)&item->info->paddr_ext; - plen = item->info->plen_ext; - getnameinfo(paddr, plen, - host, sizeof(host), port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV); - chan->value->host = g_strdup(host); - chan->value->port = g_strdup(port); - chan->value->family = inet_netfamily(paddr->sa_family); - - chan->value->connection_id = item->info->connection_id; - chan->value->channel_type = item->info->type; - chan->value->channel_id = item->info->id; - chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS; - - /* XXX: waiting for the qapi to support GSList */ - if (!cur_item) { - head = cur_item = chan; - } else { - cur_item->next = chan; - cur_item = chan; - } - } - - return head; -} - -static QemuOptsList qemu_spice_opts = { - .name = "spice", - .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), - .desc = { - { - .name = "port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "tls-port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "addr", - .type = QEMU_OPT_STRING, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, -#ifdef SPICE_ADDR_FLAG_UNIX_ONLY - },{ - .name = "unix", - .type = QEMU_OPT_BOOL, -#endif - },{ - .name = "password", - .type = QEMU_OPT_STRING, - },{ - .name = "disable-ticketing", - .type = QEMU_OPT_BOOL, - },{ - .name = "disable-copy-paste", - .type = QEMU_OPT_BOOL, - },{ - .name = "disable-agent-file-xfer", - .type = QEMU_OPT_BOOL, - },{ - .name = "sasl", - .type = QEMU_OPT_BOOL, - },{ - .name = "x509-dir", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-password", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cacert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-dh-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-ciphers", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "plaintext-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "image-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "jpeg-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "zlib-glz-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "streaming-video", - .type = QEMU_OPT_STRING, - },{ - .name = "agent-mouse", - .type = QEMU_OPT_BOOL, - },{ - .name = "playback-compression", - .type = QEMU_OPT_BOOL, - },{ - .name = "seamless-migration", - .type = QEMU_OPT_BOOL, -#ifdef HAVE_SPICE_GL - },{ - .name = "gl", - .type = QEMU_OPT_BOOL, -#endif - }, - { /* end of list */ } - }, -}; - -SpiceInfo *qmp_query_spice(Error **errp) -{ - QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); - int port, tls_port; - const char *addr; - SpiceInfo *info; - unsigned int major; - unsigned int minor; - unsigned int micro; - - info = g_malloc0(sizeof(*info)); - - if (!spice_server || !opts) { - info->enabled = false; - return info; - } - - info->enabled = true; - info->migrated = spice_migration_completed; - - addr = qemu_opt_get(opts, "addr"); - port = qemu_opt_get_number(opts, "port", 0); - tls_port = qemu_opt_get_number(opts, "tls-port", 0); - - info->has_auth = true; - info->auth = g_strdup(auth); - - info->has_host = true; - info->host = g_strdup(addr ? addr : "*"); - - info->has_compiled_version = true; - major = (SPICE_SERVER_VERSION & 0xff0000) >> 16; - minor = (SPICE_SERVER_VERSION & 0xff00) >> 8; - micro = SPICE_SERVER_VERSION & 0xff; - info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro); - - if (port) { - info->has_port = true; - info->port = port; - } - if (tls_port) { - info->has_tls_port = true; - info->tls_port = tls_port; - } - - info->mouse_mode = spice_server_is_server_mouse(spice_server) ? - SPICE_QUERY_MOUSE_MODE_SERVER : - SPICE_QUERY_MOUSE_MODE_CLIENT; - - /* for compatibility with the original command */ - info->has_channels = true; - info->channels = qmp_query_spice_channels(); - - return info; -} - -static void migration_state_notifier(Notifier *notifier, void *data) -{ - MigrationState *s = data; - - if (!spice_have_target_host) { - return; - } - - if (migration_in_setup(s)) { - spice_server_migrate_start(spice_server); - } else if (migration_has_finished(s) || - migration_in_postcopy_after_devices(s)) { - spice_server_migrate_end(spice_server, true); - spice_have_target_host = false; - } else if (migration_has_failed(s)) { - spice_server_migrate_end(spice_server, false); - spice_have_target_host = false; - } -} - -int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, - const char *subject) -{ - int ret; - - ret = spice_server_migrate_connect(spice_server, hostname, - port, tls_port, subject); - spice_have_target_host = true; - return ret; -} - -static int add_channel(void *opaque, const char *name, const char *value, - Error **errp) -{ - int security = 0; - int rc; - - if (strcmp(name, "tls-channel") == 0) { - int *tls_port = opaque; - if (!*tls_port) { - error_report("spice: tried to setup tls-channel" - " without specifying a TLS port"); - exit(1); - } - security = SPICE_CHANNEL_SECURITY_SSL; - } - if (strcmp(name, "plaintext-channel") == 0) { - security = SPICE_CHANNEL_SECURITY_NONE; - } - if (security == 0) { - return 0; - } - if (strcmp(value, "default") == 0) { - rc = spice_server_set_channel_security(spice_server, NULL, security); - } else { - rc = spice_server_set_channel_security(spice_server, value, security); - } - if (rc != 0) { - error_report("spice: failed to set channel security for %s", value); - exit(1); - } - return 0; -} - -static void vm_change_state_handler(void *opaque, int running, - RunState state) -{ - if (running) { - qemu_spice_display_start(); - } else { - qemu_spice_display_stop(); - } -} - -void qemu_spice_init(void) -{ - QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); - const char *password, *str, *x509_dir, *addr, - *x509_key_password = NULL, - *x509_dh_file = NULL, - *tls_ciphers = NULL; - char *x509_key_file = NULL, - *x509_cert_file = NULL, - *x509_cacert_file = NULL; - int port, tls_port, addr_flags; - spice_image_compression_t compression; - spice_wan_compression_t wan_compr; - bool seamless_migration; - - qemu_thread_get_self(&me); - - if (!opts) { - return; - } - port = qemu_opt_get_number(opts, "port", 0); - tls_port = qemu_opt_get_number(opts, "tls-port", 0); - if (port < 0 || port > 65535) { - error_report("spice port is out of range"); - exit(1); - } - if (tls_port < 0 || tls_port > 65535) { - error_report("spice tls-port is out of range"); - exit(1); - } - password = qemu_opt_get(opts, "password"); - - if (tls_port) { - x509_dir = qemu_opt_get(opts, "x509-dir"); - if (!x509_dir) { - x509_dir = "."; - } - - str = qemu_opt_get(opts, "x509-key-file"); - if (str) { - x509_key_file = g_strdup(str); - } else { - x509_key_file = g_strdup_printf("%s/%s", x509_dir, - X509_SERVER_KEY_FILE); - } - - str = qemu_opt_get(opts, "x509-cert-file"); - if (str) { - x509_cert_file = g_strdup(str); - } else { - x509_cert_file = g_strdup_printf("%s/%s", x509_dir, - X509_SERVER_CERT_FILE); - } - - str = qemu_opt_get(opts, "x509-cacert-file"); - if (str) { - x509_cacert_file = g_strdup(str); - } else { - x509_cacert_file = g_strdup_printf("%s/%s", x509_dir, - X509_CA_CERT_FILE); - } - - x509_key_password = qemu_opt_get(opts, "x509-key-password"); - x509_dh_file = qemu_opt_get(opts, "x509-dh-key-file"); - tls_ciphers = qemu_opt_get(opts, "tls-ciphers"); - } - - addr = qemu_opt_get(opts, "addr"); - addr_flags = 0; - if (qemu_opt_get_bool(opts, "ipv4", 0)) { - addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY; - } else if (qemu_opt_get_bool(opts, "ipv6", 0)) { - addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY; -#ifdef SPICE_ADDR_FLAG_UNIX_ONLY - } else if (qemu_opt_get_bool(opts, "unix", 0)) { - addr_flags |= SPICE_ADDR_FLAG_UNIX_ONLY; -#endif - } - - spice_server = spice_server_new(); - spice_server_set_addr(spice_server, addr ? addr : "", addr_flags); - if (port) { - spice_server_set_port(spice_server, port); - } - if (tls_port) { - spice_server_set_tls(spice_server, tls_port, - x509_cacert_file, - x509_cert_file, - x509_key_file, - x509_key_password, - x509_dh_file, - tls_ciphers); - } - if (password) { - qemu_spice_set_passwd(password, false, false); - } - if (qemu_opt_get_bool(opts, "sasl", 0)) { - if (spice_server_set_sasl(spice_server, 1) == -1) { - error_report("spice: failed to enable sasl"); - exit(1); - } - auth = "sasl"; - } - if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) { - auth = "none"; - spice_server_set_noauth(spice_server); - } - - if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) { - spice_server_set_agent_copypaste(spice_server, false); - } - - if (qemu_opt_get_bool(opts, "disable-agent-file-xfer", 0)) { -#if SPICE_SERVER_VERSION >= 0x000c04 - spice_server_set_agent_file_xfer(spice_server, false); -#else - error_report("this qemu build does not support the " - "\"disable-agent-file-xfer\" option"); - exit(1); -#endif - } - - compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ; - str = qemu_opt_get(opts, "image-compression"); - if (str) { - compression = parse_compression(str); - } - spice_server_set_image_compression(spice_server, compression); - - wan_compr = SPICE_WAN_COMPRESSION_AUTO; - str = qemu_opt_get(opts, "jpeg-wan-compression"); - if (str) { - wan_compr = parse_wan_compression(str); - } - spice_server_set_jpeg_compression(spice_server, wan_compr); - - wan_compr = SPICE_WAN_COMPRESSION_AUTO; - str = qemu_opt_get(opts, "zlib-glz-wan-compression"); - if (str) { - wan_compr = parse_wan_compression(str); - } - spice_server_set_zlib_glz_compression(spice_server, wan_compr); - - str = qemu_opt_get(opts, "streaming-video"); - if (str) { - int streaming_video = parse_stream_video(str); - spice_server_set_streaming_video(spice_server, streaming_video); - } else { - spice_server_set_streaming_video(spice_server, SPICE_STREAM_VIDEO_OFF); - } - - spice_server_set_agent_mouse - (spice_server, qemu_opt_get_bool(opts, "agent-mouse", 1)); - spice_server_set_playback_compression - (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1)); - - qemu_opt_foreach(opts, add_channel, &tls_port, NULL); - - spice_server_set_name(spice_server, qemu_name); - spice_server_set_uuid(spice_server, qemu_uuid); - - seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); - spice_server_set_seamless_migration(spice_server, seamless_migration); - spice_server_set_sasl_appname(spice_server, "qemu"); - if (spice_server_init(spice_server, &core_interface) != 0) { - error_report("failed to initialize spice server"); - exit(1); - }; - using_spice = 1; - - migration_state.notify = migration_state_notifier; - add_migration_state_change_notifier(&migration_state); - spice_migrate.base.sif = &migrate_interface.base; - qemu_spice_add_interface(&spice_migrate.base); - - qemu_spice_input_init(); - qemu_spice_audio_init(); - - qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); - qemu_spice_display_stop(); - - g_free(x509_key_file); - g_free(x509_cert_file); - g_free(x509_cacert_file); - -#if SPICE_SERVER_VERSION >= 0x000c02 - qemu_spice_register_ports(); -#endif - -#ifdef HAVE_SPICE_GL - if (qemu_opt_get_bool(opts, "gl", 0)) { - if ((port != 0) || (tls_port != 0)) { - error_report("SPICE GL support is local-only for now and " - "incompatible with -spice port/tls-port"); - exit(1); - } - if (egl_rendernode_init() == 0) { - display_opengl = 1; - } - } -#endif -} - -int qemu_spice_add_interface(SpiceBaseInstance *sin) -{ - if (!spice_server) { - if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) { - error_report("Oops: spice configured but not active"); - exit(1); - } - /* - * Create a spice server instance. - * It does *not* listen on the network. - * It handles QXL local rendering only. - * - * With a command line like '-vnc :0 -vga qxl' you'll end up here. - */ - spice_server = spice_server_new(); - spice_server_set_sasl_appname(spice_server, "qemu"); - spice_server_init(spice_server, &core_interface); - qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); - } - - return spice_server_add_interface(spice_server, sin); -} - -static GSList *spice_consoles; - -bool qemu_spice_have_display_interface(QemuConsole *con) -{ - if (g_slist_find(spice_consoles, con)) { - return true; - } - return false; -} - -int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con) -{ - if (g_slist_find(spice_consoles, con)) { - return -1; - } - qxlin->id = qemu_console_get_index(con); - spice_consoles = g_slist_append(spice_consoles, con); - return qemu_spice_add_interface(&qxlin->base); -} - -static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn) -{ - time_t lifetime, now = time(NULL); - char *passwd; - - if (now < auth_expires) { - passwd = auth_passwd; - lifetime = (auth_expires - now); - if (lifetime > INT_MAX) { - lifetime = INT_MAX; - } - } else { - passwd = NULL; - lifetime = 1; - } - return spice_server_set_ticket(spice_server, passwd, lifetime, - fail_if_conn, disconnect_if_conn); -} - -int qemu_spice_set_passwd(const char *passwd, - bool fail_if_conn, bool disconnect_if_conn) -{ - if (strcmp(auth, "spice") != 0) { - return -1; - } - - g_free(auth_passwd); - auth_passwd = g_strdup(passwd); - return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn); -} - -int qemu_spice_set_pw_expire(time_t expires) -{ - auth_expires = expires; - return qemu_spice_set_ticket(false, false); -} - -int qemu_spice_display_add_client(int csock, int skipauth, int tls) -{ - if (tls) { - return spice_server_add_ssl_client(spice_server, csock, skipauth); - } else { - return spice_server_add_client(spice_server, csock, skipauth); - } -} - -void qemu_spice_display_start(void) -{ - spice_display_is_running = true; - spice_server_vm_start(spice_server); -} - -void qemu_spice_display_stop(void) -{ - spice_server_vm_stop(spice_server); - spice_display_is_running = false; -} - -int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) -{ - return spice_display_is_running; -} - -static void spice_register_config(void) -{ - qemu_add_opts(&qemu_spice_opts); -} -opts_init(spice_register_config); diff --git a/qemu/ui/spice-display.c b/qemu/ui/spice-display.c deleted file mode 100644 index 242ab5f46..000000000 --- a/qemu/ui/spice-display.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program 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. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "ui/qemu-spice.h" -#include "qemu/timer.h" -#include "qemu/queue.h" -#include "ui/console.h" -#include "sysemu/sysemu.h" -#include "trace.h" - -#include "ui/spice-display.h" - -static int debug = 0; - -static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...) -{ - va_list args; - - if (level <= debug) { - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - } -} - -int qemu_spice_rect_is_empty(const QXLRect* r) -{ - return r->top == r->bottom || r->left == r->right; -} - -void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) -{ - if (qemu_spice_rect_is_empty(r)) { - return; - } - - if (qemu_spice_rect_is_empty(dest)) { - *dest = *r; - return; - } - - dest->top = MIN(dest->top, r->top); - dest->left = MIN(dest->left, r->left); - dest->bottom = MAX(dest->bottom, r->bottom); - dest->right = MAX(dest->right, r->right); -} - -QXLCookie *qxl_cookie_new(int type, uint64_t io) -{ - QXLCookie *cookie; - - cookie = g_malloc0(sizeof(*cookie)); - cookie->type = type; - cookie->io = io; - return cookie; -} - -void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - qxl_async_io async) -{ - trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id, - memslot->virt_start, memslot->virt_end, - async); - - if (async != QXL_SYNC) { - spice_qxl_add_memslot_async(&ssd->qxl, memslot, - (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_MEMSLOT_ADD_ASYNC)); - } else { - spice_qxl_add_memslot(&ssd->qxl, memslot); - } -} - -void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) -{ - trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid); - spice_qxl_del_memslot(&ssd->qxl, gid, sid); -} - -void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - QXLDevSurfaceCreate *surface, - qxl_async_io async) -{ - trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); - if (async != QXL_SYNC) { - spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, - (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_CREATE_PRIMARY_ASYNC)); - } else { - spice_qxl_create_primary_surface(&ssd->qxl, id, surface); - } -} - -void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - uint32_t id, qxl_async_io async) -{ - trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); - if (async != QXL_SYNC) { - spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, - (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_DESTROY_PRIMARY_ASYNC)); - } else { - spice_qxl_destroy_primary_surface(&ssd->qxl, id); - } -} - -void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) -{ - trace_qemu_spice_wakeup(ssd->qxl.id); - spice_qxl_wakeup(&ssd->qxl); -} - -static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, - QXLRect *rect) -{ - SimpleSpiceUpdate *update; - QXLDrawable *drawable; - QXLImage *image; - QXLCommand *cmd; - int bw, bh; - struct timespec time_space; - pixman_image_t *dest; - - trace_qemu_spice_create_update( - rect->left, rect->right, - rect->top, rect->bottom); - - update = g_malloc0(sizeof(*update)); - drawable = &update->drawable; - image = &update->image; - cmd = &update->ext.cmd; - - bw = rect->right - rect->left; - bh = rect->bottom - rect->top; - update->bitmap = g_malloc(bw * bh * 4); - - drawable->bbox = *rect; - drawable->clip.type = SPICE_CLIP_TYPE_NONE; - drawable->effect = QXL_EFFECT_OPAQUE; - drawable->release_info.id = (uintptr_t)(&update->ext); - drawable->type = QXL_DRAW_COPY; - drawable->surfaces_dest[0] = -1; - drawable->surfaces_dest[1] = -1; - drawable->surfaces_dest[2] = -1; - clock_gettime(CLOCK_MONOTONIC, &time_space); - /* time in milliseconds from epoch. */ - drawable->mm_time = time_space.tv_sec * 1000 - + time_space.tv_nsec / 1000 / 1000; - - drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; - drawable->u.copy.src_bitmap = (uintptr_t)image; - drawable->u.copy.src_area.right = bw; - drawable->u.copy.src_area.bottom = bh; - - QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++); - image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; - image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; - image->bitmap.stride = bw * 4; - image->descriptor.width = image->bitmap.x = bw; - image->descriptor.height = image->bitmap.y = bh; - image->bitmap.data = (uintptr_t)(update->bitmap); - image->bitmap.palette = 0; - image->bitmap.format = SPICE_BITMAP_FMT_32BIT; - - dest = pixman_image_create_bits(PIXMAN_LE_x8r8g8b8, bw, bh, - (void *)update->bitmap, bw * 4); - pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror, - rect->left, rect->top, 0, 0, - rect->left, rect->top, bw, bh); - pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest, - rect->left, rect->top, 0, 0, - 0, 0, bw, bh); - pixman_image_unref(dest); - - cmd->type = QXL_CMD_DRAW; - cmd->data = (uintptr_t)drawable; - - QTAILQ_INSERT_TAIL(&ssd->updates, update, next); -} - -static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) -{ - static const int blksize = 32; - int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize; - int dirty_top[blocks]; - int y, yoff1, yoff2, x, xoff, blk, bw; - int bpp = surface_bytes_per_pixel(ssd->ds); - uint8_t *guest, *mirror; - - if (qemu_spice_rect_is_empty(&ssd->dirty)) { - return; - }; - - for (blk = 0; blk < blocks; blk++) { - dirty_top[blk] = -1; - } - - guest = surface_data(ssd->ds); - mirror = (void *)pixman_image_get_data(ssd->mirror); - for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { - yoff1 = y * surface_stride(ssd->ds); - yoff2 = y * pixman_image_get_stride(ssd->mirror); - for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { - xoff = x * bpp; - blk = x / blksize; - bw = MIN(blksize, ssd->dirty.right - x); - if (memcmp(guest + yoff1 + xoff, - mirror + yoff2 + xoff, - bw * bpp) == 0) { - if (dirty_top[blk] != -1) { - QXLRect update = { - .top = dirty_top[blk], - .bottom = y, - .left = x, - .right = x + bw, - }; - qemu_spice_create_one_update(ssd, &update); - dirty_top[blk] = -1; - } - } else { - if (dirty_top[blk] == -1) { - dirty_top[blk] = y; - } - } - } - } - - for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { - blk = x / blksize; - bw = MIN(blksize, ssd->dirty.right - x); - if (dirty_top[blk] != -1) { - QXLRect update = { - .top = dirty_top[blk], - .bottom = ssd->dirty.bottom, - .left = x, - .right = x + bw, - }; - qemu_spice_create_one_update(ssd, &update); - dirty_top[blk] = -1; - } - } - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); -} - -static SimpleSpiceCursor* -qemu_spice_create_cursor_update(SimpleSpiceDisplay *ssd, - QEMUCursor *c, - int on) -{ - size_t size = c ? c->width * c->height * 4 : 0; - SimpleSpiceCursor *update; - QXLCursorCmd *ccmd; - QXLCursor *cursor; - QXLCommand *cmd; - - update = g_malloc0(sizeof(*update) + size); - ccmd = &update->cmd; - cursor = &update->cursor; - cmd = &update->ext.cmd; - - if (c) { - ccmd->type = QXL_CURSOR_SET; - ccmd->u.set.position.x = ssd->ptr_x + ssd->hot_x; - ccmd->u.set.position.y = ssd->ptr_y + ssd->hot_y; - ccmd->u.set.visible = true; - ccmd->u.set.shape = (uintptr_t)cursor; - cursor->header.unique = ssd->unique++; - cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; - cursor->header.width = c->width; - cursor->header.height = c->height; - cursor->header.hot_spot_x = c->hot_x; - cursor->header.hot_spot_y = c->hot_y; - cursor->data_size = size; - cursor->chunk.data_size = size; - memcpy(cursor->chunk.data, c->data, size); - } else if (!on) { - ccmd->type = QXL_CURSOR_HIDE; - } else { - ccmd->type = QXL_CURSOR_MOVE; - ccmd->u.position.x = ssd->ptr_x + ssd->hot_x; - ccmd->u.position.y = ssd->ptr_y + ssd->hot_y; - } - ccmd->release_info.id = (uintptr_t)(&update->ext); - - cmd->type = QXL_CMD_CURSOR; - cmd->data = (uintptr_t)ccmd; - - return update; -} - -/* - * Called from spice server thread context (via interface_release_resource) - * We do *not* hold the global qemu mutex here, so extra care is needed - * when calling qemu functions. QEMU interfaces used: - * - g_free (underlying glibc free is re-entrant). - */ -void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update) -{ - g_free(update->bitmap); - g_free(update); -} - -void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) -{ - QXLDevMemSlot memslot; - - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); - - memset(&memslot, 0, sizeof(memslot)); - memslot.slot_group_id = MEMSLOT_GROUP_HOST; - memslot.virt_end = ~0; - qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC); -} - -void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) -{ - QXLDevSurfaceCreate surface; - uint64_t surface_size; - - memset(&surface, 0, sizeof(surface)); - - surface_size = (uint64_t) surface_width(ssd->ds) * - surface_height(ssd->ds) * 4; - assert(surface_size > 0); - assert(surface_size < INT_MAX); - if (ssd->bufsize < surface_size) { - ssd->bufsize = surface_size; - g_free(ssd->buf); - ssd->buf = g_malloc(ssd->bufsize); - } - - dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id, - surface_width(ssd->ds), surface_height(ssd->ds), - surface_size, ssd->bufsize); - - surface.format = SPICE_SURFACE_FMT_32_xRGB; - surface.width = surface_width(ssd->ds); - surface.height = surface_height(ssd->ds); - surface.stride = -surface.width * 4; - surface.mouse_mode = true; - surface.flags = 0; - surface.type = 0; - surface.mem = (uintptr_t)ssd->buf; - surface.group_id = MEMSLOT_GROUP_HOST; - - qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); -} - -void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) -{ - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); - - qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); -} - -void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd) -{ - qemu_mutex_init(&ssd->lock); - QTAILQ_INIT(&ssd->updates); - ssd->mouse_x = -1; - ssd->mouse_y = -1; - if (ssd->num_surfaces == 0) { - ssd->num_surfaces = 1024; - } -} - -/* display listener callbacks */ - -void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - int x, int y, int w, int h) -{ - QXLRect update_area; - - dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__, - ssd->qxl.id, x, y, w, h); - update_area.left = x, - update_area.right = x + w; - update_area.top = y; - update_area.bottom = y + h; - - if (qemu_spice_rect_is_empty(&ssd->dirty)) { - ssd->notify++; - } - qemu_spice_rect_union(&ssd->dirty, &update_area); -} - -void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, - DisplaySurface *surface) -{ - SimpleSpiceUpdate *update; - bool need_destroy; - - if (surface && ssd->surface && - surface_width(surface) == pixman_image_get_width(ssd->surface) && - surface_height(surface) == pixman_image_get_height(ssd->surface) && - surface_format(surface) == pixman_image_get_format(ssd->surface)) { - /* no-resize fast path: just swap backing store */ - dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id, - surface_width(surface), surface_height(surface)); - qemu_mutex_lock(&ssd->lock); - ssd->ds = surface; - pixman_image_unref(ssd->surface); - ssd->surface = pixman_image_ref(ssd->ds->image); - qemu_mutex_unlock(&ssd->lock); - qemu_spice_display_update(ssd, 0, 0, - surface_width(surface), - surface_height(surface)); - return; - } - - /* full mode switch */ - dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id, - ssd->surface ? pixman_image_get_width(ssd->surface) : 0, - ssd->surface ? pixman_image_get_height(ssd->surface) : 0, - surface ? surface_width(surface) : 0, - surface ? surface_height(surface) : 0); - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - if (ssd->surface) { - pixman_image_unref(ssd->surface); - ssd->surface = NULL; - pixman_image_unref(ssd->mirror); - ssd->mirror = NULL; - } - - qemu_mutex_lock(&ssd->lock); - need_destroy = (ssd->ds != NULL); - ssd->ds = surface; - while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { - QTAILQ_REMOVE(&ssd->updates, update, next); - qemu_spice_destroy_update(ssd, update); - } - qemu_mutex_unlock(&ssd->lock); - if (need_destroy) { - qemu_spice_destroy_host_primary(ssd); - } - if (ssd->ds) { - ssd->surface = pixman_image_ref(ssd->ds->image); - ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, - ssd->ds->image); - qemu_spice_create_host_primary(ssd); - } - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - ssd->notify++; - - qemu_mutex_lock(&ssd->lock); - if (ssd->cursor) { - g_free(ssd->ptr_define); - ssd->ptr_define = qemu_spice_create_cursor_update(ssd, ssd->cursor, 0); - } - qemu_mutex_unlock(&ssd->lock); -} - -static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) -{ - if (ssd->cursor) { - assert(ssd->dcl.con); - dpy_cursor_define(ssd->dcl.con, ssd->cursor); - } - if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { - assert(ssd->dcl.con); - dpy_mouse_set(ssd->dcl.con, ssd->mouse_x, ssd->mouse_y, 1); - ssd->mouse_x = -1; - ssd->mouse_y = -1; - } -} - -void qemu_spice_cursor_refresh_bh(void *opaque) -{ - SimpleSpiceDisplay *ssd = opaque; - - qemu_mutex_lock(&ssd->lock); - qemu_spice_cursor_refresh_unlocked(ssd); - qemu_mutex_unlock(&ssd->lock); -} - -void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) -{ - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); - graphic_hw_update(ssd->dcl.con); - - qemu_mutex_lock(&ssd->lock); - if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { - qemu_spice_create_update(ssd); - ssd->notify++; - } - qemu_mutex_unlock(&ssd->lock); - - if (ssd->notify) { - ssd->notify = 0; - qemu_spice_wakeup(ssd); - dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id); - } -} - -/* spice display interface callbacks */ - -static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); - ssd->worker = qxl_worker; -} - -static void interface_set_compression_level(QXLInstance *sin, int level) -{ - dprint(1, "%s/%d:\n", __func__, sin->id); - /* nothing to do */ -} - -static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) -{ - dprint(3, "%s/%d:\n", __func__, sin->id); - /* nothing to do */ -} - -static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - - info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; - info->memslot_id_bits = MEMSLOT_SLOT_BITS; - info->num_memslots = NUM_MEMSLOTS; - info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; - info->internal_groupslot_id = 0; - info->qxl_ram_size = 16 * 1024 * 1024; - info->n_surfaces = ssd->num_surfaces; -} - -static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - SimpleSpiceUpdate *update; - int ret = false; - - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); - - qemu_mutex_lock(&ssd->lock); - update = QTAILQ_FIRST(&ssd->updates); - if (update != NULL) { - QTAILQ_REMOVE(&ssd->updates, update, next); - *ext = update->ext; - ret = true; - } - qemu_mutex_unlock(&ssd->lock); - - return ret; -} - -static int interface_req_cmd_notification(QXLInstance *sin) -{ - dprint(2, "%s/%d:\n", __func__, sin->id); - return 1; -} - -static void interface_release_resource(QXLInstance *sin, - QXLReleaseInfoExt rext) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - SimpleSpiceUpdate *update; - SimpleSpiceCursor *cursor; - QXLCommandExt *ext; - - dprint(2, "%s/%d:\n", __func__, ssd->qxl.id); - ext = (void *)(intptr_t)(rext.info->id); - switch (ext->cmd.type) { - case QXL_CMD_DRAW: - update = container_of(ext, SimpleSpiceUpdate, ext); - qemu_spice_destroy_update(ssd, update); - break; - case QXL_CMD_CURSOR: - cursor = container_of(ext, SimpleSpiceCursor, ext); - g_free(cursor); - break; - default: - g_assert_not_reached(); - } -} - -static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - int ret; - - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); - - qemu_mutex_lock(&ssd->lock); - if (ssd->ptr_define) { - *ext = ssd->ptr_define->ext; - ssd->ptr_define = NULL; - ret = true; - } else if (ssd->ptr_move) { - *ext = ssd->ptr_move->ext; - ssd->ptr_move = NULL; - ret = true; - } else { - ret = false; - } - qemu_mutex_unlock(&ssd->lock); - return ret; -} - -static int interface_req_cursor_notification(QXLInstance *sin) -{ - dprint(2, "%s:\n", __func__); - return 1; -} - -static void interface_notify_update(QXLInstance *sin, uint32_t update_id) -{ - fprintf(stderr, "%s: abort()\n", __FUNCTION__); - abort(); -} - -static int interface_flush_resources(QXLInstance *sin) -{ - fprintf(stderr, "%s: abort()\n", __FUNCTION__); - abort(); - return 0; -} - -static void interface_update_area_complete(QXLInstance *sin, - uint32_t surface_id, - QXLRect *dirty, uint32_t num_updated_rects) -{ - /* should never be called, used in qxl native mode only */ - fprintf(stderr, "%s: abort()\n", __func__); - abort(); -} - -/* called from spice server thread context only */ -static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) -{ - QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; - - switch (cookie->type) { -#ifdef HAVE_SPICE_GL - case QXL_COOKIE_TYPE_GL_DRAW_DONE: - { - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - qemu_bh_schedule(ssd->gl_unblock_bh); - break; - } -#endif - default: - /* should never be called, used in qxl native mode only */ - fprintf(stderr, "%s: abort()\n", __func__); - abort(); - } - g_free(cookie); -} - -static void interface_set_client_capabilities(QXLInstance *sin, - uint8_t client_present, - uint8_t caps[58]) -{ - dprint(3, "%s:\n", __func__); -} - -static int interface_client_monitors_config(QXLInstance *sin, - VDAgentMonitorsConfig *mc) -{ - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - QemuUIInfo info; - - if (!dpy_ui_info_supported(ssd->dcl.con)) { - return 0; /* == not supported by guest */ - } - - if (!mc) { - return 1; - } - - /* - * FIXME: multihead is tricky due to the way - * spice has multihead implemented. - */ - memset(&info, 0, sizeof(info)); - if (mc->num_of_monitors > 0) { - info.width = mc->monitors[0].width; - info.height = mc->monitors[0].height; - } - dpy_set_ui_info(ssd->dcl.con, &info); - dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id, - info.width, info.height); - return 1; -} - -static const QXLInterface dpy_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qemu simple display", - .base.major_version = SPICE_INTERFACE_QXL_MAJOR, - .base.minor_version = SPICE_INTERFACE_QXL_MINOR, - - .attache_worker = interface_attach_worker, - .set_compression_level = interface_set_compression_level, - .set_mm_time = interface_set_mm_time, - .get_init_info = interface_get_init_info, - - /* the callbacks below are called from spice server thread context */ - .get_command = interface_get_command, - .req_cmd_notification = interface_req_cmd_notification, - .release_resource = interface_release_resource, - .get_cursor_command = interface_get_cursor_command, - .req_cursor_notification = interface_req_cursor_notification, - .notify_update = interface_notify_update, - .flush_resources = interface_flush_resources, - .async_complete = interface_async_complete, - .update_area_complete = interface_update_area_complete, - .set_client_capabilities = interface_set_client_capabilities, - .client_monitors_config = interface_client_monitors_config, -}; - -static void display_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - qemu_spice_display_update(ssd, x, y, w, h); -} - -static void display_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - qemu_spice_display_switch(ssd, surface); -} - -static void display_refresh(DisplayChangeListener *dcl) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - qemu_spice_display_refresh(ssd); -} - -static void display_mouse_set(DisplayChangeListener *dcl, - int x, int y, int on) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - - qemu_mutex_lock(&ssd->lock); - ssd->ptr_x = x; - ssd->ptr_y = y; - g_free(ssd->ptr_move); - ssd->ptr_move = qemu_spice_create_cursor_update(ssd, NULL, on); - qemu_mutex_unlock(&ssd->lock); -} - -static void display_mouse_define(DisplayChangeListener *dcl, - QEMUCursor *c) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - - qemu_mutex_lock(&ssd->lock); - if (c) { - cursor_get(c); - } - cursor_put(ssd->cursor); - ssd->cursor = c; - ssd->hot_x = c->hot_x; - ssd->hot_y = c->hot_y; - g_free(ssd->ptr_move); - ssd->ptr_move = NULL; - g_free(ssd->ptr_define); - ssd->ptr_define = qemu_spice_create_cursor_update(ssd, c, 0); - qemu_mutex_unlock(&ssd->lock); -} - -static const DisplayChangeListenerOps display_listener_ops = { - .dpy_name = "spice", - .dpy_gfx_update = display_update, - .dpy_gfx_switch = display_switch, - .dpy_gfx_check_format = qemu_pixman_check_format, - .dpy_refresh = display_refresh, - .dpy_mouse_set = display_mouse_set, - .dpy_cursor_define = display_mouse_define, -}; - -#ifdef HAVE_SPICE_GL - -static void qemu_spice_gl_block(SimpleSpiceDisplay *ssd, bool block) -{ - uint64_t timeout; - - if (block) { - timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - timeout += 1000; /* one sec */ - timer_mod(ssd->gl_unblock_timer, timeout); - } else { - timer_del(ssd->gl_unblock_timer); - } - graphic_hw_gl_block(ssd->dcl.con, block); -} - -static void qemu_spice_gl_unblock_bh(void *opaque) -{ - SimpleSpiceDisplay *ssd = opaque; - - qemu_spice_gl_block(ssd, false); -} - -static void qemu_spice_gl_block_timer(void *opaque) -{ - fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n"); -} - -static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl, - QEMUGLParams *params) -{ - eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, - qemu_egl_rn_ctx); - return qemu_egl_create_context(dcl, params); -} - -static void qemu_spice_gl_scanout(DisplayChangeListener *dcl, - uint32_t tex_id, - bool y_0_top, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - EGLint stride = 0, fourcc = 0; - int fd = -1; - - if (tex_id) { - fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc); - if (fd < 0) { - fprintf(stderr, "%s: failed to get fd for texture\n", __func__); - return; - } - dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__, - w, h, stride, fourcc); - } else { - dprint(1, "%s: no texture (no framebuffer)\n", __func__); - } - - assert(!tex_id || fd >= 0); - - /* note: spice server will close the fd */ - spice_qxl_gl_scanout(&ssd->qxl, fd, - surface_width(ssd->ds), - surface_height(ssd->ds), - stride, fourcc, y_0_top); -} - -static void qemu_spice_gl_update(DisplayChangeListener *dcl, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - uint64_t cookie; - - dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); - qemu_spice_gl_block(ssd, true); - cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); - spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie); -} - -static const DisplayChangeListenerOps display_listener_gl_ops = { - .dpy_name = "spice-egl", - .dpy_gfx_update = display_update, - .dpy_gfx_switch = display_switch, - .dpy_gfx_check_format = qemu_pixman_check_format, - .dpy_refresh = display_refresh, - .dpy_mouse_set = display_mouse_set, - .dpy_cursor_define = display_mouse_define, - - .dpy_gl_ctx_create = qemu_spice_gl_create_context, - .dpy_gl_ctx_destroy = qemu_egl_destroy_context, - .dpy_gl_ctx_make_current = qemu_egl_make_context_current, - .dpy_gl_ctx_get_current = qemu_egl_get_current_context, - - .dpy_gl_scanout = qemu_spice_gl_scanout, - .dpy_gl_update = qemu_spice_gl_update, -}; - -#endif /* HAVE_SPICE_GL */ - -static void qemu_spice_display_init_one(QemuConsole *con) -{ - SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1); - - qemu_spice_display_init_common(ssd); - - ssd->dcl.ops = &display_listener_ops; -#ifdef HAVE_SPICE_GL - if (display_opengl) { - ssd->dcl.ops = &display_listener_gl_ops; - ssd->dmabuf_fd = -1; - ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); - ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, - qemu_spice_gl_block_timer, ssd); - } -#endif - ssd->dcl.con = con; - - ssd->qxl.base.sif = &dpy_interface.base; - qemu_spice_add_display_interface(&ssd->qxl, con); - assert(ssd->worker); - qemu_spice_create_host_memslot(ssd); - - register_displaychangelistener(&ssd->dcl); -} - -void qemu_spice_display_init(void) -{ - QemuConsole *con; - int i; - - for (i = 0;; i++) { - con = qemu_console_lookup_by_index(i); - if (!con || !qemu_console_is_graphic(con)) { - break; - } - if (qemu_spice_have_display_interface(con)) { - continue; - } - qemu_spice_display_init_one(con); - } -} diff --git a/qemu/ui/spice-input.c b/qemu/ui/spice-input.c deleted file mode 100644 index 8eeebdbb2..000000000 --- a/qemu/ui/spice-input.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program 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. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" - -#include <spice.h> -#include <spice/enums.h> - -#include "qemu-common.h" -#include "ui/qemu-spice.h" -#include "ui/console.h" -#include "ui/keymaps.h" -#include "ui/input.h" - -/* keyboard bits */ - -typedef struct QemuSpiceKbd { - SpiceKbdInstance sin; - int ledstate; - bool emul0; -} QemuSpiceKbd; - -static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag); -static uint8_t kbd_get_leds(SpiceKbdInstance *sin); -static void kbd_leds(void *opaque, int l); - -static const SpiceKbdInterface kbd_interface = { - .base.type = SPICE_INTERFACE_KEYBOARD, - .base.description = "qemu keyboard", - .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, - .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, - .push_scan_freg = kbd_push_key, - .get_leds = kbd_get_leds, -}; - -static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode) -{ - QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); - int keycode; - bool up; - - if (scancode == SCANCODE_EMUL0) { - kbd->emul0 = true; - return; - } - keycode = scancode & ~SCANCODE_UP; - up = scancode & SCANCODE_UP; - if (kbd->emul0) { - kbd->emul0 = false; - keycode |= SCANCODE_GREY; - } - - qemu_input_event_send_key_number(NULL, keycode, !up); -} - -static uint8_t kbd_get_leds(SpiceKbdInstance *sin) -{ - QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); - return kbd->ledstate; -} - -static void kbd_leds(void *opaque, int ledstate) -{ - QemuSpiceKbd *kbd = opaque; - - kbd->ledstate = 0; - if (ledstate & QEMU_SCROLL_LOCK_LED) { - kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK; - } - if (ledstate & QEMU_NUM_LOCK_LED) { - kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK; - } - if (ledstate & QEMU_CAPS_LOCK_LED) { - kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK; - } - spice_server_kbd_leds(&kbd->sin, ledstate); -} - -/* mouse bits */ - -typedef struct QemuSpicePointer { - SpiceMouseInstance mouse; - SpiceTabletInstance tablet; - int width, height; - uint32_t last_bmask; - Notifier mouse_mode; - bool absolute; -} QemuSpicePointer; - -static void spice_update_buttons(QemuSpicePointer *pointer, - int wheel, uint32_t button_mask) -{ - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = 0x01, - [INPUT_BUTTON_MIDDLE] = 0x04, - [INPUT_BUTTON_RIGHT] = 0x02, - [INPUT_BUTTON_WHEEL_UP] = 0x10, - [INPUT_BUTTON_WHEEL_DOWN] = 0x20, - }; - - if (wheel < 0) { - button_mask |= 0x10; - } - if (wheel > 0) { - button_mask |= 0x20; - } - - if (pointer->last_bmask == button_mask) { - return; - } - qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask); - pointer->last_bmask = button_mask; -} - -static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz, - uint32_t buttons_state) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse); - spice_update_buttons(pointer, dz, buttons_state); - qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); - qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); - qemu_input_event_sync(); -} - -static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse); - spice_update_buttons(pointer, 0, buttons_state); - qemu_input_event_sync(); -} - -static const SpiceMouseInterface mouse_interface = { - .base.type = SPICE_INTERFACE_MOUSE, - .base.description = "mouse", - .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR, - .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR, - .motion = mouse_motion, - .buttons = mouse_buttons, -}; - -static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - - if (height < 16) { - height = 16; - } - if (width < 16) { - width = 16; - } - pointer->width = width; - pointer->height = height; -} - -static void tablet_position(SpiceTabletInstance* sin, int x, int y, - uint32_t buttons_state) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - - spice_update_buttons(pointer, 0, buttons_state); - qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width); - qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->height); - qemu_input_event_sync(); -} - - -static void tablet_wheel(SpiceTabletInstance* sin, int wheel, - uint32_t buttons_state) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - - spice_update_buttons(pointer, wheel, buttons_state); - qemu_input_event_sync(); -} - -static void tablet_buttons(SpiceTabletInstance *sin, - uint32_t buttons_state) -{ - QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - - spice_update_buttons(pointer, 0, buttons_state); - qemu_input_event_sync(); -} - -static const SpiceTabletInterface tablet_interface = { - .base.type = SPICE_INTERFACE_TABLET, - .base.description = "tablet", - .base.major_version = SPICE_INTERFACE_TABLET_MAJOR, - .base.minor_version = SPICE_INTERFACE_TABLET_MINOR, - .set_logical_size = tablet_set_logical_size, - .position = tablet_position, - .wheel = tablet_wheel, - .buttons = tablet_buttons, -}; - -static void mouse_mode_notifier(Notifier *notifier, void *data) -{ - QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); - bool is_absolute = qemu_input_is_absolute(); - - if (pointer->absolute == is_absolute) { - return; - } - - if (is_absolute) { - qemu_spice_add_interface(&pointer->tablet.base); - } else { - spice_server_remove_interface(&pointer->tablet.base); - } - pointer->absolute = is_absolute; -} - -void qemu_spice_input_init(void) -{ - QemuSpiceKbd *kbd; - QemuSpicePointer *pointer; - - kbd = g_malloc0(sizeof(*kbd)); - kbd->sin.base.sif = &kbd_interface.base; - qemu_spice_add_interface(&kbd->sin.base); - qemu_add_led_event_handler(kbd_leds, kbd); - - pointer = g_malloc0(sizeof(*pointer)); - pointer->mouse.base.sif = &mouse_interface.base; - pointer->tablet.base.sif = &tablet_interface.base; - qemu_spice_add_interface(&pointer->mouse.base); - - pointer->absolute = false; - pointer->mouse_mode.notify = mouse_mode_notifier; - qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode); - mouse_mode_notifier(&pointer->mouse_mode, NULL); -} diff --git a/qemu/ui/vgafont.h b/qemu/ui/vgafont.h deleted file mode 100644 index 3606dd733..000000000 --- a/qemu/ui/vgafont.h +++ /dev/null @@ -1,4611 +0,0 @@ -static const uint8_t vgafont16[256 * 16] = { - - /* 0 0x00 '^@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 1 0x01 '^A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x81, /* 10000001 */ - 0xa5, /* 10100101 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 2 0x02 '^B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xdb, /* 11011011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 3 0x03 '^C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 4 0x04 '^D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 5 0x05 '^E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 6 0x06 '^F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 7 0x07 '^G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 8 0x08 '^H' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xe7, /* 11100111 */ - 0xc3, /* 11000011 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 9 0x09 '^I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x42, /* 01000010 */ - 0x42, /* 01000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 10 0x0a '^J' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0x99, /* 10011001 */ - 0xbd, /* 10111101 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0xc3, /* 11000011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 11 0x0b '^K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x1a, /* 00011010 */ - 0x32, /* 00110010 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 12 0x0c '^L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 13 0x0d '^M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x33, /* 00110011 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x70, /* 01110000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 14 0x0e '^N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x67, /* 01100111 */ - 0xe7, /* 11100111 */ - 0xe6, /* 11100110 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 15 0x0f '^O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xdb, /* 11011011 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0x3c, /* 00111100 */ - 0xdb, /* 11011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 16 0x10 '^P' */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0xf0, /* 11110000 */ - 0xf8, /* 11111000 */ - 0xfe, /* 11111110 */ - 0xf8, /* 11111000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 17 0x11 '^Q' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0e, /* 00001110 */ - 0x1e, /* 00011110 */ - 0x3e, /* 00111110 */ - 0xfe, /* 11111110 */ - 0x3e, /* 00111110 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 18 0x12 '^R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 19 0x13 '^S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 20 0x14 '^T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7b, /* 01111011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 21 0x15 '^U' */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 22 0x16 '^V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 23 0x17 '^W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 24 0x18 '^X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 25 0x19 '^Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 26 0x1a '^Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 27 0x1b '^[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xfe, /* 11111110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 28 0x1c '^\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 29 0x1d '^]' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x28, /* 00101000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x28, /* 00101000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 30 0x1e '^^' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 31 0x1f '^_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 32 0x20 ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 33 0x21 '!' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 34 0x22 '"' */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x24, /* 00100100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 35 0x23 '#' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 36 0x24 '$' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x86, /* 10000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 37 0x25 '%' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 38 0x26 '&' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 39 0x27 ''' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 40 0x28 '(' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 41 0x29 ')' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 42 0x2a '*' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0xff, /* 11111111 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 43 0x2b '+' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 44 0x2c ',' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 45 0x2d '-' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 46 0x2e '.' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 47 0x2f '/' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 48 0x30 '0' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 49 0x31 '1' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x38, /* 00111000 */ - 0x78, /* 01111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 50 0x32 '2' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 51 0x33 '3' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x3c, /* 00111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 52 0x34 '4' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x1c, /* 00011100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 53 0x35 '5' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 54 0x36 '6' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 55 0x37 '7' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 56 0x38 '8' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 57 0x39 '9' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 58 0x3a ':' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 59 0x3b ';' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 60 0x3c '<' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 61 0x3d '=' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 62 0x3e '>' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 63 0x3f '?' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 64 0x40 '@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xdc, /* 11011100 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 65 0x41 'A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 66 0x42 'B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 67 0x43 'C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 68 0x44 'D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 69 0x45 'E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 70 0x46 'F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 71 0x47 'G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xde, /* 11011110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x66, /* 01100110 */ - 0x3a, /* 00111010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 72 0x48 'H' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 73 0x49 'I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 74 0x4a 'J' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 75 0x4b 'K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe6, /* 11100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 76 0x4c 'L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 77 0x4d 'M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xee, /* 11101110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 78 0x4e 'N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 79 0x4f 'O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 80 0x50 'P' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 81 0x51 'Q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xde, /* 11011110 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 82 0x52 'R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 83 0x53 'S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 84 0x54 'T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x5a, /* 01011010 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 85 0x55 'U' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 86 0x56 'V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 87 0x57 'W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0xee, /* 11101110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 88 0x58 'X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 89 0x59 'Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 90 0x5a 'Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 91 0x5b '[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 92 0x5c '\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0x70, /* 01110000 */ - 0x38, /* 00111000 */ - 0x1c, /* 00011100 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 93 0x5d ']' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 94 0x5e '^' */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 95 0x5f '_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 96 0x60 '`' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 97 0x61 'a' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 98 0x62 'b' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 99 0x63 'c' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 100 0x64 'd' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 101 0x65 'e' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 102 0x66 'f' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x36, /* 00110110 */ - 0x32, /* 00110010 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 103 0x67 'g' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 104 0x68 'h' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x6c, /* 01101100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 105 0x69 'i' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 106 0x6a 'j' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - - /* 107 0x6b 'k' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 108 0x6c 'l' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 109 0x6d 'm' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 110 0x6e 'n' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 111 0x6f 'o' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 112 0x70 'p' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - - /* 113 0x71 'q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - - /* 114 0x72 'r' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 115 0x73 's' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 116 0x74 't' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0xfc, /* 11111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x36, /* 00110110 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 117 0x75 'u' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 118 0x76 'v' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 119 0x77 'w' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 120 0x78 'x' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 121 0x79 'y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - - /* 122 0x7a 'z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 123 0x7b '{' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 124 0x7c '|' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 125 0x7d '}' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 126 0x7e '~' */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 127 0x7f '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 128 0x80 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 129 0x81 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 130 0x82 '' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 131 0x83 '' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 132 0x84 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 133 0x85 '
' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 134 0x86 '' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 135 0x87 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 136 0x88 '' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 137 0x89 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 138 0x8a '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 139 0x8b '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 140 0x8c '' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 141 0x8d '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 142 0x8e '' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 143 0x8f '' */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 144 0x90 '' */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 145 0x91 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x6e, /* 01101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 146 0x92 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3e, /* 00111110 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xce, /* 11001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 147 0x93 '' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 148 0x94 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 149 0x95 '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 150 0x96 '' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 151 0x97 '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 152 0x98 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 153 0x99 '' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 154 0x9a '' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 155 0x9b '' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 156 0x9c '' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x64, /* 01100100 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xe6, /* 11100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 157 0x9d '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 158 0x9e '' */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xf8, /* 11111000 */ - 0xc4, /* 11000100 */ - 0xcc, /* 11001100 */ - 0xde, /* 11011110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 159 0x9f '' */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 160 0xa0 ' ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 161 0xa1 '¡' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 162 0xa2 '¢' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 163 0xa3 '£' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 164 0xa4 '¤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 165 0xa5 '¥' */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 166 0xa6 '¦' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 167 0xa7 '§' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 168 0xa8 '¨' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 169 0xa9 '©' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 170 0xaa 'ª' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 171 0xab '«' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xdc, /* 11011100 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 172 0xac '¬' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x66, /* 01100110 */ - 0xce, /* 11001110 */ - 0x9a, /* 10011010 */ - 0x3f, /* 00111111 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 173 0xad '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 174 0xae '®' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 175 0xaf '¯' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 176 0xb0 '°' */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - - /* 177 0xb1 '±' */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - - /* 178 0xb2 '²' */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - - /* 179 0xb3 '³' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 180 0xb4 '´' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 181 0xb5 'µ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 182 0xb6 '¶' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 183 0xb7 '·' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 184 0xb8 '¸' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 185 0xb9 '¹' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 186 0xba 'º' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 187 0xbb '»' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 188 0xbc '¼' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 189 0xbd '½' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 190 0xbe '¾' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 191 0xbf '¿' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 192 0xc0 'À' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 193 0xc1 'Á' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 194 0xc2 'Â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 195 0xc3 'Ã' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 196 0xc4 'Ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 197 0xc5 'Å' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 198 0xc6 'Æ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 199 0xc7 'Ç' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 200 0xc8 'È' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 201 0xc9 'É' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 202 0xca 'Ê' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 203 0xcb 'Ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 204 0xcc 'Ì' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 205 0xcd 'Í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 206 0xce 'Î' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 207 0xcf 'Ï' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 208 0xd0 'Ð' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 209 0xd1 'Ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 210 0xd2 'Ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 211 0xd3 'Ó' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 212 0xd4 'Ô' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 213 0xd5 'Õ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 214 0xd6 'Ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 215 0xd7 '×' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 216 0xd8 'Ø' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 217 0xd9 'Ù' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 218 0xda 'Ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 219 0xdb 'Û' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 220 0xdc 'Ü' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 221 0xdd 'Ý' */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - - /* 222 0xde 'Þ' */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - - /* 223 0xdf 'ß' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 224 0xe0 'à' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 225 0xe1 'á' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xd8, /* 11011000 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 226 0xe2 'â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 227 0xe3 'ã' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 228 0xe4 'ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 229 0xe5 'å' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 230 0xe6 'æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - - /* 231 0xe7 'ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 232 0xe8 'è' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 233 0xe9 'é' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 234 0xea 'ê' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xee, /* 11101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 235 0xeb 'ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x3e, /* 00111110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 236 0xec 'ì' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 237 0xed 'í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x03, /* 00000011 */ - 0x06, /* 00000110 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xf3, /* 11110011 */ - 0x7e, /* 01111110 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 238 0xee 'î' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 239 0xef 'ï' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 240 0xf0 'ð' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 241 0xf1 'ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 242 0xf2 'ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 243 0xf3 'ó' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 244 0xf4 'ô' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 245 0xf5 'õ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 246 0xf6 'ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 247 0xf7 '÷' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 248 0xf8 'ø' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 249 0xf9 'ù' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 250 0xfa 'ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 251 0xfb 'û' */ - 0x00, /* 00000000 */ - 0x0f, /* 00001111 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xec, /* 11101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3c, /* 00111100 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 252 0xfc 'ü' */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 253 0xfd 'ý' */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x32, /* 00110010 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 254 0xfe 'þ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 255 0xff 'ÿ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - -}; diff --git a/qemu/ui/vnc-auth-sasl.c b/qemu/ui/vnc-auth-sasl.c deleted file mode 100644 index 5ae29c14c..000000000 --- a/qemu/ui/vnc-auth-sasl.c +++ /dev/null @@ -1,660 +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 "qemu/osdep.h" -#include "qapi/error.h" -#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 = false; - vs->sasl.wantSSF = false; - vs->sasl.waitWriteSSF = 0; - vs->sasl.encodedLength = vs->sasl.encodedOffset = 0; - vs->sasl.encoded = NULL; - g_free(vs->sasl.username); - g_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, NULL); - - 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) { - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } - - 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, NULL); - 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 = g_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 %p\n", vs->ioc); - goto authreject; - } - - /* Check username whitelist ACL */ - if (vnc_auth_sasl_check_access(vs) < 0) { - VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); - goto authreject; - } - - VNC_DEBUG("Authentication successful %p\n", vs->ioc); - 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 %p\n", vs->ioc); - goto authreject; - } - - /* Check username whitelist ACL */ - if (vnc_auth_sasl_check_access(vs) < 0) { - VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); - goto authreject; - } - - VNC_DEBUG("Authentication successful %p\n", vs->ioc); - 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 = g_strndup((const char *) data, len); - 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]); - goto fail; - } - } else { - char *offset = strstr(vs->sasl.mechlist, mechname); - VNC_DEBUG("Two %p\n", offset); - if (!offset) { - goto fail; - } - VNC_DEBUG("Two '%s'\n", offset); - if (offset[-1] != ',' || - (offset[len] != '\0'&& - offset[len] != ',')) { - goto fail; - } - } - - g_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; - - fail: - vnc_client_error(vs); - g_free(mechname); - return -1; -} - -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; -} - -static char * -vnc_socket_ip_addr_string(QIOChannelSocket *ioc, - bool local, - Error **errp) -{ - SocketAddress *addr; - char *ret; - - if (local) { - addr = qio_channel_socket_get_local_address(ioc, errp); - } else { - addr = qio_channel_socket_get_remote_address(ioc, errp); - } - if (!addr) { - return NULL; - } - - if (addr->type != SOCKET_ADDRESS_KIND_INET) { - error_setg(errp, "Not an inet socket type"); - return NULL; - } - ret = g_strdup_printf("%s;%s", addr->u.inet.data->host, - addr->u.inet.data->port); - qapi_free_SocketAddress(addr); - return ret; -} - -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 %p\n", vs->ioc); - - /* Get local & remote client addresses in form IPADDR;PORT */ - localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL); - if (!localAddr) { - goto authabort; - } - - remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL); - if (!remoteAddr) { - g_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); - g_free(localAddr); - g_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; - } - - /* Inform SASL that we've got an external SSF layer from TLS/x509 */ - if (vs->auth == VNC_AUTH_VENCRYPT && - vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) { - Error *local_err = NULL; - int keysize; - sasl_ssf_t ssf; - - keysize = qcrypto_tls_session_get_key_size(vs->tls, - &local_err); - if (keysize < 0) { - VNC_DEBUG("cannot TLS get cipher size: %s\n", - error_get_pretty(local_err)); - error_free(local_err); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } - ssf = keysize * CHAR_BIT; /* 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 { - vs->sasl.wantSSF = 1; - } - - memset (&secprops, 0, sizeof secprops); - /* Inform SASL that we've got an external SSF layer from TLS. - * - * Disable SSF, if using TLS+x509+SASL only. TLS without x509 - * is not sufficiently strong - */ - if (vs->vd->is_unix || - (vs->auth == VNC_AUTH_VENCRYPT && - vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) { - /* 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); - - vs->sasl.mechlist = g_strdup(mechlist); - 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); -} - - diff --git a/qemu/ui/vnc-auth-sasl.h b/qemu/ui/vnc-auth-sasl.h deleted file mode 100644 index 3f59da67e..000000000 --- a/qemu/ui/vnc-auth-sasl.h +++ /dev/null @@ -1,75 +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 "qemu/acl.h" -#include "qemu/main-loop.h" - -struct VncStateSASL { - sasl_conn_t *conn; - /* If we want to negotiate an SSF layer with client */ - bool wantSSF; - /* If we are now running the SSF layer */ - bool runSSF; - /* - * 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/qemu/ui/vnc-auth-vencrypt.c b/qemu/ui/vnc-auth-vencrypt.c deleted file mode 100644 index 11c8c9a81..000000000 --- a/qemu/ui/vnc-auth-vencrypt.c +++ /dev/null @@ -1,160 +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 "qemu/osdep.h" -#include "vnc.h" -#include "qapi/error.h" -#include "qemu/main-loop.h" - -static void start_auth_vencrypt_subauth(VncState *vs) -{ - switch (vs->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"); - start_auth_sasl(vs); - break; -#endif /* CONFIG_VNC_SASL */ - - default: /* Should not be possible, but just in case */ - VNC_DEBUG("Reject subauth %d server bug\n", vs->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_done(Object *source, - Error *err, - gpointer user_data) -{ - VncState *vs = user_data; - - if (err) { - VNC_DEBUG("Handshake failed %s\n", - error_get_pretty(err)); - vnc_client_error(vs); - } else { - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); - start_auth_vencrypt_subauth(vs); - } -} - - -static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) -{ - int auth = read_u32(data, 0); - - if (auth != vs->subauth) { - VNC_DEBUG("Rejecting auth %d\n", auth); - vnc_write_u8(vs, 0); /* Reject auth */ - vnc_flush(vs); - vnc_client_error(vs); - } else { - Error *err = NULL; - QIOChannelTLS *tls; - VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); - vnc_write_u8(vs, 1); /* Accept auth */ - vnc_flush(vs); - - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - vs->ioc_tag = 0; - } - - tls = qio_channel_tls_new_server( - vs->ioc, - vs->vd->tlscreds, - vs->vd->tlsaclname, - &err); - if (!tls) { - VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); - error_free(err); - vnc_client_error(vs); - return 0; - } - - VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(tls); - vs->tls = qio_channel_tls_get_session(tls); - - qio_channel_tls_handshake(tls, - vnc_tls_handshake_done, - vs, - NULL); - } - 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->subauth); - vnc_write_u8(vs, 0); /* Accept version */ - vnc_write_u8(vs, 1); /* Number of sub-auths */ - vnc_write_u32(vs, vs->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/qemu/ui/vnc-auth-vencrypt.h b/qemu/ui/vnc-auth-vencrypt.h deleted file mode 100644 index 9f674c517..000000000 --- a/qemu/ui/vnc-auth-vencrypt.h +++ /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/qemu/ui/vnc-enc-hextile-template.h b/qemu/ui/vnc-enc-hextile-template.h deleted file mode 100644 index d868d7572..000000000 --- a/qemu/ui/vnc-enc-hextile-template.h +++ /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 = vnc_server_fb_ptr(vd, x, y); - 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->client_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 += vnc_server_fb_stride(vd) / 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 += vnc_server_fb_stride(vd) / 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->client_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->client_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 += vnc_server_fb_stride(vd) / 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. */ - } - break; - 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, last_bg, sizeof(pixel_t)); - if (flags & 0x04) - vs->write_pixels(vs, 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, row, w * 4); - row += vnc_server_fb_stride(vd); - } - } -} - -#undef NAME -#undef pixel_t -#undef CONCAT_I -#undef CONCAT diff --git a/qemu/ui/vnc-enc-hextile.c b/qemu/ui/vnc-enc-hextile.c deleted file mode 100644 index 4215bd7da..000000000 --- a/qemu/ui/vnc-enc-hextile.c +++ /dev/null @@ -1,84 +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 "qemu/osdep.h" -#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 32 -#include "vnc-enc-hextile-template.h" -#undef BPP - -#define GENERIC -#define BPP 32 -#include "vnc-enc-hextile-template.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; - - last_fg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES); - last_bg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES); - has_fg = has_bg = 0; - for (j = y; j < (y + h); j += 16) { - for (i = x; i < (x + w); i += 16) { - vs->hextile.send_tile(vs, i, j, - MIN(16, x + w - i), MIN(16, y + h - j), - last_bg, last_fg, &has_bg, &has_fg); - } - } - g_free(last_fg); - g_free(last_bg); - - return 1; -} - -void vnc_hextile_set_pixel_conversion(VncState *vs, int generic) -{ - if (!generic) { - switch (VNC_SERVER_FB_BITS) { - case 32: - vs->hextile.send_tile = send_hextile_tile_32; - break; - } - } else { - switch (VNC_SERVER_FB_BITS) { - case 32: - vs->hextile.send_tile = send_hextile_tile_generic_32; - break; - } - } -} diff --git a/qemu/ui/vnc-enc-tight.c b/qemu/ui/vnc-enc-tight.c deleted file mode 100644 index e5cba0e5a..000000000 --- a/qemu/ui/vnc-enc-tight.c +++ /dev/null @@ -1,1697 +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/osdep.h" - -/* This needs to be before jpeglib.h line because of conflict with - INT32 definitions between jmorecfg.h (included by jpeglib.h) and - Win32 basetsd.h (included by windows.h). */ -#include "qemu-common.h" - -#ifdef CONFIG_VNC_PNG -/* The following define is needed by pngconf.h. Otherwise it won't compile, - because setjmp.h was already included by qemu-common.h. */ -#define PNG_SKIP_SETJMP_CHECK -#include <png.h> -#endif -#ifdef CONFIG_VNC_JPEG -#include <jpeglib.h> -#endif - -#include "qemu/bswap.h" -#include "qapi/qmp/qint.h" -#include "vnc.h" -#include "vnc-enc-tight.h" -#include "vnc-palette.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 } -}; - - -static int tight_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h); - -#ifdef CONFIG_VNC_JPEG -static const struct { - double jpeg_freq_min; /* Don't send JPEG if the freq is bellow */ - double jpeg_freq_threshold; /* Always send JPEG if the freq is above */ - int jpeg_idx; /* Allow indexed JPEG */ - int jpeg_full; /* Allow full color JPEG */ -} tight_jpeg_conf[] = { - { 0, 8, 1, 1 }, - { 0, 8, 1, 1 }, - { 0, 8, 1, 1 }, - { 0, 8, 1, 1 }, - { 0, 10, 1, 1 }, - { 0.1, 10, 1, 1 }, - { 0.2, 10, 1, 1 }, - { 0.3, 12, 0, 0 }, - { 0.4, 14, 0, 0 }, - { 0.5, 16, 0, 0 }, -}; -#endif - -#ifdef CONFIG_VNC_PNG -static const struct { - int png_zlib_level, png_filters; -} tight_png_conf[] = { - { 0, PNG_NO_FILTERS }, - { 1, PNG_NO_FILTERS }, - { 2, PNG_NO_FILTERS }, - { 3, PNG_NO_FILTERS }, - { 4, PNG_NO_FILTERS }, - { 5, PNG_ALL_FILTERS }, - { 6, PNG_ALL_FILTERS }, - { 7, PNG_ALL_FILTERS }, - { 8, PNG_ALL_FILTERS }, - { 9, PNG_ALL_FILTERS }, -}; - -static int send_png_rect(VncState *vs, int x, int y, int w, int h, - VncPalette *palette); - -static bool tight_can_send_png_rect(VncState *vs, int w, int h) -{ - if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) { - return false; - } - - if (surface_bytes_per_pixel(vs->vd->ds) == 1 || - vs->client_pf.bytes_per_pixel == 1) { - return false; - } - - return true; -} -#endif - -/* - * Code to guess if given rectangle is suitable for smooth image - * compression (by applying "gradient" filter or JPEG coder). - */ - -static unsigned int -tight_detect_smooth_image24(VncState *vs, int w, int h) -{ - int off; - int x, y, d, dx; - unsigned int c; - unsigned int stats[256]; - int pixels = 0; - int pix, left[3]; - unsigned int errors; - unsigned char *buf = vs->tight.tight.buffer; - - /* - * If client is big-endian, color samples begin from the second - * byte (offset 1) of a 32-bit pixel value. - */ - off = vs->client_be; - - 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; - } - } - - if (pixels == 0) { - return 0; - } - - /* 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 unsigned int \ - 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; \ - unsigned int c; \ - unsigned int stats[256]; \ - int pixels = 0; \ - int sample, sum, left[3]; \ - unsigned int errors; \ - unsigned char *buf = vs->tight.tight.buffer; \ - \ - endian = 0; /* FIXME */ \ - \ - \ - max[0] = vs->client_pf.rmax; \ - max[1] = vs->client_pf.gmax; \ - max[2] = vs->client_pf.bmax; \ - shift[0] = vs->client_pf.rshift; \ - shift[1] = vs->client_pf.gshift; \ - shift[2] = vs->client_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 (pixels == 0) { \ - return 0; \ - } \ - 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) -{ - unsigned int errors; - int compression = vs->tight.compression; - int quality = vs->tight.quality; - - if (!vs->vd->lossy) { - return 0; - } - - if (surface_bytes_per_pixel(vs->vd->ds) == 1 || - vs->client_pf.bytes_per_pixel == 1 || - w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) { - return 0; - } - - if (vs->tight.quality != (uint8_t)-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->client_pf.bytes_per_pixel == 4) { - if (vs->tight.pixel24) { - errors = tight_detect_smooth_image24(vs, w, h); - if (vs->tight.quality != (uint8_t)-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 != (uint8_t)-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. - */ -#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, \ - VncPalette **palette) { \ - uint##bpp##_t *data; \ - uint##bpp##_t c0, c1, ci; \ - int i, n0, n1; \ - \ - data = (uint##bpp##_t *)vs->tight.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 = palette_new(max, bpp); \ - palette_put(*palette, c0); \ - palette_put(*palette, c1); \ - palette_put(*palette, ci); \ - \ - for (i++; i < count; i++) { \ - if (data[i] == ci) { \ - continue; \ - } else { \ - ci = data[i]; \ - if (!palette_put(*palette, (uint32_t)ci)) { \ - return 0; \ - } \ - } \ - } \ - \ - return palette_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, - VncPalette **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->client_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; -} - -/* - * Converting truecolor samples into palette indices. - */ -#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ - \ - static void \ - tight_encode_indexed_rect##bpp(uint8_t *buf, int count, \ - VncPalette *palette) { \ - uint##bpp##_t *src; \ - uint##bpp##_t rgb; \ - 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++; \ - } \ - idx = palette_idx(palette, rgb); \ - /* \ - * Should never happen, but don't break everything \ - * if it does, use the first color instead \ - */ \ - if (idx == (uint8_t)-1) { \ - idx = 0; \ - } \ - 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 (1 /* FIXME */) { - shift[0] = vs->client_pf.rshift; - shift[1] = vs->client_pf.gshift; - shift[2] = vs->client_pf.bshift; - } else { - shift[0] = 24 - vs->client_pf.rshift; - shift[1] = 24 - vs->client_pf.gshift; - shift[2] = 24 - vs->client_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 = 0; /* FIXME */ \ - \ - max[0] = vs->client_pf.rmax; \ - max[1] = vs->client_pf.gmax; \ - max[2] = vs->client_pf.bmax; \ - shift[0] = vs->client_pf.rshift; \ - shift[1] = vs->client_pf.gshift; \ - shift[2] = vs->client_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 successful, and in - * that case new color will be stored in *colorPtr. - */ - -static bool -check_solid_tile32(VncState *vs, int x, int y, int w, int h, - uint32_t *color, bool samecolor) -{ - VncDisplay *vd = vs->vd; - uint32_t *fbptr; - uint32_t c; - int dx, dy; - - fbptr = vnc_server_fb_ptr(vd, x, y); - - 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 = (uint32_t *) - ((uint8_t *)fbptr + vnc_server_fb_stride(vd)); - } - - *color = (uint32_t)c; - return true; -} - -static bool check_solid_tile(VncState *vs, int x, int y, int w, int h, - uint32_t* color, bool samecolor) -{ - switch (VNC_SERVER_FB_BYTES) { - case 4: - return check_solid_tile32(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.tight.buffer, vs->tight.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.tight.buffer; - zstream->avail_in = vs->tight.tight.offset; - zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset; - zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset; - previous_out = zstream->avail_out; - zstream->data_type = Z_BINARY; - - /* 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; - /* ...how much data has actually been produced by deflate() */ - bytes = previous_out - zstream->avail_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 (1 /* FIXME */) { - rshift = vs->client_pf.rshift; - gshift = vs->client_pf.gshift; - bshift = vs->client_pf.bshift; - } else { - rshift = 24 - vs->client_pf.rshift; - gshift = 24 - vs->client_pf.gshift; - bshift = 24 - vs->client_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 x, int y, int w, int h) -{ - int stream = 0; - ssize_t bytes; - -#ifdef CONFIG_VNC_PNG - if (tight_can_send_png_rect(vs, w, h)) { - return send_png_rect(vs, x, y, w, h, NULL); - } -#endif - - vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ - - if (vs->tight.pixel24) { - tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset); - bytes = 3; - } else { - bytes = vs->client_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.tight.buffer, 1, &vs->tight.tight.offset); - bytes = 3; - } else { - bytes = vs->client_pf.bytes_per_pixel; - } - - vnc_write(vs, vs->tight.tight.buffer, bytes); - return 1; -} - -static int send_mono_rect(VncState *vs, int x, int y, - int w, int h, uint32_t bg, uint32_t fg) -{ - ssize_t bytes; - int stream = 1; - int level = tight_conf[vs->tight.compression].mono_zlib_level; - -#ifdef CONFIG_VNC_PNG - if (tight_can_send_png_rect(vs, w, h)) { - int ret; - int bpp = vs->client_pf.bytes_per_pixel * 8; - VncPalette *palette = palette_new(2, bpp); - - palette_put(palette, bg); - palette_put(palette, fg); - ret = send_png_rect(vs, x, y, w, h, palette); - palette_destroy(palette); - return ret; - } -#endif - - 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->client_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.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.tight.buffer, w, h, bg, fg); - break; - default: - vnc_write_u8(vs, bg); - vnc_write_u8(vs, fg); - tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg); - break; - } - vs->tight.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; -#ifdef CONFIG_VNC_PNG - png_colorp png_palette; -#endif -}; - -static void write_palette(int idx, uint32_t color, void *opaque) -{ - struct palette_cb_priv *priv = opaque; - VncState *vs = priv->vs; - uint32_t bytes = vs->client_pf.bytes_per_pixel; - - if (bytes == 4) { - ((uint32_t*)priv->header)[idx] = color; - } else { - ((uint16_t*)priv->header)[idx] = color; - } -} - -static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) -{ - int stream = 3; - int level = tight_conf[vs->tight.compression].gradient_zlib_level; - ssize_t bytes; - - if (vs->client_pf.bytes_per_pixel == 1) { - return send_full_color_rect(vs, x, y, 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.tight.buffer, w, h); - bytes = 3; - } else if (vs->client_pf.bytes_per_pixel == 4) { - tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h); - bytes = 4; - } else { - tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h); - bytes = 2; - } - - buffer_reset(&vs->tight.gradient); - - bytes = w * h * bytes; - vs->tight.tight.offset = bytes; - - bytes = tight_compress_data(vs, stream, bytes, - level, Z_FILTERED); - return (bytes >= 0); -} - -static int send_palette_rect(VncState *vs, int x, int y, - int w, int h, VncPalette *palette) -{ - int stream = 2; - int level = tight_conf[vs->tight.compression].idx_zlib_level; - int colors; - ssize_t bytes; - -#ifdef CONFIG_VNC_PNG - if (tight_can_send_png_rect(vs, w, h)) { - return send_png_rect(vs, x, y, w, h, palette); - } -#endif - - colors = palette_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->client_pf.bytes_per_pixel) { - case 4: - { - size_t old_offset, offset; - uint32_t header[palette_size(palette)]; - struct palette_cb_priv priv = { vs, (uint8_t *)header }; - - old_offset = vs->output.offset; - palette_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.tight.buffer, w * h, palette); - break; - } - case 2: - { - uint16_t header[palette_size(palette)]; - struct palette_cb_priv priv = { vs, (uint8_t *)header }; - - palette_iter(palette, write_palette, &priv); - vnc_write(vs, header, sizeof(header)); - tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); - break; - } - default: - return -1; /* No palette for 8bits colors */ - break; - } - bytes = w * h; - vs->tight.tight.offset = bytes; - - bytes = tight_compress_data(vs, stream, bytes, - level, Z_DEFAULT_STRATEGY); - return (bytes >= 0); -} - -/* - * JPEG compression stuff. - */ -#ifdef CONFIG_VNC_JPEG -/* - * 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; - pixman_image_t *linebuf; - JSAMPROW row[1]; - uint8_t *buf; - int dy; - - if (surface_bytes_per_pixel(vs->vd->ds) == 1) { - return send_full_color_rect(vs, x, y, w, h); - } - - 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); - - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w); - buf = (uint8_t *)pixman_image_get_data(linebuf); - row[0] = buf; - for (dy = 0; dy < h; dy++) { - qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy); - jpeg_write_scanlines(&cinfo, row, 1); - } - qemu_pixman_image_unref(linebuf); - - 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 */ - -/* - * PNG compression stuff. - */ -#ifdef CONFIG_VNC_PNG -static void write_png_palette(int idx, uint32_t pix, void *opaque) -{ - struct palette_cb_priv *priv = opaque; - VncState *vs = priv->vs; - png_colorp color = &priv->png_palette[idx]; - - if (vs->tight.pixel24) - { - color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax; - color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax; - color->blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax; - } - else - { - int red, green, blue; - - red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax; - green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax; - blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax; - color->red = ((red * 255 + vs->client_pf.rmax / 2) / - vs->client_pf.rmax); - color->green = ((green * 255 + vs->client_pf.gmax / 2) / - vs->client_pf.gmax); - color->blue = ((blue * 255 + vs->client_pf.bmax / 2) / - vs->client_pf.bmax); - } -} - -static void png_write_data(png_structp png_ptr, png_bytep data, - png_size_t length) -{ - VncState *vs = png_get_io_ptr(png_ptr); - - buffer_reserve(&vs->tight.png, vs->tight.png.offset + length); - memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length); - - vs->tight.png.offset += length; -} - -static void png_flush_data(png_structp png_ptr) -{ -} - -static void *vnc_png_malloc(png_structp png_ptr, png_size_t size) -{ - return g_malloc(size); -} - -static void vnc_png_free(png_structp png_ptr, png_voidp ptr) -{ - g_free(ptr); -} - -static int send_png_rect(VncState *vs, int x, int y, int w, int h, - VncPalette *palette) -{ - png_byte color_type; - png_structp png_ptr; - png_infop info_ptr; - png_colorp png_palette = NULL; - pixman_image_t *linebuf; - int level = tight_png_conf[vs->tight.compression].png_zlib_level; - int filters = tight_png_conf[vs->tight.compression].png_filters; - uint8_t *buf; - int dy; - - png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, - NULL, vnc_png_malloc, vnc_png_free); - - if (png_ptr == NULL) - return -1; - - info_ptr = png_create_info_struct(png_ptr); - - if (info_ptr == NULL) { - png_destroy_write_struct(&png_ptr, NULL); - return -1; - } - - png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data); - png_set_compression_level(png_ptr, level); - png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters); - - if (palette) { - color_type = PNG_COLOR_TYPE_PALETTE; - } else { - color_type = PNG_COLOR_TYPE_RGB; - } - - png_set_IHDR(png_ptr, info_ptr, w, h, - 8, color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - if (color_type == PNG_COLOR_TYPE_PALETTE) { - struct palette_cb_priv priv; - - png_palette = png_malloc(png_ptr, sizeof(*png_palette) * - palette_size(palette)); - - priv.vs = vs; - priv.png_palette = png_palette; - palette_iter(palette, write_png_palette, &priv); - - png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette)); - - if (vs->client_pf.bytes_per_pixel == 4) { - tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette); - } else { - tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); - } - } - - png_write_info(png_ptr, info_ptr); - - buffer_reserve(&vs->tight.png, 2048); - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w); - buf = (uint8_t *)pixman_image_get_data(linebuf); - for (dy = 0; dy < h; dy++) - { - if (color_type == PNG_COLOR_TYPE_PALETTE) { - memcpy(buf, vs->tight.tight.buffer + (dy * w), w); - } else { - qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy); - } - png_write_row(png_ptr, buf); - } - qemu_pixman_image_unref(linebuf); - - png_write_end(png_ptr, NULL); - - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_free(png_ptr, png_palette); - } - - png_destroy_write_struct(&png_ptr, &info_ptr); - - vnc_write_u8(vs, VNC_TIGHT_PNG << 4); - - tight_send_compact_size(vs, vs->tight.png.offset); - vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset); - buffer_reset(&vs->tight.png); - return 1; -} -#endif /* CONFIG_VNC_PNG */ - -static void vnc_tight_start(VncState *vs) -{ - buffer_reset(&vs->tight.tight); - - // make the output buffer be the zlib buffer, so we can compress it later - vs->tight.tmp = vs->output; - vs->output = vs->tight.tight; -} - -static void vnc_tight_stop(VncState *vs) -{ - // switch back to normal output/zlib buffers - vs->tight.tight = vs->output; - vs->output = vs->tight.tmp; -} - -static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h, - int bg, int fg, int colors, VncPalette *palette) -{ - int ret; - - if (colors == 0) { - if (tight_detect_smooth_image(vs, w, h)) { - ret = send_gradient_rect(vs, x, y, w, h); - } else { - ret = send_full_color_rect(vs, x, y, w, h); - } - } else if (colors == 1) { - ret = send_solid_rect(vs); - } else if (colors == 2) { - ret = send_mono_rect(vs, x, y, w, h, bg, fg); - } else if (colors <= 256) { - ret = send_palette_rect(vs, x, y, w, h, palette); - } else { - ret = 0; - } - return ret; -} - -#ifdef CONFIG_VNC_JPEG -static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h, - int bg, int fg, int colors, - VncPalette *palette, bool force) -{ - int ret; - - if (colors == 0) { - if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full && - 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_full_color_rect(vs, x, y, w, h); - } - } else if (colors == 1) { - ret = send_solid_rect(vs); - } else if (colors == 2) { - ret = send_mono_rect(vs, x, y, w, h, bg, fg); - } else if (colors <= 256) { - if (force || (colors > 96 && - tight_jpeg_conf[vs->tight.quality].jpeg_idx && - 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, x, y, w, h, palette); - } - } else { - ret = 0; - } - return ret; -} -#endif - -static int send_sub_rect(VncState *vs, int x, int y, int w, int h) -{ - VncPalette *palette = NULL; - uint32_t bg = 0, fg = 0; - int colors; - int ret = 0; -#ifdef CONFIG_VNC_JPEG - bool force_jpeg = false; - bool allow_jpeg = true; -#endif - - vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type); - - vnc_tight_start(vs); - vnc_raw_send_framebuffer_update(vs, x, y, w, h); - vnc_tight_stop(vs); - -#ifdef CONFIG_VNC_JPEG - if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) { - double freq = vnc_update_freq(vs, x, y, w, h); - - if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) { - allow_jpeg = false; - } - if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { - force_jpeg = true; - vnc_sent_lossy_rect(vs, x, y, w, h); - } - } -#endif - - colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, &palette); - -#ifdef CONFIG_VNC_JPEG - if (allow_jpeg && vs->tight.quality != (uint8_t)-1) { - ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette, - force_jpeg); - } else { - ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette); - } -#else - ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette); -#endif - - palette_destroy(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, vs->tight.type); - - 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, - bool split) -{ - 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 (split && (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, true); - 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, true); - } - if (x_best != x) { - n += 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 += 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 += 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, true); -} - -static int tight_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) -{ - int max_rows; - - if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF && - vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) { - vs->tight.pixel24 = true; - } else { - vs->tight.pixel24 = false; - } - -#ifdef CONFIG_VNC_JPEG - if (vs->tight.quality != (uint8_t)-1) { - double freq = vnc_update_freq(vs, x, y, w, h); - - if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { - return send_rect_simple(vs, x, y, w, h, false); - } - } -#endif - - if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) { - return send_rect_simple(vs, x, y, w, h, true); - } - - /* 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); -} - -int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) -{ - vs->tight.type = VNC_ENCODING_TIGHT; - return tight_send_framebuffer_update(vs, x, y, w, h); -} - -int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) -{ - vs->tight.type = VNC_ENCODING_TIGHT_PNG; - return tight_send_framebuffer_update(vs, x, y, w, h); -} - -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.tight); - buffer_free(&vs->tight.zlib); - buffer_free(&vs->tight.gradient); -#ifdef CONFIG_VNC_JPEG - buffer_free(&vs->tight.jpeg); -#endif -#ifdef CONFIG_VNC_PNG - buffer_free(&vs->tight.png); -#endif -} diff --git a/qemu/ui/vnc-enc-tight.h b/qemu/ui/vnc-enc-tight.h deleted file mode 100644 index a3add788e..000000000 --- a/qemu/ui/vnc-enc-tight.h +++ /dev/null @@ -1,183 +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 1010 (0x0A), then the compression type is "png", - * if 0xxx, then the compression type is "basic", - * values greater than 1010 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", "png" 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" or "png", the following data stream - * looks like this: - * - * 1..3 bytes: data size (N) in compact representation; - * N bytes: JPEG or PNG 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", "jpeg" or "png". - * - *-- 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_PNG 0x0A -#define VNC_TIGHT_MAX_SUBENCODING 0x0A - -/* 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/qemu/ui/vnc-enc-zlib.c b/qemu/ui/vnc-enc-zlib.c deleted file mode 100644 index 33e9df2f6..000000000 --- a/qemu/ui/vnc-enc-zlib.c +++ /dev/null @@ -1,153 +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 "qemu/osdep.h" -#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 = g_malloc0(size); - - return (p); -} - -void vnc_zlib_zfree(void *x, void *addr) -{ - g_free(addr); -} - -static void vnc_zlib_start(VncState *vs) -{ - buffer_reset(&vs->zlib.zlib); - - // make the output buffer be the zlib buffer, so we can compress it later - vs->zlib.tmp = vs->output; - vs->output = vs->zlib.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.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.zlib.offset + 64); - - // set pointers - zstream->next_in = vs->zlib.zlib.buffer; - zstream->avail_in = vs->zlib.zlib.offset; - zstream->next_out = vs->output.buffer + vs->output.offset; - zstream->avail_out = vs->output.capacity - vs->output.offset; - previous_out = zstream->avail_out; - zstream->data_type = Z_BINARY; - - // 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 previous_out - zstream->avail_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.zlib); -} diff --git a/qemu/ui/vnc-enc-zrle-template.c b/qemu/ui/vnc-enc-zrle-template.c deleted file mode 100644 index abf6b86e4..000000000 --- a/qemu/ui/vnc-enc-zrle-template.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) - * - * From libvncserver/libvncserver/zrleencodetemplate.c - * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2003 Sun Microsystems, Inc. - * - * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -/* - * Before including this file, you must define a number of CPP macros. - * - * ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel. - * - * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel - * bigger than the largest tile of pixel data, since the ZRLE encoding - * algorithm writes to the position one past the end of the pixel data. - */ - - -#include "qemu/osdep.h" - -#undef ZRLE_ENDIAN_SUFFIX - -#if ZYWRLE_ENDIAN == ENDIAN_LITTLE -#define ZRLE_ENDIAN_SUFFIX le -#elif ZYWRLE_ENDIAN == ENDIAN_BIG -#define ZRLE_ENDIAN_SUFFIX be -#else -#define ZRLE_ENDIAN_SUFFIX ne -#endif - -#ifndef ZRLE_CONCAT -#define ZRLE_CONCAT_I(a, b) a##b -#define ZRLE_CONCAT2(a, b) ZRLE_CONCAT_I(a, b) -#define ZRLE_CONCAT3(a, b, c) ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c)) -#endif - -#ifdef ZRLE_COMPACT_PIXEL -#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX) -#define ZRLE_WRITE_SUFFIX ZRLE_COMPACT_PIXEL -#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t) -#define ZRLE_BPP_OUT 24 -#elif ZRLE_BPP == 15 -#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) -#define ZRLE_WRITE_SUFFIX 16 -#define ZRLE_PIXEL uint16_t -#define ZRLE_BPP_OUT 16 -#else -#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) -#define ZRLE_WRITE_SUFFIX ZRLE_BPP -#define ZRLE_BPP_OUT ZRLE_BPP -#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t) -#endif - -#define ZRLE_WRITE_PIXEL ZRLE_CONCAT2(zrle_write_u, ZRLE_WRITE_SUFFIX) -#define ZRLE_ENCODE ZRLE_CONCAT2(zrle_encode_, ZRLE_ENCODE_SUFFIX) -#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX) -#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX) - -static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, - int zywrle_level); - -#if ZRLE_BPP != 8 -#include "vnc-enc-zywrle-template.c" -#endif - - -static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h, - int zywrle_level) -{ - int ty; - - for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) { - - int tx, th; - - th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty); - - for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) { - int tw; - ZRLE_PIXEL *buf; - - tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx); - - buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP); - ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level); - } - } -} - -static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, - int zywrle_level) -{ - VncPalette *palette = &vs->zrle.palette; - - int runs = 0; - int single_pixels = 0; - - bool use_rle; - bool use_palette; - - int i; - - ZRLE_PIXEL *ptr = data; - ZRLE_PIXEL *end = ptr + h * w; - *end = ~*(end-1); /* one past the end is different so the while loop ends */ - - /* Real limit is 127 but we wan't a way to know if there is more than 127 */ - palette_init(palette, 256, ZRLE_BPP); - - while (ptr < end) { - ZRLE_PIXEL pix = *ptr; - if (*++ptr != pix) { /* FIXME */ - single_pixels++; - } else { - while (*++ptr == pix) ; - runs++; - } - palette_put(palette, pix); - } - - /* Solid tile is a special case */ - - if (palette_size(palette) == 1) { - bool found; - - vnc_write_u8(vs, 1); - ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found)); - return; - } - - zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT, - runs, single_pixels, zywrle_level, - &use_rle, &use_palette); - - if (!use_palette) { - vnc_write_u8(vs, (use_rle ? 128 : 0)); - } else { - uint32_t colors[VNC_PALETTE_MAX_SIZE]; - size_t size = palette_size(palette); - - vnc_write_u8(vs, (use_rle ? 128 : 0) | size); - palette_fill(palette, colors); - - for (i = 0; i < size; i++) { - ZRLE_WRITE_PIXEL(vs, colors[i]); - } - } - - if (use_rle) { - ZRLE_PIXEL *ptr = data; - ZRLE_PIXEL *end = ptr + w * h; - ZRLE_PIXEL *run_start; - ZRLE_PIXEL pix; - - while (ptr < end) { - int len; - int index = 0; - - run_start = ptr; - pix = *ptr++; - - while (*ptr == pix && ptr < end) { - ptr++; - } - - len = ptr - run_start; - - if (use_palette) - index = palette_idx(palette, pix); - - if (len <= 2 && use_palette) { - if (len == 2) { - vnc_write_u8(vs, index); - } - vnc_write_u8(vs, index); - continue; - } - if (use_palette) { - vnc_write_u8(vs, index | 128); - } else { - ZRLE_WRITE_PIXEL(vs, pix); - } - - len -= 1; - - while (len >= 255) { - vnc_write_u8(vs, 255); - len -= 255; - } - - vnc_write_u8(vs, len); - } - } else if (use_palette) { /* no RLE */ - int bppp; - ZRLE_PIXEL *ptr = data; - - /* packed pixels */ - - assert (palette_size(palette) < 17); - - bppp = bits_per_packed_pixel[palette_size(palette)-1]; - - for (i = 0; i < h; i++) { - uint8_t nbits = 0; - uint8_t byte = 0; - - ZRLE_PIXEL *eol = ptr + w; - - while (ptr < eol) { - ZRLE_PIXEL pix = *ptr++; - uint8_t index = palette_idx(palette, pix); - - byte = (byte << bppp) | index; - nbits += bppp; - if (nbits >= 8) { - vnc_write_u8(vs, byte); - nbits = 0; - } - } - if (nbits > 0) { - byte <<= 8 - nbits; - vnc_write_u8(vs, byte); - } - } - } else { - - /* raw */ - -#if ZRLE_BPP != 8 - if (zywrle_level > 0 && !(zywrle_level & 0x80)) { - ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf); - ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80); - } - else -#endif - { -#ifdef ZRLE_COMPACT_PIXEL - ZRLE_PIXEL *ptr; - - for (ptr = data; ptr < data + w * h; ptr++) { - ZRLE_WRITE_PIXEL(vs, *ptr); - } -#else - vnc_write(vs, data, w * h * (ZRLE_BPP / 8)); -#endif - } - } -} - -#undef ZRLE_PIXEL -#undef ZRLE_WRITE_PIXEL -#undef ZRLE_ENCODE -#undef ZRLE_ENCODE_TILE -#undef ZYWRLE_ENCODE_TILE -#undef ZRLE_BPP_OUT -#undef ZRLE_WRITE_SUFFIX -#undef ZRLE_ENCODE_SUFFIX diff --git a/qemu/ui/vnc-enc-zrle.c b/qemu/ui/vnc-enc-zrle.c deleted file mode 100644 index 5489870e7..000000000 --- a/qemu/ui/vnc-enc-zrle.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) - * - * From libvncserver/libvncserver/zrle.c - * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2003 Sun Microsystems, Inc. - * - * 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/osdep.h" -#include "vnc.h" -#include "vnc-enc-zrle.h" - -static const int bits_per_packed_pixel[] = { - 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 -}; - - -static void vnc_zrle_start(VncState *vs) -{ - buffer_reset(&vs->zrle.zrle); - - /* make the output buffer be the zlib buffer, so we can compress it later */ - vs->zrle.tmp = vs->output; - vs->output = vs->zrle.zrle; -} - -static void vnc_zrle_stop(VncState *vs) -{ - /* switch back to normal output/zlib buffers */ - vs->zrle.zrle = vs->output; - vs->output = vs->zrle.tmp; -} - -static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, - int bpp) -{ - Buffer tmp; - - buffer_reset(&vs->zrle.fb); - buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp); - - tmp = vs->output; - vs->output = vs->zrle.fb; - - vnc_raw_send_framebuffer_update(vs, x, y, w, h); - - vs->zrle.fb = vs->output; - vs->output = tmp; - return vs->zrle.fb.buffer; -} - -static int zrle_compress_data(VncState *vs, int level) -{ - z_streamp zstream = &vs->zrle.stream; - - buffer_reset(&vs->zrle.zlib); - - if (zstream->opaque != vs) { - int err; - - zstream->zalloc = vnc_zlib_zalloc; - zstream->zfree = vnc_zlib_zfree; - - err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS, - MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); - - if (err != Z_OK) { - fprintf(stderr, "VNC: error initializing zlib\n"); - return -1; - } - - zstream->opaque = vs; - } - - /* reserve memory in output buffer */ - buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64); - - /* set pointers */ - zstream->next_in = vs->zrle.zrle.buffer; - zstream->avail_in = vs->zrle.zrle.offset; - zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset; - zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset; - zstream->data_type = Z_BINARY; - - /* start encoding */ - if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { - fprintf(stderr, "VNC: error during zrle compression\n"); - return -1; - } - - vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out; - return vs->zrle.zlib.offset; -} - -/* Try to work out whether to use RLE and/or a palette. We do this by - * estimating the number of bytes which will be generated and picking the - * method which results in the fewest bytes. Of course this may not result - * in the fewest bytes after compression... */ -static void zrle_choose_palette_rle(VncState *vs, int w, int h, - VncPalette *palette, int bpp_out, - int runs, int single_pixels, - int zywrle_level, - bool *use_rle, bool *use_palette) -{ - size_t estimated_bytes; - size_t plain_rle_bytes; - - *use_palette = *use_rle = false; - - estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */ - - if (bpp_out != 8) { - if (zywrle_level > 0 && !(zywrle_level & 0x80)) - estimated_bytes >>= zywrle_level; - } - - plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels); - - if (plain_rle_bytes < estimated_bytes) { - *use_rle = true; - estimated_bytes = plain_rle_bytes; - } - - if (palette_size(palette) < 128) { - int palette_rle_bytes; - - palette_rle_bytes = (bpp_out / 8) * palette_size(palette); - palette_rle_bytes += 2 * runs + single_pixels; - - if (palette_rle_bytes < estimated_bytes) { - *use_rle = true; - *use_palette = true; - estimated_bytes = palette_rle_bytes; - } - - if (palette_size(palette) < 17) { - int packed_bytes; - - packed_bytes = (bpp_out / 8) * palette_size(palette); - packed_bytes += w * h * - bits_per_packed_pixel[palette_size(palette)-1] / 8; - - if (packed_bytes < estimated_bytes) { - *use_rle = false; - *use_palette = true; - estimated_bytes = packed_bytes; - } - } - } -} - -static void zrle_write_u32(VncState *vs, uint32_t value) -{ - vnc_write(vs, (uint8_t *)&value, 4); -} - -static void zrle_write_u24a(VncState *vs, uint32_t value) -{ - vnc_write(vs, (uint8_t *)&value, 3); -} - -static void zrle_write_u24b(VncState *vs, uint32_t value) -{ - vnc_write(vs, ((uint8_t *)&value) + 1, 3); -} - -static void zrle_write_u16(VncState *vs, uint16_t value) -{ - vnc_write(vs, (uint8_t *)&value, 2); -} - -static void zrle_write_u8(VncState *vs, uint8_t value) -{ - vnc_write_u8(vs, value); -} - -#define ENDIAN_LITTLE 0 -#define ENDIAN_BIG 1 -#define ENDIAN_NO 2 - -#define ZRLE_BPP 8 -#define ZYWRLE_ENDIAN ENDIAN_NO -#include "vnc-enc-zrle-template.c" -#undef ZRLE_BPP - -#define ZRLE_BPP 15 -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_LITTLE -#include "vnc-enc-zrle-template.c" - -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_BIG -#include "vnc-enc-zrle-template.c" - -#undef ZRLE_BPP -#define ZRLE_BPP 16 -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_LITTLE -#include "vnc-enc-zrle-template.c" - -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_BIG -#include "vnc-enc-zrle-template.c" - -#undef ZRLE_BPP -#define ZRLE_BPP 32 -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_LITTLE -#include "vnc-enc-zrle-template.c" - -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_BIG -#include "vnc-enc-zrle-template.c" - -#define ZRLE_COMPACT_PIXEL 24a -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_LITTLE -#include "vnc-enc-zrle-template.c" - -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_BIG -#include "vnc-enc-zrle-template.c" - -#undef ZRLE_COMPACT_PIXEL -#define ZRLE_COMPACT_PIXEL 24b -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_LITTLE -#include "vnc-enc-zrle-template.c" - -#undef ZYWRLE_ENDIAN -#define ZYWRLE_ENDIAN ENDIAN_BIG -#include "vnc-enc-zrle-template.c" -#undef ZRLE_COMPACT_PIXEL -#undef ZRLE_BPP - -static int zrle_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) -{ - bool be = vs->client_be; - size_t bytes; - int zywrle_level; - - if (vs->zrle.type == VNC_ENCODING_ZYWRLE) { - if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1 - || vs->tight.quality == 9) { - zywrle_level = 0; - vs->zrle.type = VNC_ENCODING_ZRLE; - } else if (vs->tight.quality < 3) { - zywrle_level = 3; - } else if (vs->tight.quality < 6) { - zywrle_level = 2; - } else { - zywrle_level = 1; - } - } else { - zywrle_level = 0; - } - - vnc_zrle_start(vs); - - switch (vs->client_pf.bytes_per_pixel) { - case 1: - zrle_encode_8ne(vs, x, y, w, h, zywrle_level); - break; - - case 2: - if (vs->client_pf.gmax > 0x1F) { - if (be) { - zrle_encode_16be(vs, x, y, w, h, zywrle_level); - } else { - zrle_encode_16le(vs, x, y, w, h, zywrle_level); - } - } else { - if (be) { - zrle_encode_15be(vs, x, y, w, h, zywrle_level); - } else { - zrle_encode_15le(vs, x, y, w, h, zywrle_level); - } - } - break; - - case 4: - { - bool fits_in_ls3bytes; - bool fits_in_ms3bytes; - - fits_in_ls3bytes = - ((vs->client_pf.rmax << vs->client_pf.rshift) < (1 << 24) && - (vs->client_pf.gmax << vs->client_pf.gshift) < (1 << 24) && - (vs->client_pf.bmax << vs->client_pf.bshift) < (1 << 24)); - - fits_in_ms3bytes = (vs->client_pf.rshift > 7 && - vs->client_pf.gshift > 7 && - vs->client_pf.bshift > 7); - - if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) { - if (be) { - zrle_encode_24abe(vs, x, y, w, h, zywrle_level); - } else { - zrle_encode_24ale(vs, x, y, w, h, zywrle_level); - } - } else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) { - if (be) { - zrle_encode_24bbe(vs, x, y, w, h, zywrle_level); - } else { - zrle_encode_24ble(vs, x, y, w, h, zywrle_level); - } - } else { - if (be) { - zrle_encode_32be(vs, x, y, w, h, zywrle_level); - } else { - zrle_encode_32le(vs, x, y, w, h, zywrle_level); - } - } - } - break; - } - - vnc_zrle_stop(vs); - bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION); - vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type); - vnc_write_u32(vs, bytes); - vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset); - return 1; -} - -int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) -{ - vs->zrle.type = VNC_ENCODING_ZRLE; - return zrle_send_framebuffer_update(vs, x, y, w, h); -} - -int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) -{ - vs->zrle.type = VNC_ENCODING_ZYWRLE; - return zrle_send_framebuffer_update(vs, x, y, w, h); -} - -void vnc_zrle_clear(VncState *vs) -{ - if (vs->zrle.stream.opaque) { - deflateEnd(&vs->zrle.stream); - } - buffer_free(&vs->zrle.zrle); - buffer_free(&vs->zrle.fb); - buffer_free(&vs->zrle.zlib); -} diff --git a/qemu/ui/vnc-enc-zrle.h b/qemu/ui/vnc-enc-zrle.h deleted file mode 100644 index 6b182132a..000000000 --- a/qemu/ui/vnc-enc-zrle.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) - * - * From libvncserver/libvncserver/zrle.c - * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2003 Sun Microsystems, Inc. - * - * 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. - */ - -#ifndef VNC_ENCODING_ZRLE_H -#define VNC_ENCODING_ZRLE_H - -/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * ZRLE - encoding combining Zlib compression, tiling, palettisation and - * run-length encoding. - */ - -#define VNC_ZRLE_TILE_WIDTH 64 -#define VNC_ZRLE_TILE_HEIGHT 64 - -#endif diff --git a/qemu/ui/vnc-enc-zywrle-template.c b/qemu/ui/vnc-enc-zywrle-template.c deleted file mode 100644 index b446380a7..000000000 --- a/qemu/ui/vnc-enc-zywrle-template.c +++ /dev/null @@ -1,171 +0,0 @@ - -/******************************************************************** - * * - * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. * - * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 * - * BY Hitachi Systems & Services, Ltd. * - * (Noriaki Yamazaki, Research & Development Center) * - * * - * * - ******************************************************************** -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Hitachi Systems & Services, Ltd. nor -the names of its contributors may be used to endorse or promote -products derived from this software without specific prior written -permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ********************************************************************/ - -/* Change Log: - V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline - (Thanks Johannes Schindelin, author of LibVNC - Server/Client) - V0.01 : 2007/02/06 : Initial release -*/ - -/* -[References] - PLHarr: - Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy, - "An Improved N-Bit to N-Bit Reversible Haar-Like Transform," - Pacific Graphics 2004, October 2004, pp. 371-380. - EZW: - Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients, - IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993). -*/ - - -/* Template Macro stuffs. */ -#undef ZYWRLE_ANALYZE -#undef ZYWRLE_SYNTHESIZE - -#define ZYWRLE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) - -#define ZYWRLE_ANALYZE ZRLE_CONCAT2(zywrle_analyze_, ZYWRLE_SUFFIX) -#define ZYWRLE_SYNTHESIZE ZRLE_CONCAT2(zywrle_synthesize_,ZYWRLE_SUFFIX) - -#define ZYWRLE_RGBYUV ZRLE_CONCAT2(zywrle_rgbyuv_, ZYWRLE_SUFFIX) -#define ZYWRLE_YUVRGB ZRLE_CONCAT2(zywrle_yuvrgb_, ZYWRLE_SUFFIX) -#define ZYWRLE_YMASK ZRLE_CONCAT2(ZYWRLE_YMASK, ZRLE_BPP) -#define ZYWRLE_UVMASK ZRLE_CONCAT2(ZYWRLE_UVMASK, ZRLE_BPP) -#define ZYWRLE_LOAD_PIXEL ZRLE_CONCAT2(ZYWRLE_LOAD_PIXEL, ZRLE_BPP) -#define ZYWRLE_SAVE_PIXEL ZRLE_CONCAT2(ZYWRLE_SAVE_PIXEL, ZRLE_BPP) - -/* Packing/Unpacking pixel stuffs. - Endian conversion stuffs. */ -#undef S_0 -#undef S_1 -#undef L_0 -#undef L_1 -#undef L_2 - -#if ZYWRLE_ENDIAN == ENDIAN_BIG -# define S_0 1 -# define S_1 0 -# define L_0 3 -# define L_1 2 -# define L_2 1 -#else -# define S_0 0 -# define S_1 1 -# define L_0 0 -# define L_1 1 -# define L_2 2 -#endif - -#define ZYWRLE_QUANTIZE -#include "qemu/osdep.h" -#include "vnc-enc-zywrle.h" - -#ifndef ZRLE_COMPACT_PIXEL -static inline void ZYWRLE_RGBYUV(int *buf, ZRLE_PIXEL *data, - int width, int height, int scanline) -{ - int r, g, b; - int y, u, v; - int *line; - int *end; - - end = buf + height * width; - while (buf < end) { - line = buf + width; - while (buf < line) { - ZYWRLE_LOAD_PIXEL(data, r, g, b); - ZYWRLE_RGBYUV_(r, g, b, y, u, v, ZYWRLE_YMASK, ZYWRLE_UVMASK); - ZYWRLE_SAVE_COEFF(buf, v, y, u); - buf++; - data++; - } - data += scanline - width; - } -} - -static ZRLE_PIXEL *ZYWRLE_ANALYZE(ZRLE_PIXEL *dst, ZRLE_PIXEL *src, - int w, int h, int scanline, int level, - int *buf) { - int l; - int uw = w; - int uh = h; - int *top; - int *end; - int *line; - ZRLE_PIXEL *p; - int r, g, b; - int s; - int *ph; - - zywrle_calc_size(&w, &h, level); - - if (w == 0 || h == 0) { - return NULL; - } - uw -= w; - uh -= h; - - p = dst; - ZYWRLE_LOAD_UNALIGN(src,*(ZRLE_PIXEL*)top = *p;); - ZYWRLE_RGBYUV(buf, src, w, h, scanline); - wavelet(buf, w, h, level); - for (l = 0; l < level; l++) { - ZYWRLE_PACK_COEFF(buf, dst, 3, w, h, scanline, l); - ZYWRLE_PACK_COEFF(buf, dst, 2, w, h, scanline, l); - ZYWRLE_PACK_COEFF(buf, dst, 1, w, h, scanline, l); - if (l == level - 1) { - ZYWRLE_PACK_COEFF(buf, dst, 0, w, h, scanline, l); - } - } - ZYWRLE_SAVE_UNALIGN(dst,*dst = *(ZRLE_PIXEL*)top;); - return dst; -} -#endif /* ZRLE_COMPACT_PIXEL */ - -#undef ZYWRLE_RGBYUV -#undef ZYWRLE_YUVRGB -#undef ZYWRLE_LOAD_PIXEL -#undef ZYWRLE_SAVE_PIXEL diff --git a/qemu/ui/vnc-enc-zywrle.h b/qemu/ui/vnc-enc-zywrle.h deleted file mode 100644 index d436d588f..000000000 --- a/qemu/ui/vnc-enc-zywrle.h +++ /dev/null @@ -1,659 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. * - * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 * - * BY Hitachi Systems & Services, Ltd. * - * (Noriaki Yamazaki, Research & Development Center) * - * * - * * - ******************************************************************** -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Hitachi Systems & Services, Ltd. nor -the names of its contributors may be used to endorse or promote -products derived from this software without specific prior written -permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ********************************************************************/ - -#ifndef VNC_ENCODING_ZYWRLE_H -#define VNC_ENCODING_ZYWRLE_H - -/* Tables for Coefficients filtering. */ -#ifndef ZYWRLE_QUANTIZE -/* Type A:lower bit omitting of EZW style. */ -static const unsigned int zywrle_param[3][3]={ - {0x0000F000, 0x00000000, 0x00000000}, - {0x0000C000, 0x00F0F0F0, 0x00000000}, - {0x0000C000, 0x00C0C0C0, 0x00F0F0F0}, -/* {0x0000FF00, 0x00000000, 0x00000000}, - {0x0000FF00, 0x00FFFFFF, 0x00000000}, - {0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */ -}; -#else -/* Type B:Non liner quantization filter. */ -static const int8_t zywrle_conv[4][256]={ -{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}, -{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 64, 64, 64, 64, - 64, 64, 64, 64, 72, 72, 72, 72, - 72, 72, 72, 72, 80, 80, 80, 80, - 80, 80, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 96, 96, - 96, 96, 96, 104, 104, 104, 104, 104, - 104, 104, 104, 104, 104, 112, 112, 112, - 112, 112, 112, 112, 112, 112, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 0, -120, -120, -120, -120, -120, -120, -120, - -120, -120, -120, -112, -112, -112, -112, -112, - -112, -112, -112, -112, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -96, -96, - -96, -96, -96, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -80, - -80, -80, -80, -80, -80, -72, -72, -72, - -72, -72, -72, -72, -72, -64, -64, -64, - -64, -64, -64, -64, -64, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, - -48, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}, -{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 104, 104, 104, 104, 104, 104, 104, 104, - 104, 104, 104, 112, 112, 112, 112, 112, - 112, 112, 112, 112, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 0, -120, -120, -120, -120, -120, -120, -120, - -120, -120, -120, -120, -120, -112, -112, -112, - -112, -112, -112, -112, -112, -112, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, - -104, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, - -80, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, - -64, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, - -48, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}, -{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, - 0, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, - -88, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -} -}; - -static const int8_t *zywrle_param[3][3][3]={ - {{zywrle_conv[0], zywrle_conv[2], zywrle_conv[0]}, - {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}, - {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}}, - {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]}, - {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}, - {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}}, - {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]}, - {zywrle_conv[2], zywrle_conv[2], zywrle_conv[2]}, - {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}}, -}; -#endif - -/* Load/Save pixel stuffs. */ -#define ZYWRLE_YMASK15 0xFFFFFFF8 -#define ZYWRLE_UVMASK15 0xFFFFFFF8 -#define ZYWRLE_LOAD_PIXEL15(src, r, g, b) \ - do { \ - r = (((uint8_t*)src)[S_1]<< 1)& 0xF8; \ - g = (((uint8_t*)src)[S_1]<< 6) | (((uint8_t*)src)[S_0]>> 2); \ - g &= 0xF8; \ - b = (((uint8_t*)src)[S_0]<< 3)& 0xF8; \ - } while (0) - -#define ZYWRLE_SAVE_PIXEL15(dst, r, g, b) \ - do { \ - r &= 0xF8; \ - g &= 0xF8; \ - b &= 0xF8; \ - ((uint8_t*)dst)[S_1] = (uint8_t)((r >> 1)|(g >> 6)); \ - ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 2))& 0xFF); \ - } while (0) - -#define ZYWRLE_YMASK16 0xFFFFFFFC -#define ZYWRLE_UVMASK16 0xFFFFFFF8 -#define ZYWRLE_LOAD_PIXEL16(src, r, g, b) \ - do { \ - r = ((uint8_t*)src)[S_1] & 0xF8; \ - g = (((uint8_t*)src)[S_1]<< 5) | (((uint8_t*)src)[S_0] >> 3); \ - g &= 0xFC; \ - b = (((uint8_t*)src)[S_0]<< 3) & 0xF8; \ - } while (0) - -#define ZYWRLE_SAVE_PIXEL16(dst, r, g,b) \ - do { \ - r &= 0xF8; \ - g &= 0xFC; \ - b &= 0xF8; \ - ((uint8_t*)dst)[S_1] = (uint8_t)(r | (g >> 5)); \ - ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 3)) & 0xFF); \ - } while (0) - -#define ZYWRLE_YMASK32 0xFFFFFFFF -#define ZYWRLE_UVMASK32 0xFFFFFFFF -#define ZYWRLE_LOAD_PIXEL32(src, r, g, b) \ - do { \ - r = ((uint8_t*)src)[L_2]; \ - g = ((uint8_t*)src)[L_1]; \ - b = ((uint8_t*)src)[L_0]; \ - } while (0) -#define ZYWRLE_SAVE_PIXEL32(dst, r, g, b) \ - do { \ - ((uint8_t*)dst)[L_2] = (uint8_t)r; \ - ((uint8_t*)dst)[L_1] = (uint8_t)g; \ - ((uint8_t*)dst)[L_0] = (uint8_t)b; \ - } while (0) - -static inline void harr(int8_t *px0, int8_t *px1) -{ - /* Piecewise-Linear Harr(PLHarr) */ - int x0 = (int)*px0, x1 = (int)*px1; - int orgx0 = x0, orgx1 = x1; - - if ((x0 ^ x1) & 0x80) { - /* differ sign */ - x1 += x0; - if (((x1 ^ orgx1) & 0x80) == 0) { - /* |x1| > |x0| */ - x0 -= x1; /* H = -B */ - } - } else { - /* same sign */ - x0 -= x1; - if (((x0 ^ orgx0) & 0x80) == 0) { - /* |x0| > |x1| */ - x1 += x0; /* L = A */ - } - } - *px0 = (int8_t)x1; - *px1 = (int8_t)x0; -} - -/* - 1D-Wavelet transform. - - In coefficients array, the famous 'pyramid' decomposition is well used. - - 1D Model: - |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0 - |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1 - - But this method needs line buffer because H/L is different position from X0/X1. - So, I used 'interleave' decomposition instead of it. - - 1D Model: - |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0 - |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1 - - In this method, H/L and X0/X1 is always same position. - This leads us to more speed and less memory. - Of cause, the result of both method is quite same - because it's only difference that coefficient position. -*/ -static inline void wavelet_level(int *data, int size, int l, int skip_pixel) -{ - int s, ofs; - int8_t *px0; - int8_t *end; - - px0 = (int8_t*)data; - s = (8 << l) * skip_pixel; - end = px0 + (size >> (l + 1)) * s; - s -= 2; - ofs = (4 << l) * skip_pixel; - - while (px0 < end) { - harr(px0, px0 + ofs); - px0++; - harr(px0, px0 + ofs); - px0++; - harr(px0, px0 + ofs); - px0 += s; - } -} - -#ifndef ZYWRLE_QUANTIZE -/* Type A:lower bit omitting of EZW style. */ -static inline void filter_wavelet_square(int *buf, int width, int height, - int level, int l) -{ - int r, s; - int x, y; - int *h; - const unsigned int *m; - - m = &(zywrle_param[level - 1][l]); - s = 2 << l; - - for (r = 1; r < 4; r++) { - h = buf; - if (r & 0x01) { - h += s >> 1; - } - if (r & 0x02) { - h += (s >> 1) * width; - } - for (y = 0; y < height / s; y++) { - for (x = 0; x < width / s; x++) { - /* - these are same following code. - h[x] = h[x] / (~m[x]+1) * (~m[x]+1); - ( round h[x] with m[x] bit ) - '&' operator isn't 'round' but is 'floor'. - So, we must offset when h[x] is negative. - */ - if (((int8_t*)h)[0] & 0x80) { - ((int8_t*)h)[0] += ~((int8_t*)m)[0]; - } - if (((int8_t*)h)[1] & 0x80) { - ((int8_t*)h)[1] += ~((int8_t*)m)[1]; - } - if (((int8_t*)h)[2] & 0x80) { - ((int8_t*)h)[2] += ~((int8_t*)m)[2]; - } - *h &= *m; - h += s; - } - h += (s-1)*width; - } - } -} -#else -/* - Type B:Non liner quantization filter. - - Coefficients have Gaussian curve and smaller value which is - large part of coefficients isn't more important than larger value. - So, I use filter of Non liner quantize/dequantize table. - In general, Non liner quantize formula is explained as following. - - y=f(x) = sign(x)*round( ((abs(x)/(2^7))^ r )* 2^(bo-1) )*2^(8-bo) - x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi) - ( r:power coefficient bi:effective MSB in input bo:effective MSB in output ) - - r < 1.0 : Smaller value is more important than larger value. - r > 1.0 : Larger value is more important than smaller value. - r = 1.0 : Liner quantization which is same with EZW style. - - r = 0.75 is famous non liner quantization used in MP3 audio codec. - In contrast to audio data, larger value is important in wavelet coefficients. - So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ). - - As compared with EZW style liner quantization, this filter tended to be - more sharp edge and be more compression rate but be more blocking noise and be - less quality. Especially, the surface of graphic objects has distinguishable - noise in middle quality mode. - - We need only quantized-dequantized(filtered) value rather than quantized value - itself because all values are packed or palette-lized in later ZRLE section. - This lead us not to need to modify client decoder when we change - the filtering procedure in future. - Client only decodes coefficients given by encoder. -*/ -static inline void filter_wavelet_square(int *buf, int width, int height, - int level, int l) -{ - int r, s; - int x, y; - int *h; - const int8_t **m; - - m = zywrle_param[level - 1][l]; - s = 2 << l; - - for (r = 1; r < 4; r++) { - h = buf; - if (r & 0x01) { - h += s >> 1; - } - if (r & 0x02) { - h += (s >> 1) * width; - } - for (y = 0; y < height / s; y++) { - for (x = 0; x < width / s; x++) { - ((int8_t*)h)[0] = m[0][((uint8_t*)h)[0]]; - ((int8_t*)h)[1] = m[1][((uint8_t*)h)[1]]; - ((int8_t*)h)[2] = m[2][((uint8_t*)h)[2]]; - h += s; - } - h += (s - 1) * width; - } - } -} -#endif - -static inline void wavelet(int *buf, int width, int height, int level) -{ - int l, s; - int *top; - int *end; - - for (l = 0; l < level; l++) { - top = buf; - end = buf + height * width; - s = width << l; - while (top < end) { - wavelet_level(top, width, l, 1); - top += s; - } - top = buf; - end = buf + width; - s = 1<<l; - while (top < end) { - wavelet_level(top, height, l, width); - top += s; - } - filter_wavelet_square(buf, width, height, level, l); - } -} - - -/* Load/Save coefficients stuffs. - Coefficients manages as 24 bits little-endian pixel. */ -#define ZYWRLE_LOAD_COEFF(src, r, g, b) \ - do { \ - r = ((int8_t*)src)[2]; \ - g = ((int8_t*)src)[1]; \ - b = ((int8_t*)src)[0]; \ - } while (0) - -#define ZYWRLE_SAVE_COEFF(dst, r, g, b) \ - do { \ - ((int8_t*)dst)[2] = (int8_t)r; \ - ((int8_t*)dst)[1] = (int8_t)g; \ - ((int8_t*)dst)[0] = (int8_t)b; \ - } while (0) - -/* - RGB <=> YUV conversion stuffs. - YUV coversion is explained as following formula in strict meaning: - Y = 0.299R + 0.587G + 0.114B ( 0<=Y<=255) - U = -0.169R - 0.331G + 0.500B (-128<=U<=127) - V = 0.500R - 0.419G - 0.081B (-128<=V<=127) - - I use simple conversion RCT(reversible color transform) which is described - in JPEG-2000 specification. - Y = (R + 2G + B)/4 ( 0<=Y<=255) - U = B-G (-256<=U<=255) - V = R-G (-256<=V<=255) -*/ - -/* RCT is N-bit RGB to N-bit Y and N+1-bit UV. - For make Same N-bit, UV is lossy. - More exact PLHarr, we reduce to odd range(-127<=x<=127). */ -#define ZYWRLE_RGBYUV_(r, g, b, y, u, v, ymask, uvmask) \ - do { \ - y = (r + (g << 1) + b) >> 2; \ - u = b - g; \ - v = r - g; \ - y -= 128; \ - u >>= 1; \ - v >>= 1; \ - y &= ymask; \ - u &= uvmask; \ - v &= uvmask; \ - if (y == -128) { \ - y += (0xFFFFFFFF - ymask + 1); \ - } \ - if (u == -128) { \ - u += (0xFFFFFFFF - uvmask + 1); \ - } \ - if (v == -128) { \ - v += (0xFFFFFFFF - uvmask + 1); \ - } \ - } while (0) - - -/* - coefficient packing/unpacking stuffs. - Wavelet transform makes 4 sub coefficient image from 1 original image. - - model with pyramid decomposition: - +------+------+ - | | | - | L | Hx | - | | | - +------+------+ - | | | - | H | Hxy | - | | | - +------+------+ - - So, we must transfer each sub images individually in strict meaning. - But at least ZRLE meaning, following one decompositon image is same as - avobe individual sub image. I use this format. - (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L) - for simplified procedure for any wavelet level.) - - +------+------+ - | L | - +------+------+ - | Hx | - +------+------+ - | Hy | - +------+------+ - | Hxy | - +------+------+ -*/ -#define ZYWRLE_INC_PTR(data) \ - do { \ - data++; \ - if( data - p >= (w + uw) ) { \ - data += scanline-(w + uw); \ - p = data; \ - } \ - } while (0) - -#define ZYWRLE_TRANSFER_COEFF(buf, data, t, w, h, scanline, level, TRANS) \ - do { \ - ph = buf; \ - s = 2 << level; \ - if (t & 0x01) { \ - ph += s >> 1; \ - } \ - if (t & 0x02) { \ - ph += (s >> 1) * w; \ - } \ - end = ph + h * w; \ - while (ph < end) { \ - line = ph + w; \ - while (ph < line) { \ - TRANS \ - ZYWRLE_INC_PTR(data); \ - ph += s; \ - } \ - ph += (s - 1) * w; \ - } \ - } while (0) - -#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level) \ - ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \ - ZYWRLE_LOAD_COEFF(ph, r, g, b); \ - ZYWRLE_SAVE_PIXEL(data, r, g, b);) - -#define ZYWRLE_UNPACK_COEFF(buf, data, t, width, height, scanline, level) \ - ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \ - ZYWRLE_LOAD_PIXEL(data, r, g, b); \ - ZYWRLE_SAVE_COEFF(ph, r, g, b);) - -#define ZYWRLE_SAVE_UNALIGN(data, TRANS) \ - do { \ - top = buf + w * h; \ - end = buf + (w + uw) * (h + uh); \ - while (top < end) { \ - TRANS \ - ZYWRLE_INC_PTR(data); \ - top++; \ - } \ - } while (0) - -#define ZYWRLE_LOAD_UNALIGN(data,TRANS) \ - do { \ - top = buf + w * h; \ - if (uw) { \ - p = data + w; \ - end = (int*)(p + h * scanline); \ - while (p < (ZRLE_PIXEL*)end) { \ - line = (int*)(p + uw); \ - while (p < (ZRLE_PIXEL*)line) { \ - TRANS \ - p++; \ - top++; \ - } \ - p += scanline - uw; \ - } \ - } \ - if (uh) { \ - p = data + h * scanline; \ - end = (int*)(p + uh * scanline); \ - while (p < (ZRLE_PIXEL*)end) { \ - line = (int*)(p + w); \ - while (p < (ZRLE_PIXEL*)line) { \ - TRANS \ - p++; \ - top++; \ - } \ - p += scanline - w; \ - } \ - } \ - if (uw && uh) { \ - p= data + w + h * scanline; \ - end = (int*)(p + uh * scanline); \ - while (p < (ZRLE_PIXEL*)end) { \ - line = (int*)(p + uw); \ - while (p < (ZRLE_PIXEL*)line) { \ - TRANS \ - p++; \ - top++; \ - } \ - p += scanline-uw; \ - } \ - } \ - } while (0) - -static inline void zywrle_calc_size(int *w, int *h, int level) -{ - *w &= ~((1 << level) - 1); - *h &= ~((1 << level) - 1); -} - -#endif diff --git a/qemu/ui/vnc-jobs.c b/qemu/ui/vnc-jobs.c deleted file mode 100644 index 98ca978b0..000000000 --- a/qemu/ui/vnc-jobs.c +++ /dev/null @@ -1,356 +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 - * 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/osdep.h" -#include "vnc.h" -#include "vnc-jobs.h" -#include "qemu/sockets.h" -#include "qemu/main-loop.h" -#include "block/aio.h" - -/* - * Locking: - * - * There are three levels of locking: - * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) - * - VncDisplay global lock: mainly used for framebuffer updates to avoid - * screen corruption if the framebuffer is updated - * while the worker is doing something. - * - VncState::output lock: used to make sure the output buffer is not corrupted - * if two threads try to write on it at the same time - * - * While the VNC worker thread is working, the VncDisplay global lock is held - * to avoid screen corruption (this does not block vnc_refresh() because it - * uses trylock()) but the output lock is not held because the thread works on - * its own output buffer. - * When the encoding job is done, the worker thread will hold the output lock - * and copy its output buffer in vs->output. - */ - -struct VncJobQueue { - QemuCond cond; - QemuMutex mutex; - QemuThread thread; - bool exit; - QTAILQ_HEAD(, VncJob) jobs; -}; - -typedef struct VncJobQueue VncJobQueue; - -/* - * We use a single global queue, but most of the functions are - * already reentrant, so we can easily add more than one encoding thread - */ -static VncJobQueue *queue; - -static void vnc_lock_queue(VncJobQueue *queue) -{ - qemu_mutex_lock(&queue->mutex); -} - -static void vnc_unlock_queue(VncJobQueue *queue) -{ - qemu_mutex_unlock(&queue->mutex); -} - -VncJob *vnc_job_new(VncState *vs) -{ - VncJob *job = g_new0(VncJob, 1); - - job->vs = vs; - vnc_lock_queue(queue); - QLIST_INIT(&job->rectangles); - vnc_unlock_queue(queue); - return job; -} - -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) -{ - VncRectEntry *entry = g_new0(VncRectEntry, 1); - - entry->rect.x = x; - entry->rect.y = y; - entry->rect.w = w; - entry->rect.h = h; - - vnc_lock_queue(queue); - QLIST_INSERT_HEAD(&job->rectangles, entry, next); - vnc_unlock_queue(queue); - return 1; -} - -void vnc_job_push(VncJob *job) -{ - vnc_lock_queue(queue); - if (queue->exit || QLIST_EMPTY(&job->rectangles)) { - g_free(job); - } else { - QTAILQ_INSERT_TAIL(&queue->jobs, job, next); - qemu_cond_broadcast(&queue->cond); - } - vnc_unlock_queue(queue); -} - -static bool vnc_has_job_locked(VncState *vs) -{ - VncJob *job; - - QTAILQ_FOREACH(job, &queue->jobs, next) { - if (job->vs == vs || !vs) { - return true; - } - } - return false; -} - -bool vnc_has_job(VncState *vs) -{ - bool ret; - - vnc_lock_queue(queue); - ret = vnc_has_job_locked(vs); - vnc_unlock_queue(queue); - return ret; -} - -void vnc_jobs_clear(VncState *vs) -{ - VncJob *job, *tmp; - - vnc_lock_queue(queue); - QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) { - if (job->vs == vs || !vs) { - QTAILQ_REMOVE(&queue->jobs, job, next); - } - } - vnc_unlock_queue(queue); -} - -void vnc_jobs_join(VncState *vs) -{ - vnc_lock_queue(queue); - while (vnc_has_job_locked(vs)) { - qemu_cond_wait(&queue->cond, &queue->mutex); - } - vnc_unlock_queue(queue); - vnc_jobs_consume_buffer(vs); -} - -void vnc_jobs_consume_buffer(VncState *vs) -{ - bool flush; - - vnc_lock_output(vs); - if (vs->jobs_buffer.offset) { - if (vs->ioc != NULL && buffer_empty(&vs->output)) { - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); - } - buffer_move(&vs->output, &vs->jobs_buffer); - } - flush = vs->ioc != NULL && vs->abort != true; - vnc_unlock_output(vs); - - if (flush) { - vnc_flush(vs); - } -} - -/* - * Copy data for local use - */ -static void vnc_async_encoding_start(VncState *orig, VncState *local) -{ - buffer_init(&local->output, "vnc-worker-output"); - local->sioc = NULL; /* Don't do any network work on this thread */ - local->ioc = NULL; /* Don't do any network work on this thread */ - - local->vnc_encoding = orig->vnc_encoding; - local->features = orig->features; - local->vd = orig->vd; - local->lossy_rect = orig->lossy_rect; - local->write_pixels = orig->write_pixels; - local->client_pf = orig->client_pf; - local->client_be = orig->client_be; - local->tight = orig->tight; - local->zlib = orig->zlib; - local->hextile = orig->hextile; - local->zrle = orig->zrle; -} - -static void vnc_async_encoding_end(VncState *orig, VncState *local) -{ - orig->tight = local->tight; - orig->zlib = local->zlib; - orig->hextile = local->hextile; - orig->zrle = local->zrle; - orig->lossy_rect = local->lossy_rect; -} - -static int vnc_worker_thread_loop(VncJobQueue *queue) -{ - VncJob *job; - VncRectEntry *entry, *tmp; - VncState vs = {}; - int n_rectangles; - int saved_offset; - - vnc_lock_queue(queue); - while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) { - qemu_cond_wait(&queue->cond, &queue->mutex); - } - /* Here job can only be NULL if queue->exit is true */ - job = QTAILQ_FIRST(&queue->jobs); - vnc_unlock_queue(queue); - - if (queue->exit) { - return -1; - } - - vnc_lock_output(job->vs); - if (job->vs->ioc == NULL || job->vs->abort == true) { - vnc_unlock_output(job->vs); - goto disconnected; - } - if (buffer_empty(&job->vs->output)) { - /* - * Looks like a NOP as it obviously moves no data. But it - * moves the empty buffer, so we don't have to malloc a new - * one for vs.output - */ - buffer_move_empty(&vs.output, &job->vs->output); - } - vnc_unlock_output(job->vs); - - /* Make a local copy of vs and switch output buffers */ - vnc_async_encoding_start(job->vs, &vs); - - /* Start sending rectangles */ - 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); - - vnc_lock_display(job->vs->vd); - QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { - int n; - - if (job->vs->ioc == NULL) { - vnc_unlock_display(job->vs->vd); - /* Copy persistent encoding data */ - vnc_async_encoding_end(job->vs, &vs); - goto disconnected; - } - - n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, - entry->rect.w, entry->rect.h); - - if (n >= 0) { - n_rectangles += n; - } - g_free(entry); - } - vnc_unlock_display(job->vs->vd); - - /* Put n_rectangles at the beginning of the message */ - vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; - vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF; - - vnc_lock_output(job->vs); - if (job->vs->ioc != NULL) { - buffer_move(&job->vs->jobs_buffer, &vs.output); - /* Copy persistent encoding data */ - vnc_async_encoding_end(job->vs, &vs); - - qemu_bh_schedule(job->vs->bh); - } else { - buffer_reset(&vs.output); - /* Copy persistent encoding data */ - vnc_async_encoding_end(job->vs, &vs); - } - vnc_unlock_output(job->vs); - -disconnected: - vnc_lock_queue(queue); - QTAILQ_REMOVE(&queue->jobs, job, next); - vnc_unlock_queue(queue); - qemu_cond_broadcast(&queue->cond); - g_free(job); - return 0; -} - -static VncJobQueue *vnc_queue_init(void) -{ - VncJobQueue *queue = g_new0(VncJobQueue, 1); - - qemu_cond_init(&queue->cond); - qemu_mutex_init(&queue->mutex); - QTAILQ_INIT(&queue->jobs); - return queue; -} - -static void vnc_queue_clear(VncJobQueue *q) -{ - qemu_cond_destroy(&queue->cond); - qemu_mutex_destroy(&queue->mutex); - g_free(q); - queue = NULL; /* Unset global queue */ -} - -static void *vnc_worker_thread(void *arg) -{ - VncJobQueue *queue = arg; - - qemu_thread_get_self(&queue->thread); - - while (!vnc_worker_thread_loop(queue)) ; - vnc_queue_clear(queue); - return NULL; -} - -static bool vnc_worker_thread_running(void) -{ - return queue; /* Check global queue */ -} - -void vnc_start_worker_thread(void) -{ - VncJobQueue *q; - - if (vnc_worker_thread_running()) - return ; - - q = vnc_queue_init(); - qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q, - QEMU_THREAD_DETACHED); - queue = q; /* Set global queue */ -} diff --git a/qemu/ui/vnc-jobs.h b/qemu/ui/vnc-jobs.h deleted file mode 100644 index 044bf9fbf..000000000 --- a/qemu/ui/vnc-jobs.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * QEMU VNC display driver - * - * 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_JOBS_H -#define VNC_JOBS_H - -/* Jobs */ -VncJob *vnc_job_new(VncState *vs); -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h); -void vnc_job_push(VncJob *job); -bool vnc_has_job(VncState *vs); -void vnc_jobs_clear(VncState *vs); -void vnc_jobs_join(VncState *vs); - -void vnc_jobs_consume_buffer(VncState *vs); -void vnc_start_worker_thread(void); - -/* Locks */ -static inline int vnc_trylock_display(VncDisplay *vd) -{ - return qemu_mutex_trylock(&vd->mutex); -} - -static inline void vnc_lock_display(VncDisplay *vd) -{ - qemu_mutex_lock(&vd->mutex); -} - -static inline void vnc_unlock_display(VncDisplay *vd) -{ - qemu_mutex_unlock(&vd->mutex); -} - -static inline void vnc_lock_output(VncState *vs) -{ - qemu_mutex_lock(&vs->output_mutex); -} - -static inline void vnc_unlock_output(VncState *vs) -{ - qemu_mutex_unlock(&vs->output_mutex); -} - -#endif /* VNC_JOBS_H */ diff --git a/qemu/ui/vnc-palette.c b/qemu/ui/vnc-palette.c deleted file mode 100644 index 3b89d1af2..000000000 --- a/qemu/ui/vnc-palette.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * QEMU VNC display driver: palette hash table - * - * 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/osdep.h" -#include "vnc-palette.h" -#include <glib.h> - -static VncPaletteEntry *palette_find(const VncPalette *palette, - uint32_t color, unsigned int hash) -{ - VncPaletteEntry *entry; - - QLIST_FOREACH(entry, &palette->table[hash], next) { - if (entry->color == color) { - return entry; - } - } - - return NULL; -} - -static unsigned int palette_hash(uint32_t rgb, int bpp) -{ - if (bpp == 16) { - return ((unsigned int)(((rgb >> 8) + rgb) & 0xFF)); - } else { - return ((unsigned int)(((rgb >> 16) + (rgb >> 8)) & 0xFF)); - } -} - -VncPalette *palette_new(size_t max, int bpp) -{ - VncPalette *palette; - - palette = g_malloc0(sizeof(*palette)); - palette_init(palette, max, bpp); - return palette; -} - -void palette_init(VncPalette *palette, size_t max, int bpp) -{ - memset(palette, 0, sizeof (*palette)); - palette->max = max; - palette->bpp = bpp; -} - -void palette_destroy(VncPalette *palette) -{ - g_free(palette); -} - -int palette_put(VncPalette *palette, uint32_t color) -{ - unsigned int hash; - unsigned int idx = palette->size; - VncPaletteEntry *entry; - - hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE; - entry = palette_find(palette, color, hash); - - if (!entry && palette->size >= palette->max) { - return 0; - } - if (!entry) { - VncPaletteEntry *entry; - - entry = &palette->pool[palette->size]; - entry->color = color; - entry->idx = idx; - QLIST_INSERT_HEAD(&palette->table[hash], entry, next); - palette->size++; - } - return palette->size; -} - -int palette_idx(const VncPalette *palette, uint32_t color) -{ - VncPaletteEntry *entry; - unsigned int hash; - - hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE; - entry = palette_find(palette, color, hash); - return (entry == NULL ? -1 : entry->idx); -} - -size_t palette_size(const VncPalette *palette) -{ - return palette->size; -} - -void palette_iter(const VncPalette *palette, - void (*iter)(int idx, uint32_t color, void *opaque), - void *opaque) -{ - int i; - VncPaletteEntry *entry; - - for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) { - QLIST_FOREACH(entry, &palette->table[i], next) { - iter(entry->idx, entry->color, opaque); - } - } -} - -uint32_t palette_color(const VncPalette *palette, int idx, bool *found) -{ - int i; - VncPaletteEntry *entry; - - for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) { - QLIST_FOREACH(entry, &palette->table[i], next) { - if (entry->idx == idx) { - *found = true; - return entry->color; - } - } - } - - *found = false; - return -1; -} - -static void palette_fill_cb(int idx, uint32_t color, void *opaque) -{ - uint32_t *colors = opaque; - - colors[idx] = color; -} - -size_t palette_fill(const VncPalette *palette, - uint32_t colors[VNC_PALETTE_MAX_SIZE]) -{ - palette_iter(palette, palette_fill_cb, colors); - return palette_size(palette); -} diff --git a/qemu/ui/vnc-palette.h b/qemu/ui/vnc-palette.h deleted file mode 100644 index 1bd4318f5..000000000 --- a/qemu/ui/vnc-palette.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * QEMU VNC display driver: palette hash table - * - * 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. - */ - -#ifndef VNC_PALETTE_H -#define VNC_PALETTE_H - -#include "qapi/qmp/qlist.h" -#include "qemu/queue.h" - -#define VNC_PALETTE_HASH_SIZE 256 -#define VNC_PALETTE_MAX_SIZE 256 - -typedef struct VncPaletteEntry { - int idx; - uint32_t color; - QLIST_ENTRY(VncPaletteEntry) next; -} VncPaletteEntry; - -typedef struct VncPalette { - VncPaletteEntry pool[VNC_PALETTE_MAX_SIZE]; - size_t size; - size_t max; - int bpp; - QLIST_HEAD(,VncPaletteEntry) table[VNC_PALETTE_HASH_SIZE]; -} VncPalette; - -VncPalette *palette_new(size_t max, int bpp); -void palette_init(VncPalette *palette, size_t max, int bpp); -void palette_destroy(VncPalette *palette); - -int palette_put(VncPalette *palette, uint32_t color); -int palette_idx(const VncPalette *palette, uint32_t color); -size_t palette_size(const VncPalette *palette); - -void palette_iter(const VncPalette *palette, - void (*iter)(int idx, uint32_t color, void *opaque), - void *opaque); -uint32_t palette_color(const VncPalette *palette, int idx, bool *found); -size_t palette_fill(const VncPalette *palette, - uint32_t colors[VNC_PALETTE_MAX_SIZE]); - -#endif /* VNC_PALETTE_H */ diff --git a/qemu/ui/vnc-ws.c b/qemu/ui/vnc-ws.c deleted file mode 100644 index 7c79a4c37..000000000 --- a/qemu/ui/vnc-ws.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * QEMU VNC display driver: Websockets support - * - * Copyright (C) 2010 Joel Martin - * Copyright (C) 2012 Tim Hardeck - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "vnc.h" -#include "io/channel-websock.h" - -static void vncws_tls_handshake_done(Object *source, - Error *err, - gpointer user_data) -{ - VncState *vs = user_data; - - if (err) { - VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); - vnc_client_error(vs); - } else { - VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); - vs->ioc_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); - } -} - - -gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - GIOCondition condition G_GNUC_UNUSED, - void *opaque) -{ - VncState *vs = opaque; - QIOChannelTLS *tls; - Error *err = NULL; - - VNC_DEBUG("TLS Websocket connection required\n"); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - vs->ioc_tag = 0; - } - - tls = qio_channel_tls_new_server( - vs->ioc, - vs->vd->tlscreds, - vs->vd->tlsaclname, - &err); - if (!tls) { - VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); - error_free(err); - vnc_client_error(vs); - return TRUE; - } - - VNC_DEBUG("Start TLS WS handshake process\n"); - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(tls); - vs->tls = qio_channel_tls_get_session(tls); - - qio_channel_tls_handshake(tls, - vncws_tls_handshake_done, - vs, - NULL); - - return TRUE; -} - - -static void vncws_handshake_done(Object *source, - Error *err, - gpointer user_data) -{ - VncState *vs = user_data; - - if (err) { - VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err)); - vnc_client_error(vs); - } else { - VNC_DEBUG("Websock handshake complete, starting VNC protocol\n"); - vnc_init_state(vs); - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } -} - - -gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - GIOCondition condition G_GNUC_UNUSED, - void *opaque) -{ - VncState *vs = opaque; - QIOChannelWebsock *wioc; - - VNC_DEBUG("Websocket negotiate starting\n"); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - vs->ioc_tag = 0; - } - - wioc = qio_channel_websock_new_server(vs->ioc); - - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(wioc); - - qio_channel_websock_handshake(wioc, - vncws_handshake_done, - vs, - NULL); - - return TRUE; -} diff --git a/qemu/ui/vnc-ws.h b/qemu/ui/vnc-ws.h deleted file mode 100644 index 652b6fc39..000000000 --- a/qemu/ui/vnc-ws.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * QEMU VNC display driver: Websockets support - * - * Copyright (C) 2010 Joel Martin - * Copyright (C) 2012 Tim Hardeck - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __QEMU_UI_VNC_WS_H -#define __QEMU_UI_VNC_WS_H - -gboolean vncws_tls_handshake_io(QIOChannel *ioc, - GIOCondition condition, - void *opaque); -gboolean vncws_handshake_io(QIOChannel *ioc, - GIOCondition condition, - void *opaque); - -#endif /* __QEMU_UI_VNC_WS_H */ diff --git a/qemu/ui/vnc.c b/qemu/ui/vnc.c deleted file mode 100644 index d2ebf1fb7..000000000 --- a/qemu/ui/vnc.c +++ /dev/null @@ -1,3880 +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 "qemu/osdep.h" -#include "vnc.h" -#include "vnc-jobs.h" -#include "trace.h" -#include "hw/qdev.h" -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" -#include "qemu/sockets.h" -#include "qemu/timer.h" -#include "qemu/acl.h" -#include "qemu/config-file.h" -#include "qapi/qmp/qerror.h" -#include "qapi/qmp/types.h" -#include "qmp-commands.h" -#include "ui/input.h" -#include "qapi-event.h" -#include "crypto/hash.h" -#include "crypto/tlscredsanon.h" -#include "crypto/tlscredsx509.h" -#include "qom/object_interfaces.h" -#include "qemu/cutils.h" - -#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT -#define VNC_REFRESH_INTERVAL_INC 50 -#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE -static const struct timeval VNC_REFRESH_STATS = { 0, 500000 }; -static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 }; - -#include "vnc_keysym.h" -#include "crypto/cipher.h" - -static QTAILQ_HEAD(, VncDisplay) vnc_displays = - QTAILQ_HEAD_INITIALIZER(vnc_displays); - -static int vnc_cursor_define(VncState *vs); -static void vnc_release_modifiers(VncState *vs); - -static void vnc_set_share_mode(VncState *vs, VncShareMode mode) -{ -#ifdef _VNC_DEBUG - static const char *mn[] = { - [0] = "undefined", - [VNC_SHARE_MODE_CONNECTING] = "connecting", - [VNC_SHARE_MODE_SHARED] = "shared", - [VNC_SHARE_MODE_EXCLUSIVE] = "exclusive", - [VNC_SHARE_MODE_DISCONNECTED] = "disconnected", - }; - fprintf(stderr, "%s/%p: %s -> %s\n", __func__, - vs->ioc, mn[vs->share_mode], mn[mode]); -#endif - - switch (vs->share_mode) { - case VNC_SHARE_MODE_CONNECTING: - vs->vd->num_connecting--; - break; - case VNC_SHARE_MODE_SHARED: - vs->vd->num_shared--; - break; - case VNC_SHARE_MODE_EXCLUSIVE: - vs->vd->num_exclusive--; - break; - default: - break; - } - - vs->share_mode = mode; - - switch (vs->share_mode) { - case VNC_SHARE_MODE_CONNECTING: - vs->vd->num_connecting++; - break; - case VNC_SHARE_MODE_SHARED: - vs->vd->num_shared++; - break; - case VNC_SHARE_MODE_EXCLUSIVE: - vs->vd->num_exclusive++; - break; - default: - break; - } -} - - -static void vnc_init_basic_info(SocketAddress *addr, - VncBasicInfo *info, - Error **errp) -{ - switch (addr->type) { - case SOCKET_ADDRESS_KIND_INET: - info->host = g_strdup(addr->u.inet.data->host); - info->service = g_strdup(addr->u.inet.data->port); - if (addr->u.inet.data->ipv6) { - info->family = NETWORK_ADDRESS_FAMILY_IPV6; - } else { - info->family = NETWORK_ADDRESS_FAMILY_IPV4; - } - break; - - case SOCKET_ADDRESS_KIND_UNIX: - info->host = g_strdup(""); - info->service = g_strdup(addr->u.q_unix.data->path); - info->family = NETWORK_ADDRESS_FAMILY_UNIX; - break; - - default: - error_setg(errp, "Unsupported socket kind %d", - addr->type); - break; - } - - return; -} - -static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc, - VncBasicInfo *info, - Error **errp) -{ - SocketAddress *addr = NULL; - - addr = qio_channel_socket_get_local_address(ioc, errp); - if (!addr) { - return; - } - - vnc_init_basic_info(addr, info, errp); - qapi_free_SocketAddress(addr); -} - -static void vnc_init_basic_info_from_remote_addr(QIOChannelSocket *ioc, - VncBasicInfo *info, - Error **errp) -{ - SocketAddress *addr = NULL; - - addr = qio_channel_socket_get_remote_address(ioc, errp); - if (!addr) { - return; - } - - vnc_init_basic_info(addr, info, errp); - qapi_free_SocketAddress(addr); -} - -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: - 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"; - } - case VNC_AUTH_SASL: - return "sasl"; - } - return "unknown"; -} - -static VncServerInfo *vnc_server_info_get(VncDisplay *vd) -{ - VncServerInfo *info; - Error *err = NULL; - - info = g_malloc(sizeof(*info)); - vnc_init_basic_info_from_server_addr(vd->lsock, - qapi_VncServerInfo_base(info), &err); - info->has_auth = true; - info->auth = g_strdup(vnc_auth_name(vd)); - if (err) { - qapi_free_VncServerInfo(info); - info = NULL; - error_free(err); - } - return info; -} - -static void vnc_client_cache_auth(VncState *client) -{ - if (!client->info) { - return; - } - - if (client->tls) { - client->info->x509_dname = - qcrypto_tls_session_get_peer_name(client->tls); - client->info->has_x509_dname = - client->info->x509_dname != NULL; - } -#ifdef CONFIG_VNC_SASL - if (client->sasl.conn && - client->sasl.username) { - client->info->has_sasl_username = true; - client->info->sasl_username = g_strdup(client->sasl.username); - } -#endif -} - -static void vnc_client_cache_addr(VncState *client) -{ - Error *err = NULL; - - client->info = g_malloc0(sizeof(*client->info)); - vnc_init_basic_info_from_remote_addr(client->sioc, - qapi_VncClientInfo_base(client->info), - &err); - if (err) { - qapi_free_VncClientInfo(client->info); - client->info = NULL; - error_free(err); - } -} - -static void vnc_qmp_event(VncState *vs, QAPIEvent event) -{ - VncServerInfo *si; - - if (!vs->info) { - return; - } - - si = vnc_server_info_get(vs->vd); - if (!si) { - return; - } - - switch (event) { - case QAPI_EVENT_VNC_CONNECTED: - qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info), - &error_abort); - break; - case QAPI_EVENT_VNC_INITIALIZED: - qapi_event_send_vnc_initialized(si, vs->info, &error_abort); - break; - case QAPI_EVENT_VNC_DISCONNECTED: - qapi_event_send_vnc_disconnected(si, vs->info, &error_abort); - break; - default: - break; - } - - qapi_free_VncServerInfo(si); -} - -static VncClientInfo *qmp_query_vnc_client(const VncState *client) -{ - VncClientInfo *info; - Error *err = NULL; - - info = g_malloc0(sizeof(*info)); - - vnc_init_basic_info_from_remote_addr(client->sioc, - qapi_VncClientInfo_base(info), - &err); - if (err) { - error_free(err); - qapi_free_VncClientInfo(info); - return NULL; - } - - info->websocket = client->websocket; - - if (client->tls) { - info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls); - info->has_x509_dname = info->x509_dname != NULL; - } -#ifdef CONFIG_VNC_SASL - if (client->sasl.conn && client->sasl.username) { - info->has_sasl_username = true; - info->sasl_username = g_strdup(client->sasl.username); - } -#endif - - return info; -} - -static VncDisplay *vnc_display_find(const char *id) -{ - VncDisplay *vd; - - if (id == NULL) { - return QTAILQ_FIRST(&vnc_displays); - } - QTAILQ_FOREACH(vd, &vnc_displays, next) { - if (strcmp(id, vd->id) == 0) { - return vd; - } - } - return NULL; -} - -static VncClientInfoList *qmp_query_client_list(VncDisplay *vd) -{ - VncClientInfoList *cinfo, *prev = NULL; - VncState *client; - - QTAILQ_FOREACH(client, &vd->clients, next) { - cinfo = g_new0(VncClientInfoList, 1); - cinfo->value = qmp_query_vnc_client(client); - cinfo->next = prev; - prev = cinfo; - } - return prev; -} - -VncInfo *qmp_query_vnc(Error **errp) -{ - VncInfo *info = g_malloc0(sizeof(*info)); - VncDisplay *vd = vnc_display_find(NULL); - SocketAddress *addr = NULL; - - if (vd == NULL || !vd->enabled) { - info->enabled = false; - } else { - info->enabled = true; - - /* for compatibility with the original command */ - info->has_clients = true; - info->clients = qmp_query_client_list(vd); - - if (vd->lsock == NULL) { - return info; - } - - addr = qio_channel_socket_get_local_address(vd->lsock, errp); - if (!addr) { - goto out_error; - } - - switch (addr->type) { - case SOCKET_ADDRESS_KIND_INET: - info->host = g_strdup(addr->u.inet.data->host); - info->service = g_strdup(addr->u.inet.data->port); - if (addr->u.inet.data->ipv6) { - info->family = NETWORK_ADDRESS_FAMILY_IPV6; - } else { - info->family = NETWORK_ADDRESS_FAMILY_IPV4; - } - break; - - case SOCKET_ADDRESS_KIND_UNIX: - info->host = g_strdup(""); - info->service = g_strdup(addr->u.q_unix.data->path); - info->family = NETWORK_ADDRESS_FAMILY_UNIX; - break; - - default: - error_setg(errp, "Unsupported socket kind %d", - addr->type); - goto out_error; - } - - info->has_host = true; - info->has_service = true; - info->has_family = true; - - info->has_auth = true; - info->auth = g_strdup(vnc_auth_name(vd)); - } - - qapi_free_SocketAddress(addr); - return info; - -out_error: - qapi_free_SocketAddress(addr); - qapi_free_VncInfo(info); - return NULL; -} - -static VncBasicInfoList *qmp_query_server_entry(QIOChannelSocket *ioc, - bool websocket, - VncBasicInfoList *prev) -{ - VncBasicInfoList *list; - VncBasicInfo *info; - Error *err = NULL; - SocketAddress *addr; - - addr = qio_channel_socket_get_local_address(ioc, &err); - if (!addr) { - error_free(err); - return prev; - } - - info = g_new0(VncBasicInfo, 1); - vnc_init_basic_info(addr, info, &err); - qapi_free_SocketAddress(addr); - if (err) { - qapi_free_VncBasicInfo(info); - error_free(err); - return prev; - } - info->websocket = websocket; - - list = g_new0(VncBasicInfoList, 1); - list->value = info; - list->next = prev; - return list; -} - -static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info) -{ - switch (vd->auth) { - case VNC_AUTH_VNC: - info->auth = VNC_PRIMARY_AUTH_VNC; - break; - case VNC_AUTH_RA2: - info->auth = VNC_PRIMARY_AUTH_RA2; - break; - case VNC_AUTH_RA2NE: - info->auth = VNC_PRIMARY_AUTH_RA2NE; - break; - case VNC_AUTH_TIGHT: - info->auth = VNC_PRIMARY_AUTH_TIGHT; - break; - case VNC_AUTH_ULTRA: - info->auth = VNC_PRIMARY_AUTH_ULTRA; - break; - case VNC_AUTH_TLS: - info->auth = VNC_PRIMARY_AUTH_TLS; - break; - case VNC_AUTH_VENCRYPT: - info->auth = VNC_PRIMARY_AUTH_VENCRYPT; - info->has_vencrypt = true; - switch (vd->subauth) { - case VNC_AUTH_VENCRYPT_PLAIN: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_PLAIN; - break; - case VNC_AUTH_VENCRYPT_TLSNONE: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_NONE; - break; - case VNC_AUTH_VENCRYPT_TLSVNC: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_VNC; - break; - case VNC_AUTH_VENCRYPT_TLSPLAIN: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_PLAIN; - break; - case VNC_AUTH_VENCRYPT_X509NONE: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_NONE; - break; - case VNC_AUTH_VENCRYPT_X509VNC: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_VNC; - break; - case VNC_AUTH_VENCRYPT_X509PLAIN: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_PLAIN; - break; - case VNC_AUTH_VENCRYPT_TLSSASL: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_SASL; - break; - case VNC_AUTH_VENCRYPT_X509SASL: - info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_SASL; - break; - default: - info->has_vencrypt = false; - break; - } - break; - case VNC_AUTH_SASL: - info->auth = VNC_PRIMARY_AUTH_SASL; - break; - case VNC_AUTH_NONE: - default: - info->auth = VNC_PRIMARY_AUTH_NONE; - break; - } -} - -VncInfo2List *qmp_query_vnc_servers(Error **errp) -{ - VncInfo2List *item, *prev = NULL; - VncInfo2 *info; - VncDisplay *vd; - DeviceState *dev; - - QTAILQ_FOREACH(vd, &vnc_displays, next) { - info = g_new0(VncInfo2, 1); - info->id = g_strdup(vd->id); - info->clients = qmp_query_client_list(vd); - qmp_query_auth(vd, info); - if (vd->dcl.con) { - dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con), - "device", NULL)); - info->has_display = true; - info->display = g_strdup(dev->id); - } - if (vd->lsock != NULL) { - info->server = qmp_query_server_entry( - vd->lsock, false, info->server); - } - if (vd->lwebsock != NULL) { - info->server = qmp_query_server_entry( - vd->lwebsock, true, info->server); - } - - item = g_new0(VncInfo2List, 1); - item->value = info; - item->next = prev; - prev = item; - } - return prev; -} - -/* 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, bool sync); -static void vnc_disconnect_start(VncState *vs); - -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(DisplayChangeListener *dcl); -static int vnc_refresh_server_surface(VncDisplay *vd); - -static int vnc_width(VncDisplay *vd) -{ - return MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds), - VNC_DIRTY_PIXELS_PER_BIT)); -} - -static int vnc_height(VncDisplay *vd) -{ - return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds)); -} - -static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], - VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT), - VncDisplay *vd, - int x, int y, int w, int h) -{ - int width = vnc_width(vd); - int height = vnc_height(vd); - - /* this is needed this to ensure we updated all affected - * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */ - w += (x % VNC_DIRTY_PIXELS_PER_BIT); - x -= (x % VNC_DIRTY_PIXELS_PER_BIT); - - x = MIN(x, width); - y = MIN(y, height); - w = MIN(x + w, width) - x; - h = MIN(y + h, height); - - for (; y < h; y++) { - bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT, - DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT)); - } -} - -static void vnc_dpy_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - struct VncSurface *s = &vd->guest; - - vnc_set_area_dirty(s->dirty, vd, x, y, w, h); -} - -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); -} - - -static void vnc_desktop_resize(VncState *vs) -{ - if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { - return; - } - if (vs->client_width == pixman_image_get_width(vs->vd->server) && - vs->client_height == pixman_image_get_height(vs->vd->server)) { - return; - } - vs->client_width = pixman_image_get_width(vs->vd->server); - vs->client_height = pixman_image_get_height(vs->vd->server); - vnc_lock_output(vs); - 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_unlock_output(vs); - vnc_flush(vs); -} - -static void vnc_abort_display_jobs(VncDisplay *vd) -{ - VncState *vs; - - QTAILQ_FOREACH(vs, &vd->clients, next) { - vnc_lock_output(vs); - vs->abort = true; - vnc_unlock_output(vs); - } - QTAILQ_FOREACH(vs, &vd->clients, next) { - vnc_jobs_join(vs); - } - QTAILQ_FOREACH(vs, &vd->clients, next) { - vnc_lock_output(vs); - vs->abort = false; - vnc_unlock_output(vs); - } -} - -int vnc_server_fb_stride(VncDisplay *vd) -{ - return pixman_image_get_stride(vd->server); -} - -void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) -{ - uint8_t *ptr; - - ptr = (uint8_t *)pixman_image_get_data(vd->server); - ptr += y * vnc_server_fb_stride(vd); - ptr += x * VNC_SERVER_FB_BYTES; - return ptr; -} - -static void vnc_update_server_surface(VncDisplay *vd) -{ - qemu_pixman_image_unref(vd->server); - vd->server = NULL; - - if (QTAILQ_EMPTY(&vd->clients)) { - return; - } - - vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, - vnc_width(vd), - vnc_height(vd), - NULL, 0); -} - -static void vnc_dpy_switch(DisplayChangeListener *dcl, - DisplaySurface *surface) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - VncState *vs; - int width, height; - - vnc_abort_display_jobs(vd); - vd->ds = surface; - - /* server surface */ - vnc_update_server_surface(vd); - - /* guest surface */ - qemu_pixman_image_unref(vd->guest.fb); - vd->guest.fb = pixman_image_ref(surface->image); - vd->guest.format = surface->format; - width = vnc_width(vd); - height = vnc_height(vd); - memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty)); - vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0, - width, height); - - QTAILQ_FOREACH(vs, &vd->clients, next) { - vnc_colordepth(vs); - vnc_desktop_resize(vs); - if (vs->vd->cursor) { - vnc_cursor_define(vs); - } - memset(vs->dirty, 0x00, sizeof(vs->dirty)); - vnc_set_area_dirty(vs->dirty, vd, 0, 0, - width, height); - } -} - -/* fastest code */ -static void vnc_write_pixels_copy(VncState *vs, - 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; - -#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8) - r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8; - g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8; - b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8; -#else -# error need some bits here if you change VNC_SERVER_FB_FORMAT -#endif - v = (r << vs->client_pf.rshift) | - (g << vs->client_pf.gshift) | - (b << vs->client_pf.bshift); - switch (vs->client_pf.bytes_per_pixel) { - case 1: - buf[0] = v; - break; - case 2: - if (vs->client_be) { - buf[0] = v >> 8; - buf[1] = v; - } else { - buf[1] = v >> 8; - buf[0] = v; - } - break; - default: - case 4: - if (vs->client_be) { - 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, - void *pixels1, int size) -{ - uint8_t buf[4]; - - if (VNC_SERVER_FB_BYTES == 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->client_pf.bytes_per_pixel); - } - } -} - -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 = vnc_server_fb_ptr(vd, x, y); - for (i = 0; i < h; i++) { - vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES); - row += vnc_server_fb_stride(vd); - } - return 1; -} - -int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) -{ - int n = 0; - bool encode_raw = false; - size_t saved_offs = vs->output.offset; - - 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; - case VNC_ENCODING_TIGHT_PNG: - n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h); - break; - case VNC_ENCODING_ZRLE: - n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h); - break; - case VNC_ENCODING_ZYWRLE: - n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h); - break; - default: - encode_raw = true; - break; - } - - /* If the client has the same pixel format as our internal buffer and - * a RAW encoding would need less space fall back to RAW encoding to - * save bandwidth and processing power in the client. */ - if (!encode_raw && vs->write_pixels == vnc_write_pixels_copy && - 12 + h * w * VNC_SERVER_FB_BYTES <= (vs->output.offset - saved_offs)) { - vs->output.offset = saved_offs; - encode_raw = true; - } - - if (encode_raw) { - vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW); - n = vnc_raw_send_framebuffer_update(vs, x, y, w, h); - } - - 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_lock_output(vs); - 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_unlock_output(vs); - vnc_flush(vs); -} - -static void vnc_dpy_copy(DisplayChangeListener *dcl, - int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - VncState *vs, *vn; - uint8_t *src_row; - uint8_t *dst_row; - int i, x, y, pitch, inc, w_lim, s; - int cmp_bytes; - - if (!vd->server) { - /* no client connected */ - return; - } - - 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, true); - /* vs might be free()ed here */ - } - } - - /* do bitblit op on the local surface too */ - pitch = vnc_server_fb_stride(vd); - src_row = vnc_server_fb_ptr(vd, src_x, src_y); - dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y); - 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 - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); - if (w_lim < 0) { - w_lim = w; - } else { - w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT); - } - 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 = (VNC_DIRTY_PIXELS_PER_BIT - - (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); - s = MIN(s, w_lim); - } else { - s = VNC_DIRTY_PIXELS_PER_BIT; - } - cmp_bytes = s * VNC_SERVER_FB_BYTES; - 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)) { - set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT), - vs->dirty[y]); - } - } - } - src_row += pitch - w * VNC_SERVER_FB_BYTES; - dst_row += pitch - w * VNC_SERVER_FB_BYTES; - 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(DisplayChangeListener *dcl, - 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; - int isize; - - if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) { - vnc_lock_output(vs); - 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->client_pf.bytes_per_pixel; - vnc_write_pixels_generic(vs, c->data, isize); - vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize); - vnc_unlock_output(vs); - return 0; - } - return -1; -} - -static void vnc_dpy_cursor_define(DisplayChangeListener *dcl, - QEMUCursor *c) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - VncState *vs; - - cursor_put(vd->cursor); - g_free(vd->cursor_mask); - - vd->cursor = c; - cursor_get(vd->cursor); - vd->cursor_msize = cursor_get_mono_bpl(c) * c->height; - vd->cursor_mask = g_malloc0(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(VncState *vs, - int y, int last_x, int x, int height) -{ - int h; - - for (h = 1; h < (height - y); h++) { - if (!test_bit(last_x, vs->dirty[y + h])) { - break; - } - bitmap_clear(vs->dirty[y + h], last_x, x - last_x); - } - - return h; -} - -static int vnc_update_client(VncState *vs, int has_dirty, bool sync) -{ - vs->has_dirty += has_dirty; - if (vs->need_update && vs->ioc != NULL) { - VncDisplay *vd = vs->vd; - VncJob *job; - int y; - int height, width; - int n = 0; - - if (vs->output.offset && !vs->audio_cap && !vs->force_update) - /* kernel send buffers are full -> drop frames to throttle */ - return 0; - - if (!vs->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. - */ - job = vnc_job_new(vs); - - height = pixman_image_get_height(vd->server); - width = pixman_image_get_width(vd->server); - - y = 0; - for (;;) { - int x, h; - unsigned long x2; - unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, - height * VNC_DIRTY_BPL(vs), - y * VNC_DIRTY_BPL(vs)); - if (offset == height * VNC_DIRTY_BPL(vs)) { - /* no more dirty bits */ - break; - } - y = offset / VNC_DIRTY_BPL(vs); - x = offset % VNC_DIRTY_BPL(vs); - x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], - VNC_DIRTY_BPL(vs), x); - bitmap_clear(vs->dirty[y], x, x2 - x); - h = find_and_clear_dirty_height(vs, y, x, x2, height); - x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT); - if (x2 > x) { - n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, - (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); - } - if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) { - y += h; - if (y == height) { - break; - } - } - } - - vnc_job_push(job); - if (sync) { - vnc_jobs_join(vs); - } - vs->force_update = 0; - vs->has_dirty = 0; - return n; - } - - if (vs->disconnecting) { - vnc_disconnect_finish(vs); - } else if (sync) { - vnc_jobs_join(vs); - } - - return 0; -} - -/* audio */ -static void audio_capture_notify(void *opaque, audcnotification_e cmd) -{ - VncState *vs = opaque; - - switch (cmd) { - case AUD_CNOTIFY_DISABLE: - vnc_lock_output(vs); - 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_unlock_output(vs); - vnc_flush(vs); - break; - - case AUD_CNOTIFY_ENABLE: - vnc_lock_output(vs); - 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_unlock_output(vs); - 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_lock_output(vs); - 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_unlock_output(vs); - vnc_flush(vs); -} - -static void audio_add(VncState *vs) -{ - struct audio_capture_ops ops; - - if (vs->audio_cap) { - error_report("audio already running"); - 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) { - error_report("Failed to add audio capture"); - } -} - -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->disconnecting) { - return; - } - vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - qio_channel_close(vs->ioc, NULL); - vs->disconnecting = TRUE; -} - -void vnc_disconnect_finish(VncState *vs) -{ - int i; - - vnc_jobs_join(vs); /* Wait encoding jobs */ - - vnc_lock_output(vs); - vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED); - - buffer_free(&vs->input); - buffer_free(&vs->output); - - qapi_free_VncClientInfo(vs->info); - - vnc_zlib_clear(vs); - vnc_tight_clear(vs); - vnc_zrle_clear(vs); - -#ifdef CONFIG_VNC_SASL - vnc_sasl_client_cleanup(vs); -#endif /* CONFIG_VNC_SASL */ - audio_del(vs); - vnc_release_modifiers(vs); - - if (vs->initialized) { - QTAILQ_REMOVE(&vs->vd->clients, vs, next); - qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); - if (QTAILQ_EMPTY(&vs->vd->clients)) { - /* last client gone */ - vnc_update_server_surface(vs->vd); - } - } - - if (vs->vd->lock_key_sync) - qemu_remove_led_event_handler(vs->led); - vnc_unlock_output(vs); - - qemu_mutex_destroy(&vs->output_mutex); - if (vs->bh != NULL) { - qemu_bh_delete(vs->bh); - } - buffer_free(&vs->jobs_buffer); - - for (i = 0; i < VNC_STAT_ROWS; ++i) { - g_free(vs->lossy_rect[i]); - } - g_free(vs->lossy_rect); - - object_unref(OBJECT(vs->ioc)); - vs->ioc = NULL; - object_unref(OBJECT(vs->sioc)); - vs->sioc = NULL; - g_free(vs); -} - -ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp) -{ - if (ret <= 0) { - if (ret == 0) { - VNC_DEBUG("Closing down client sock: EOF\n"); - } else if (ret != QIO_CHANNEL_ERR_BLOCK) { - VNC_DEBUG("Closing down client sock: ret %d (%s)\n", - ret, errp ? error_get_pretty(*errp) : "Unknown"); - } - - vnc_disconnect_start(vs); - if (errp) { - error_free(*errp); - *errp = NULL; - } - 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. - */ -ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) -{ - Error *err = NULL; - ssize_t ret; - ret = qio_channel_write( - vs->ioc, (const char *)data, datalen, &err); - VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret); - return vnc_client_io_error(vs, ret, &err); -} - - -/* - * 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 ssize_t vnc_client_write_plain(VncState *vs) -{ - ssize_t 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; - - buffer_advance(&vs->output, ret); - - if (vs->output.offset == 0) { - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } - - 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) - */ -static void vnc_client_write_locked(VncState *vs) -{ -#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); - } -} - -static void vnc_client_write(VncState *vs) -{ - - vnc_lock_output(vs); - if (vs->output.offset) { - vnc_client_write_locked(vs); - } else if (vs->ioc != NULL) { - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } - vnc_unlock_output(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. - */ -ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) -{ - ssize_t ret; - Error *err = NULL; - ret = qio_channel_read( - vs->ioc, (char *)data, datalen, &err); - VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret); - return vnc_client_io_error(vs, ret, &err); -} - - -/* - * 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 ssize_t vnc_client_read_plain(VncState *vs) -{ - ssize_t 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; -} - -static void vnc_jobs_bh(void *opaque) -{ - VncState *vs = opaque; - - vnc_jobs_consume_buffer(vs); -} - -/* - * 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) - */ -static void vnc_client_read(VncState *vs) -{ - ssize_t 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->disconnecting) { - 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->disconnecting) { - vnc_disconnect_finish(vs); - return; - } - - if (!ret) { - buffer_advance(&vs->input, len); - } else { - vs->read_handler_expect = ret; - } - } -} - -gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED, - GIOCondition condition, void *opaque) -{ - VncState *vs = opaque; - if (condition & G_IO_IN) { - vnc_client_read(vs); - } - if (condition & G_IO_OUT) { - vnc_client_write(vs); - } - return TRUE; -} - - -void vnc_write(VncState *vs, const void *data, size_t len) -{ - buffer_reserve(&vs->output, len); - - if (vs->ioc != NULL && buffer_empty(&vs->output)) { - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); - } - - 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) -{ - vnc_lock_output(vs); - if (vs->ioc != NULL && vs->output.offset) { - vnc_client_write_locked(vs); - } - vnc_unlock_output(vs); -} - -static uint8_t read_u8(uint8_t *data, size_t offset) -{ - return data[offset]; -} - -static uint16_t read_u16(uint8_t *data, size_t offset) -{ - return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); -} - -static 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, void *data) -{ - VncState *vs = container_of(notifier, VncState, mouse_mode_notifier); - int absolute = qemu_input_is_absolute(); - - if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { - vnc_lock_output(vs); - 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, - pixman_image_get_width(vs->vd->server), - pixman_image_get_height(vs->vd->server), - VNC_ENCODING_POINTER_TYPE_CHANGE); - vnc_unlock_output(vs); - vnc_flush(vs); - } - vs->absolute = absolute; -} - -static void pointer_event(VncState *vs, int button_mask, int x, int y) -{ - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = 0x01, - [INPUT_BUTTON_MIDDLE] = 0x02, - [INPUT_BUTTON_RIGHT] = 0x04, - [INPUT_BUTTON_WHEEL_UP] = 0x08, - [INPUT_BUTTON_WHEEL_DOWN] = 0x10, - }; - QemuConsole *con = vs->vd->dcl.con; - int width = pixman_image_get_width(vs->vd->server); - int height = pixman_image_get_height(vs->vd->server); - - if (vs->last_bmask != button_mask) { - qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask); - vs->last_bmask = button_mask; - } - - if (vs->absolute) { - qemu_input_queue_abs(con, INPUT_AXIS_X, x, width); - qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height); - } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) { - qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF); - qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF); - } else { - if (vs->last_x != -1) { - qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x); - qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y); - } - vs->last_x = x; - vs->last_y = y; - } - qemu_input_event_sync(); -} - -static void reset_keys(VncState *vs) -{ - int i; - for(i = 0; i < 256; i++) { - if (vs->modifiers_state[i]) { - qemu_input_event_send_key_number(vs->vd->dcl.con, i, false); - vs->modifiers_state[i] = 0; - } - } -} - -static void press_key(VncState *vs, int keysym) -{ - int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; - qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true); - qemu_input_event_send_key_delay(0); - qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); - qemu_input_event_send_key_delay(0); -} - -static int current_led_state(VncState *vs) -{ - int ledstate = 0; - - if (vs->modifiers_state[0x46]) { - ledstate |= QEMU_SCROLL_LOCK_LED; - } - if (vs->modifiers_state[0x45]) { - ledstate |= QEMU_NUM_LOCK_LED; - } - if (vs->modifiers_state[0x3a]) { - ledstate |= QEMU_CAPS_LOCK_LED; - } - - return ledstate; -} - -static void vnc_led_state_change(VncState *vs) -{ - int ledstate = 0; - - if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) { - return; - } - - ledstate = current_led_state(vs); - vnc_lock_output(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, 1, 1, VNC_ENCODING_LED_STATE); - vnc_write_u8(vs, ledstate); - vnc_unlock_output(vs); - vnc_flush(vs); -} - -static void kbd_leds(void *opaque, int ledstate) -{ - VncState *vs = opaque; - int caps, num, scr; - bool has_changed = (ledstate != current_led_state(vs)); - - trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED), - (ledstate & QEMU_NUM_LOCK_LED), - (ledstate & QEMU_SCROLL_LOCK_LED)); - - caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0; - num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0; - scr = ledstate & QEMU_SCROLL_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; - } - if (vs->modifiers_state[0x46] != scr) { - vs->modifiers_state[0x46] = scr; - } - - /* Sending the current led state message to the client */ - if (has_changed) { - vnc_led_state_change(vs); - } -} - -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 (vs->vd->dcl.con == NULL && - 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; - } - - /* Turn off the lock state sync logic if the client support the led - state extension. - */ - if (down && vs->vd->lock_key_sync && - !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) && - 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]) { - trace_vnc_key_sync_numlock(true); - vs->modifiers_state[0x45] = 1; - press_key(vs, 0xff7f); - } - } else { - if (vs->modifiers_state[0x45]) { - trace_vnc_key_sync_numlock(false); - vs->modifiers_state[0x45] = 0; - press_key(vs, 0xff7f); - } - } - } - - if (down && vs->vd->lock_key_sync && - !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) && - ((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) { - trace_vnc_key_sync_capslock(false); - vs->modifiers_state[0x3a] = 0; - press_key(vs, 0xffe5); - } - } else { - if (uppercase != shift) { - trace_vnc_key_sync_capslock(true); - vs->modifiers_state[0x3a] = 1; - press_key(vs, 0xffe5); - } - } - } - - if (qemu_console_is_graphic(NULL)) { - qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down); - } else { - bool numlock = vs->modifiers_state[0x45]; - bool control = (vs->modifiers_state[0x1d] || - vs->modifiers_state[0x9d]); - /* QEMU console emulation */ - if (down) { - 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: - if (control) { - kbd_put_keysym(sym & 0x1f); - } else { - kbd_put_keysym(sym); - } - break; - } - } - } -} - -static void vnc_release_modifiers(VncState *vs) -{ - static const int keycodes[] = { - /* shift, control, alt keys, both left & right */ - 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8, - }; - int i, keycode; - - if (!qemu_console_is_graphic(NULL)) { - return; - } - for (i = 0; i < ARRAY_SIZE(keycodes); i++) { - keycode = keycodes[i]; - if (!vs->modifiers_state[keycode]) { - continue; - } - qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); - } -} - -static const char *code2name(int keycode) -{ - return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)]; -} - -static void key_event(VncState *vs, int down, uint32_t sym) -{ - int keycode; - int lsym = sym; - - if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) { - lsym = lsym - 'A' + 'a'; - } - - keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK; - trace_vnc_key_event_map(down, sym, keycode, code2name(keycode)); - 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 { - trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode)); - do_key_event(vs, down, keycode, sym); - } -} - -static void framebuffer_update_request(VncState *vs, int incremental, - int x, int y, int w, int h) -{ - vs->need_update = 1; - - if (incremental) { - return; - } - - vs->force_update = 1; - vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); -} - -static void send_ext_key_event_ack(VncState *vs) -{ - vnc_lock_output(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, - pixman_image_get_width(vs->vd->server), - pixman_image_get_height(vs->vd->server), - VNC_ENCODING_EXT_KEY_EVENT); - vnc_unlock_output(vs); - vnc_flush(vs); -} - -static void send_ext_audio_ack(VncState *vs) -{ - vnc_lock_output(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, - pixman_image_get_width(vs->vd->server), - pixman_image_get_height(vs->vd->server), - VNC_ENCODING_AUDIO); - vnc_unlock_output(vs); - 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 preferred 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; -#ifdef CONFIG_VNC_PNG - case VNC_ENCODING_TIGHT_PNG: - vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; - vs->vnc_encoding = enc; - break; -#endif - case VNC_ENCODING_ZLIB: - vs->features |= VNC_FEATURE_ZLIB_MASK; - vs->vnc_encoding = enc; - break; - case VNC_ENCODING_ZRLE: - vs->features |= VNC_FEATURE_ZRLE_MASK; - vs->vnc_encoding = enc; - break; - case VNC_ENCODING_ZYWRLE: - vs->features |= VNC_FEATURE_ZYWRLE_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; - if (vs->vd->cursor) { - vnc_cursor_define(vs); - } - 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_LED_STATE: - vs->features |= VNC_FEATURE_LED_STATE_MASK; - break; - case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9: - vs->tight.compression = (enc & 0x0F); - break; - case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9: - if (vs->vd->lossy) { - 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, NULL); - vnc_led_state_change(vs); -} - -static void set_pixel_conversion(VncState *vs) -{ - pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf); - - if (fmt == VNC_SERVER_FB_FORMAT) { - 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; - } - - switch (bits_per_pixel) { - case 8: - case 16: - case 32: - break; - default: - vnc_client_error(vs); - return; - } - - vs->client_pf.rmax = red_max ? red_max : 0xFF; - vs->client_pf.rbits = hweight_long(red_max); - vs->client_pf.rshift = red_shift; - vs->client_pf.rmask = red_max << red_shift; - vs->client_pf.gmax = green_max ? green_max : 0xFF; - vs->client_pf.gbits = hweight_long(green_max); - vs->client_pf.gshift = green_shift; - vs->client_pf.gmask = green_max << green_shift; - vs->client_pf.bmax = blue_max ? blue_max : 0xFF; - vs->client_pf.bbits = hweight_long(blue_max); - vs->client_pf.bshift = blue_shift; - vs->client_pf.bmask = blue_max << blue_shift; - vs->client_pf.bits_per_pixel = bits_per_pixel; - vs->client_pf.bytes_per_pixel = bits_per_pixel / 8; - vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel; - vs->client_be = big_endian_flag; - - set_pixel_conversion(vs); - - graphic_hw_invalidate(vs->vd->dcl.con); - graphic_hw_update(vs->vd->dcl.con); -} - -static void pixel_format_message (VncState *vs) { - char pad[3] = { 0, 0, 0 }; - - vs->client_pf = qemu_default_pixelformat(32); - - vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */ - vnc_write_u8(vs, vs->client_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->client_pf.rmax); /* red-max */ - vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */ - vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */ - vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */ - vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */ - vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */ - vnc_write(vs, pad, 3); /* padding */ - - vnc_hextile_set_pixel_conversion(vs, 0); - vs->write_pixels = vnc_write_pixels_copy; -} - -static void vnc_colordepth(VncState *vs) -{ - if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { - /* Sending a WMVi message to notify the client*/ - vnc_lock_output(vs); - 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, - pixman_image_get_width(vs->vd->server), - pixman_image_get_height(vs->vd->server), - VNC_ENCODING_WMVi); - pixel_format_message(vs); - vnc_unlock_output(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) { - update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); - } - - 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 > (1 << 20)) { - error_report("vnc: client_cut_text msg payload has %u bytes" - " which exceeds our limit of 1MB.", dlen); - vnc_client_error(vs); - break; - } - 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: - VNC_DEBUG("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) { - VNC_DEBUG("Invalid audio channel coount %d\n", - read_u8(data, 5)); - vnc_client_error(vs); - break; - } - vs->as.freq = read_u32(data, 6); - break; - default: - VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4)); - vnc_client_error(vs); - break; - } - break; - - default: - VNC_DEBUG("Msg: %d\n", read_u16(data, 0)); - vnc_client_error(vs); - break; - } - break; - default: - VNC_DEBUG("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]; - VncShareMode mode; - int size; - - mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE; - switch (vs->vd->share_policy) { - case VNC_SHARE_POLICY_IGNORE: - /* - * Ignore the shared flag. Nothing to do here. - * - * Doesn't conform to the rfb spec but is traditional qemu - * behavior, thus left here as option for compatibility - * reasons. - */ - break; - case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE: - /* - * Policy: Allow clients ask for exclusive access. - * - * Implementation: When a client asks for exclusive access, - * disconnect all others. Shared connects are allowed as long - * as no exclusive connection exists. - * - * This is how the rfb spec suggests to handle the shared flag. - */ - if (mode == VNC_SHARE_MODE_EXCLUSIVE) { - VncState *client; - QTAILQ_FOREACH(client, &vs->vd->clients, next) { - if (vs == client) { - continue; - } - if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE && - client->share_mode != VNC_SHARE_MODE_SHARED) { - continue; - } - vnc_disconnect_start(client); - } - } - if (mode == VNC_SHARE_MODE_SHARED) { - if (vs->vd->num_exclusive > 0) { - vnc_disconnect_start(vs); - return 0; - } - } - break; - case VNC_SHARE_POLICY_FORCE_SHARED: - /* - * Policy: Shared connects only. - * Implementation: Disallow clients asking for exclusive access. - * - * Useful for shared desktop sessions where you don't want - * someone forgetting to say -shared when running the vnc - * client disconnect everybody else. - */ - if (mode == VNC_SHARE_MODE_EXCLUSIVE) { - vnc_disconnect_start(vs); - return 0; - } - break; - } - vnc_set_share_mode(vs, mode); - - if (vs->vd->num_shared > vs->vd->connections_limit) { - vnc_disconnect_start(vs); - return 0; - } - - vs->client_width = pixman_image_get_width(vs->vd->server); - vs->client_height = pixman_image_get_height(vs->vd->server); - 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, QAPI_EVENT_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]; - size_t i, pwlen; - unsigned char key[8]; - time_t now = time(NULL); - QCryptoCipher *cipher = NULL; - Error *err = NULL; - - if (!vs->vd->password) { - VNC_DEBUG("No password configured on server"); - goto reject; - } - if (vs->vd->expires < now) { - VNC_DEBUG("Password is expired"); - goto reject; - } - - 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; - - cipher = qcrypto_cipher_new( - QCRYPTO_CIPHER_ALG_DES_RFB, - QCRYPTO_CIPHER_MODE_ECB, - key, G_N_ELEMENTS(key), - &err); - if (!cipher) { - VNC_DEBUG("Cannot initialize cipher %s", - error_get_pretty(err)); - error_free(err); - goto reject; - } - - if (qcrypto_cipher_encrypt(cipher, - vs->challenge, - response, - VNC_AUTH_CHALLENGE_SIZE, - &err) < 0) { - VNC_DEBUG("Cannot encrypt challenge %s", - error_get_pretty(err)); - error_free(err); - goto reject; - } - - /* Compare expected vs actual challenge response */ - if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { - VNC_DEBUG("Client challenge response did not match\n"); - goto reject; - } else { - VNC_DEBUG("Accepting VNC challenge response\n"); - vnc_write_u32(vs, 0); /* Accept auth */ - vnc_flush(vs); - - start_client_init(vs); - } - - qcrypto_cipher_free(cipher); - return 0; - -reject: - 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); - qcrypto_cipher_free(cipher); - 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->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->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; - - case VNC_AUTH_VENCRYPT: - VNC_DEBUG("Accept VeNCrypt auth\n"); - start_auth_vencrypt(vs); - break; - -#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->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->auth == VNC_AUTH_NONE) { - VNC_DEBUG("Tell client auth none\n"); - vnc_write_u32(vs, vs->auth); - vnc_flush(vs); - start_client_init(vs); - } else if (vs->auth == VNC_AUTH_VNC) { - VNC_DEBUG("Tell client VNC auth\n"); - vnc_write_u32(vs, vs->auth); - vnc_flush(vs); - start_auth_vnc(vs); - } else { - VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->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->auth); - vnc_write_u8(vs, 1); /* num auth */ - vnc_write_u8(vs, vs->auth); - vnc_read_when(vs, protocol_client_auth, 1); - vnc_flush(vs); - } - - return 0; -} - -static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y) -{ - struct VncSurface *vs = &vd->guest; - - return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT]; -} - -void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h) -{ - int i, j; - - w = (x + w) / VNC_STAT_RECT; - h = (y + h) / VNC_STAT_RECT; - x /= VNC_STAT_RECT; - y /= VNC_STAT_RECT; - - for (j = y; j <= h; j++) { - for (i = x; i <= w; i++) { - vs->lossy_rect[j][i] = 1; - } - } -} - -static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y) -{ - VncState *vs; - int sty = y / VNC_STAT_RECT; - int stx = x / VNC_STAT_RECT; - int has_dirty = 0; - - y = y / VNC_STAT_RECT * VNC_STAT_RECT; - x = x / VNC_STAT_RECT * VNC_STAT_RECT; - - QTAILQ_FOREACH(vs, &vd->clients, next) { - int j; - - /* kernel send buffers are full -> refresh later */ - if (vs->output.offset) { - continue; - } - - if (!vs->lossy_rect[sty][stx]) { - continue; - } - - vs->lossy_rect[sty][stx] = 0; - for (j = 0; j < VNC_STAT_RECT; ++j) { - bitmap_set(vs->dirty[y + j], - x / VNC_DIRTY_PIXELS_PER_BIT, - VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT); - } - has_dirty++; - } - - return has_dirty; -} - -static int vnc_update_stats(VncDisplay *vd, struct timeval * tv) -{ - int width = pixman_image_get_width(vd->guest.fb); - int height = pixman_image_get_height(vd->guest.fb); - int x, y; - struct timeval res; - int has_dirty = 0; - - for (y = 0; y < height; y += VNC_STAT_RECT) { - for (x = 0; x < width; x += VNC_STAT_RECT) { - VncRectStat *rect = vnc_stat_rect(vd, x, y); - - rect->updated = false; - } - } - - qemu_timersub(tv, &VNC_REFRESH_STATS, &res); - - if (timercmp(&vd->guest.last_freq_check, &res, >)) { - return has_dirty; - } - vd->guest.last_freq_check = *tv; - - for (y = 0; y < height; y += VNC_STAT_RECT) { - for (x = 0; x < width; x += VNC_STAT_RECT) { - VncRectStat *rect= vnc_stat_rect(vd, x, y); - int count = ARRAY_SIZE(rect->times); - struct timeval min, max; - - if (!timerisset(&rect->times[count - 1])) { - continue ; - } - - max = rect->times[(rect->idx + count - 1) % count]; - qemu_timersub(tv, &max, &res); - - if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) { - rect->freq = 0; - has_dirty += vnc_refresh_lossy_rect(vd, x, y); - memset(rect->times, 0, sizeof (rect->times)); - continue ; - } - - min = rect->times[rect->idx]; - max = rect->times[(rect->idx + count - 1) % count]; - qemu_timersub(&max, &min, &res); - - rect->freq = res.tv_sec + res.tv_usec / 1000000.; - rect->freq /= count; - rect->freq = 1. / rect->freq; - } - } - return has_dirty; -} - -double vnc_update_freq(VncState *vs, int x, int y, int w, int h) -{ - int i, j; - double total = 0; - int num = 0; - - x = (x / VNC_STAT_RECT) * VNC_STAT_RECT; - y = (y / VNC_STAT_RECT) * VNC_STAT_RECT; - - for (j = y; j <= y + h; j += VNC_STAT_RECT) { - for (i = x; i <= x + w; i += VNC_STAT_RECT) { - total += vnc_stat_rect(vs->vd, i, j)->freq; - num++; - } - } - - if (num) { - return total / num; - } else { - return 0; - } -} - -static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv) -{ - VncRectStat *rect; - - rect = vnc_stat_rect(vd, x, y); - if (rect->updated) { - return ; - } - rect->times[rect->idx] = *tv; - rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times); - rect->updated = true; -} - -static int vnc_refresh_server_surface(VncDisplay *vd) -{ - int width = MIN(pixman_image_get_width(vd->guest.fb), - pixman_image_get_width(vd->server)); - int height = MIN(pixman_image_get_height(vd->guest.fb), - pixman_image_get_height(vd->server)); - int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0; - uint8_t *guest_row0 = NULL, *server_row0; - VncState *vs; - int has_dirty = 0; - pixman_image_t *tmpbuf = NULL; - - struct timeval tv = { 0, 0 }; - - if (!vd->non_adaptive) { - gettimeofday(&tv, NULL); - has_dirty = vnc_update_stats(vd, &tv); - } - - /* - * Walk through the guest dirty map. - * Check and copy modified bits from guest to server surface. - * Update server dirty map. - */ - server_row0 = (uint8_t *)pixman_image_get_data(vd->server); - server_stride = guest_stride = guest_ll = - pixman_image_get_stride(vd->server); - cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES, - server_stride); - if (vd->guest.format != VNC_SERVER_FB_FORMAT) { - int width = pixman_image_get_width(vd->server); - tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); - } else { - int guest_bpp = - PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb)); - guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); - guest_stride = pixman_image_get_stride(vd->guest.fb); - guest_ll = pixman_image_get_width(vd->guest.fb) * ((guest_bpp + 7) / 8); - } - line_bytes = MIN(server_stride, guest_ll); - - for (;;) { - int x; - uint8_t *guest_ptr, *server_ptr; - unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty, - height * VNC_DIRTY_BPL(&vd->guest), - y * VNC_DIRTY_BPL(&vd->guest)); - if (offset == height * VNC_DIRTY_BPL(&vd->guest)) { - /* no more dirty bits */ - break; - } - y = offset / VNC_DIRTY_BPL(&vd->guest); - x = offset % VNC_DIRTY_BPL(&vd->guest); - - server_ptr = server_row0 + y * server_stride + x * cmp_bytes; - - if (vd->guest.format != VNC_SERVER_FB_FORMAT) { - qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y); - guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf); - } else { - guest_ptr = guest_row0 + y * guest_stride; - } - guest_ptr += x * cmp_bytes; - - for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT); - x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { - int _cmp_bytes = cmp_bytes; - if (!test_and_clear_bit(x, vd->guest.dirty[y])) { - continue; - } - if ((x + 1) * cmp_bytes > line_bytes) { - _cmp_bytes = line_bytes - x * cmp_bytes; - } - assert(_cmp_bytes >= 0); - if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) { - continue; - } - memcpy(server_ptr, guest_ptr, _cmp_bytes); - if (!vd->non_adaptive) { - vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT, - y, &tv); - } - QTAILQ_FOREACH(vs, &vd->clients, next) { - set_bit(x, vs->dirty[y]); - } - has_dirty++; - } - - y++; - } - qemu_pixman_image_unref(tmpbuf); - return has_dirty; -} - -static void vnc_refresh(DisplayChangeListener *dcl) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - VncState *vs, *vn; - int has_dirty, rects = 0; - - if (QTAILQ_EMPTY(&vd->clients)) { - update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX); - return; - } - - graphic_hw_update(vd->dcl.con); - - if (vnc_trylock_display(vd)) { - update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); - return; - } - - has_dirty = vnc_refresh_server_surface(vd); - vnc_unlock_display(vd); - - QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { - rects += vnc_update_client(vs, has_dirty, false); - /* vs might be free()ed here */ - } - - if (has_dirty && rects) { - vd->dcl.update_interval /= 2; - if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) { - vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE; - } - } else { - vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC; - if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) { - vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX; - } - } -} - -static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, - bool skipauth, bool websocket) -{ - VncState *vs = g_new0(VncState, 1); - int i; - - vs->sioc = sioc; - object_ref(OBJECT(vs->sioc)); - vs->ioc = QIO_CHANNEL(sioc); - object_ref(OBJECT(vs->ioc)); - vs->vd = vd; - - buffer_init(&vs->input, "vnc-input/%p", sioc); - buffer_init(&vs->output, "vnc-output/%p", sioc); - buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc); - - buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc); - buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc); - buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc); -#ifdef CONFIG_VNC_JPEG - buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc); -#endif -#ifdef CONFIG_VNC_PNG - buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc); -#endif - buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc); - buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc); - buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc); - buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc); - - if (skipauth) { - vs->auth = VNC_AUTH_NONE; - vs->subauth = VNC_AUTH_INVALID; - } else { - if (websocket) { - vs->auth = vd->ws_auth; - vs->subauth = VNC_AUTH_INVALID; - } else { - vs->auth = vd->auth; - vs->subauth = vd->subauth; - } - } - VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n", - sioc, websocket, vs->auth, vs->subauth); - - vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect)); - for (i = 0; i < VNC_STAT_ROWS; ++i) { - vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS); - } - - VNC_DEBUG("New client on socket %p\n", vs->sioc); - update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); - qio_channel_set_blocking(vs->ioc, false, NULL); - if (websocket) { - vs->websocket = 1; - if (vd->ws_tls) { - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL); - } else { - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vncws_handshake_io, vs, NULL); - } - } else { - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } - - vnc_client_cache_addr(vs); - vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED); - vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING); - - if (!vs->websocket) { - vnc_init_state(vs); - } - - if (vd->num_connecting > vd->connections_limit) { - QTAILQ_FOREACH(vs, &vd->clients, next) { - if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) { - vnc_disconnect_start(vs); - return; - } - } - } -} - -void vnc_init_state(VncState *vs) -{ - vs->initialized = true; - VncDisplay *vd = vs->vd; - bool first_client = QTAILQ_EMPTY(&vd->clients); - - 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; - - qemu_mutex_init(&vs->output_mutex); - vs->bh = qemu_bh_new(vnc_jobs_bh, vs); - - QTAILQ_INSERT_TAIL(&vd->clients, vs, next); - if (first_client) { - vnc_update_server_surface(vd); - } - - graphic_hw_update(vd->dcl.con); - - 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); - - /* vs might be free()ed here */ -} - -static gboolean vnc_listen_io(QIOChannel *ioc, - GIOCondition condition, - void *opaque) -{ - VncDisplay *vs = opaque; - QIOChannelSocket *sioc = NULL; - Error *err = NULL; - - /* Catch-up */ - graphic_hw_update(vs->dcl.con); - sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err); - if (sioc != NULL) { - qio_channel_set_delay(QIO_CHANNEL(sioc), false); - vnc_connect(vs, sioc, false, - ioc != QIO_CHANNEL(vs->lsock)); - object_unref(OBJECT(sioc)); - } else { - /* client probably closed connection before we got there */ - error_free(err); - } - - return TRUE; -} - -static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "vnc", - .dpy_refresh = vnc_refresh, - .dpy_gfx_copy = vnc_dpy_copy, - .dpy_gfx_update = vnc_dpy_update, - .dpy_gfx_switch = vnc_dpy_switch, - .dpy_gfx_check_format = qemu_pixman_check_format, - .dpy_mouse_set = vnc_mouse_set, - .dpy_cursor_define = vnc_dpy_cursor_define, -}; - -void vnc_display_init(const char *id) -{ - VncDisplay *vs; - - if (vnc_display_find(id) != NULL) { - return; - } - vs = g_malloc0(sizeof(*vs)); - - vs->id = strdup(id); - QTAILQ_INSERT_TAIL(&vnc_displays, vs, next); - - QTAILQ_INIT(&vs->clients); - vs->expires = TIME_MAX; - - if (keyboard_layout) { - trace_vnc_key_map_init(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); - - qemu_mutex_init(&vs->mutex); - vnc_start_worker_thread(); - - vs->dcl.ops = &dcl_ops; - register_displaychangelistener(&vs->dcl); -} - - -static void vnc_display_close(VncDisplay *vs) -{ - if (!vs) - return; - vs->enabled = false; - vs->is_unix = false; - if (vs->lsock != NULL) { - if (vs->lsock_tag) { - g_source_remove(vs->lsock_tag); - } - object_unref(OBJECT(vs->lsock)); - vs->lsock = NULL; - } - vs->ws_enabled = false; - if (vs->lwebsock != NULL) { - if (vs->lwebsock_tag) { - g_source_remove(vs->lwebsock_tag); - } - object_unref(OBJECT(vs->lwebsock)); - vs->lwebsock = NULL; - } - vs->auth = VNC_AUTH_INVALID; - vs->subauth = VNC_AUTH_INVALID; - if (vs->tlscreds) { - object_unparent(OBJECT(vs->tlscreds)); - vs->tlscreds = NULL; - } - g_free(vs->tlsaclname); - vs->tlsaclname = NULL; -} - -int vnc_display_password(const char *id, const char *password) -{ - VncDisplay *vs = vnc_display_find(id); - - if (!vs) { - return -EINVAL; - } - if (vs->auth == VNC_AUTH_NONE) { - error_printf_unless_qmp("If you want use passwords please enable " - "password auth using '-vnc ${dpy},password'."); - return -EINVAL; - } - - g_free(vs->password); - vs->password = g_strdup(password); - - return 0; -} - -int vnc_display_pw_expire(const char *id, time_t expires) -{ - VncDisplay *vs = vnc_display_find(id); - - if (!vs) { - return -EINVAL; - } - - vs->expires = expires; - return 0; -} - -char *vnc_display_local_addr(const char *id) -{ - VncDisplay *vs = vnc_display_find(id); - SocketAddress *addr; - char *ret; - Error *err = NULL; - - assert(vs); - - addr = qio_channel_socket_get_local_address(vs->lsock, &err); - if (!addr) { - return NULL; - } - - if (addr->type != SOCKET_ADDRESS_KIND_INET) { - qapi_free_SocketAddress(addr); - return NULL; - } - ret = g_strdup_printf("%s;%s", addr->u.inet.data->host, - addr->u.inet.data->port); - qapi_free_SocketAddress(addr); - - return ret; -} - -static QemuOptsList qemu_vnc_opts = { - .name = "vnc", - .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head), - .implied_opt_name = "vnc", - .desc = { - { - .name = "vnc", - .type = QEMU_OPT_STRING, - },{ - .name = "websocket", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-creds", - .type = QEMU_OPT_STRING, - },{ - /* Deprecated in favour of tls-creds */ - .name = "x509", - .type = QEMU_OPT_STRING, - },{ - .name = "share", - .type = QEMU_OPT_STRING, - },{ - .name = "display", - .type = QEMU_OPT_STRING, - },{ - .name = "head", - .type = QEMU_OPT_NUMBER, - },{ - .name = "connections", - .type = QEMU_OPT_NUMBER, - },{ - .name = "to", - .type = QEMU_OPT_NUMBER, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - },{ - .name = "password", - .type = QEMU_OPT_BOOL, - },{ - .name = "reverse", - .type = QEMU_OPT_BOOL, - },{ - .name = "lock-key-sync", - .type = QEMU_OPT_BOOL, - },{ - .name = "sasl", - .type = QEMU_OPT_BOOL, - },{ - /* Deprecated in favour of tls-creds */ - .name = "tls", - .type = QEMU_OPT_BOOL, - },{ - /* Deprecated in favour of tls-creds */ - .name = "x509verify", - .type = QEMU_OPT_STRING, - },{ - .name = "acl", - .type = QEMU_OPT_BOOL, - },{ - .name = "lossy", - .type = QEMU_OPT_BOOL, - },{ - .name = "non-adaptive", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - - -static int -vnc_display_setup_auth(VncDisplay *vs, - bool password, - bool sasl, - bool websocket, - Error **errp) -{ - /* - * We have a choice of 3 authentication options - * - * 1. none - * 2. vnc - * 3. sasl - * - * The channel can be run in 2 modes - * - * 1. clear - * 2. tls - * - * And TLS can use 2 types of credentials - * - * 1. anon - * 2. x509 - * - * We thus have 9 possible logical combinations - * - * 1. clear + none - * 2. clear + vnc - * 3. clear + sasl - * 4. tls + anon + none - * 5. tls + anon + vnc - * 6. tls + anon + sasl - * 7. tls + x509 + none - * 8. tls + x509 + vnc - * 9. tls + x509 + sasl - * - * These need to be mapped into the VNC auth schemes - * in an appropriate manner. In regular VNC, all the - * TLS options get mapped into VNC_AUTH_VENCRYPT - * sub-auth types. - * - * In websockets, the https:// protocol already provides - * TLS support, so there is no need to make use of the - * VeNCrypt extension. Furthermore, websockets browser - * clients could not use VeNCrypt even if they wanted to, - * as they cannot control when the TLS handshake takes - * place. Thus there is no option but to rely on https://, - * meaning combinations 4->6 and 7->9 will be mapped to - * VNC auth schemes in the same way as combos 1->3. - * - * Regardless of fact that we have a different mapping to - * VNC auth mechs for plain VNC vs websockets VNC, the end - * result has the same security characteristics. - */ - if (password) { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } - if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { - VNC_DEBUG("Initializing VNC server with x509 password auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS password auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; - } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); - return -1; - } - } else { - VNC_DEBUG("Initializing VNC server with password auth\n"); - vs->auth = VNC_AUTH_VNC; - vs->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vs->ws_auth = VNC_AUTH_VNC; - } else { - vs->ws_auth = VNC_AUTH_INVALID; - } - } else if (sasl) { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } - if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { - VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509SASL; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL; - } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); - return -1; - } - } else { - VNC_DEBUG("Initializing VNC server with SASL auth\n"); - vs->auth = VNC_AUTH_SASL; - vs->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vs->ws_auth = VNC_AUTH_SASL; - } else { - vs->ws_auth = VNC_AUTH_INVALID; - } - } else { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } - if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { - VNC_DEBUG("Initializing VNC server with x509 no auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS no auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; - } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); - return -1; - } - } else { - VNC_DEBUG("Initializing VNC server with no auth\n"); - vs->auth = VNC_AUTH_NONE; - vs->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vs->ws_auth = VNC_AUTH_NONE; - } else { - vs->ws_auth = VNC_AUTH_INVALID; - } - } - return 0; -} - - -/* - * Handle back compat with old CLI syntax by creating some - * suitable QCryptoTLSCreds objects - */ -static QCryptoTLSCreds * -vnc_display_create_creds(bool x509, - bool x509verify, - const char *dir, - const char *id, - Error **errp) -{ - gchar *credsid = g_strdup_printf("tlsvnc%s", id); - Object *parent = object_get_objects_root(); - Object *creds; - Error *err = NULL; - - if (x509) { - creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509, - parent, - credsid, - &err, - "endpoint", "server", - "dir", dir, - "verify-peer", x509verify ? "yes" : "no", - NULL); - } else { - creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON, - parent, - credsid, - &err, - "endpoint", "server", - NULL); - } - - g_free(credsid); - - if (err) { - error_propagate(errp, err); - return NULL; - } - - return QCRYPTO_TLS_CREDS(creds); -} - - -void vnc_display_open(const char *id, Error **errp) -{ - VncDisplay *vs = vnc_display_find(id); - QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); - SocketAddress *saddr = NULL, *wsaddr = NULL; - const char *share, *device_id; - QemuConsole *con; - bool password = false; - bool reverse = false; - const char *vnc; - char *h; - const char *credid; - bool sasl = false; -#ifdef CONFIG_VNC_SASL - int saslErr; -#endif - int acl = 0; - int lock_key_sync = 1; - - if (!vs) { - error_setg(errp, "VNC display not active"); - return; - } - vnc_display_close(vs); - - if (!opts) { - return; - } - vnc = qemu_opt_get(opts, "vnc"); - if (!vnc || strcmp(vnc, "none") == 0) { - return; - } - - h = strrchr(vnc, ':'); - if (h) { - size_t hlen = h - vnc; - - const char *websocket = qemu_opt_get(opts, "websocket"); - int to = qemu_opt_get_number(opts, "to", 0); - bool has_ipv4 = qemu_opt_get(opts, "ipv4"); - bool has_ipv6 = qemu_opt_get(opts, "ipv6"); - bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false); - bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false); - - saddr = g_new0(SocketAddress, 1); - if (websocket) { - if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { - error_setg(errp, - "SHA1 hash support is required for websockets"); - goto fail; - } - - wsaddr = g_new0(SocketAddress, 1); - vs->ws_enabled = true; - } - - if (strncmp(vnc, "unix:", 5) == 0) { - saddr->type = SOCKET_ADDRESS_KIND_UNIX; - saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1); - saddr->u.q_unix.data->path = g_strdup(vnc + 5); - - if (vs->ws_enabled) { - error_setg(errp, "UNIX sockets not supported with websock"); - goto fail; - } - } else { - unsigned long long baseport; - InetSocketAddress *inet; - saddr->type = SOCKET_ADDRESS_KIND_INET; - inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1); - if (vnc[0] == '[' && vnc[hlen - 1] == ']') { - inet->host = g_strndup(vnc + 1, hlen - 2); - } else { - inet->host = g_strndup(vnc, hlen); - } - if (parse_uint_full(h + 1, &baseport, 10) < 0) { - error_setg(errp, "can't convert to a number: %s", h + 1); - goto fail; - } - if (baseport > 65535 || - baseport + 5900 > 65535) { - error_setg(errp, "port %s out of range", h + 1); - goto fail; - } - inet->port = g_strdup_printf( - "%d", (int)baseport + 5900); - - if (to) { - inet->has_to = true; - inet->to = to + 5900; - } - inet->ipv4 = ipv4; - inet->has_ipv4 = has_ipv4; - inet->ipv6 = ipv6; - inet->has_ipv6 = has_ipv6; - - if (vs->ws_enabled) { - wsaddr->type = SOCKET_ADDRESS_KIND_INET; - inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1); - inet->host = g_strdup(saddr->u.inet.data->host); - inet->port = g_strdup(websocket); - - if (to) { - inet->has_to = true; - inet->to = to; - } - inet->ipv4 = ipv4; - inet->has_ipv4 = has_ipv4; - inet->ipv6 = ipv6; - inet->has_ipv6 = has_ipv6; - } - } - } else { - error_setg(errp, "no vnc port specified"); - goto fail; - } - - password = qemu_opt_get_bool(opts, "password", false); - if (password) { - if (fips_get_state()) { - error_setg(errp, - "VNC password auth disabled due to FIPS mode, " - "consider using the VeNCrypt or SASL authentication " - "methods as an alternative"); - goto fail; - } - if (!qcrypto_cipher_supports( - QCRYPTO_CIPHER_ALG_DES_RFB)) { - error_setg(errp, - "Cipher backend does not support DES RFB algorithm"); - goto fail; - } - } - - reverse = qemu_opt_get_bool(opts, "reverse", false); - lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); - sasl = qemu_opt_get_bool(opts, "sasl", false); -#ifndef CONFIG_VNC_SASL - if (sasl) { - error_setg(errp, "VNC SASL auth requires cyrus-sasl support"); - goto fail; - } -#endif /* CONFIG_VNC_SASL */ - credid = qemu_opt_get(opts, "tls-creds"); - if (credid) { - Object *creds; - if (qemu_opt_get(opts, "tls") || - qemu_opt_get(opts, "x509") || - qemu_opt_get(opts, "x509verify")) { - error_setg(errp, - "'tls-creds' parameter is mutually exclusive with " - "'tls', 'x509' and 'x509verify' parameters"); - goto fail; - } - - creds = object_resolve_path_component( - object_get_objects_root(), credid); - if (!creds) { - error_setg(errp, "No TLS credentials with id '%s'", - credid); - goto fail; - } - vs->tlscreds = (QCryptoTLSCreds *) - object_dynamic_cast(creds, - TYPE_QCRYPTO_TLS_CREDS); - if (!vs->tlscreds) { - error_setg(errp, "Object with id '%s' is not TLS credentials", - credid); - goto fail; - } - object_ref(OBJECT(vs->tlscreds)); - - if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { - error_setg(errp, - "Expecting TLS credentials with a server endpoint"); - goto fail; - } - } else { - const char *path; - bool tls = false, x509 = false, x509verify = false; - tls = qemu_opt_get_bool(opts, "tls", false); - if (tls) { - path = qemu_opt_get(opts, "x509"); - - if (path) { - x509 = true; - } else { - path = qemu_opt_get(opts, "x509verify"); - if (path) { - x509 = true; - x509verify = true; - } - } - vs->tlscreds = vnc_display_create_creds(x509, - x509verify, - path, - vs->id, - errp); - if (!vs->tlscreds) { - goto fail; - } - } - } - acl = qemu_opt_get_bool(opts, "acl", false); - - share = qemu_opt_get(opts, "share"); - if (share) { - if (strcmp(share, "ignore") == 0) { - vs->share_policy = VNC_SHARE_POLICY_IGNORE; - } else if (strcmp(share, "allow-exclusive") == 0) { - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; - } else if (strcmp(share, "force-shared") == 0) { - vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; - } else { - error_setg(errp, "unknown vnc share= option"); - goto fail; - } - } else { - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; - } - vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); - -#ifdef CONFIG_VNC_JPEG - vs->lossy = qemu_opt_get_bool(opts, "lossy", false); -#endif - vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false); - /* adaptive updates are only used with tight encoding and - * if lossy updates are enabled so we can disable all the - * calculations otherwise */ - if (!vs->lossy) { - vs->non_adaptive = true; - } - - if (acl) { - if (strcmp(vs->id, "default") == 0) { - vs->tlsaclname = g_strdup("vnc.x509dname"); - } else { - vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id); - } - qemu_acl_init(vs->tlsaclname); - } -#ifdef CONFIG_VNC_SASL - if (acl && sasl) { - char *aclname; - - if (strcmp(vs->id, "default") == 0) { - aclname = g_strdup("vnc.username"); - } else { - aclname = g_strdup_printf("vnc.%s.username", vs->id); - } - vs->sasl.acl = qemu_acl_init(aclname); - g_free(aclname); - } -#endif - - if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) { - goto fail; - } - -#ifdef CONFIG_VNC_SASL - if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { - error_setg(errp, "Failed to initialize SASL auth: %s", - sasl_errstring(saslErr, NULL, NULL)); - goto fail; - } -#endif - vs->lock_key_sync = lock_key_sync; - - device_id = qemu_opt_get(opts, "display"); - if (device_id) { - int head = qemu_opt_get_number(opts, "head", 0); - Error *err = NULL; - - con = qemu_console_lookup_by_device_name(device_id, head, &err); - if (err) { - error_propagate(errp, err); - goto fail; - } - } else { - con = NULL; - } - - if (con != vs->dcl.con) { - unregister_displaychangelistener(&vs->dcl); - vs->dcl.con = con; - register_displaychangelistener(&vs->dcl); - } - - if (reverse) { - /* connect to viewer */ - QIOChannelSocket *sioc = NULL; - vs->lsock = NULL; - vs->lwebsock = NULL; - if (vs->ws_enabled) { - error_setg(errp, "Cannot use websockets in reverse mode"); - goto fail; - } - vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; - sioc = qio_channel_socket_new(); - if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) { - goto fail; - } - vnc_connect(vs, sioc, false, false); - object_unref(OBJECT(sioc)); - } else { - vs->lsock = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) { - goto fail; - } - vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; - vs->enabled = true; - - if (vs->ws_enabled) { - vs->lwebsock = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(vs->lwebsock, - wsaddr, errp) < 0) { - object_unref(OBJECT(vs->lsock)); - vs->lsock = NULL; - goto fail; - } - } - - vs->lsock_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->lsock), - G_IO_IN, vnc_listen_io, vs, NULL); - if (vs->ws_enabled) { - vs->lwebsock_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->lwebsock), - G_IO_IN, vnc_listen_io, vs, NULL); - } - } - - qapi_free_SocketAddress(saddr); - qapi_free_SocketAddress(wsaddr); - return; - -fail: - qapi_free_SocketAddress(saddr); - qapi_free_SocketAddress(wsaddr); - vs->enabled = false; - vs->ws_enabled = false; -} - -void vnc_display_add_client(const char *id, int csock, bool skipauth) -{ - VncDisplay *vs = vnc_display_find(id); - QIOChannelSocket *sioc; - - if (!vs) { - return; - } - - sioc = qio_channel_socket_new_fd(csock, NULL); - if (sioc) { - vnc_connect(vs, sioc, skipauth, false); - object_unref(OBJECT(sioc)); - } -} - -static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts) -{ - int i = 2; - char *id; - - id = g_strdup("default"); - while (qemu_opts_find(olist, id)) { - g_free(id); - id = g_strdup_printf("vnc%d", i++); - } - qemu_opts_set_id(opts, id); -} - -QemuOpts *vnc_parse(const char *str, Error **errp) -{ - QemuOptsList *olist = qemu_find_opts("vnc"); - QemuOpts *opts = qemu_opts_parse(olist, str, true, errp); - const char *id; - - if (!opts) { - return NULL; - } - - id = qemu_opts_id(opts); - if (!id) { - /* auto-assign id if not present */ - vnc_auto_assign_id(olist, opts); - } - return opts; -} - -int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) -{ - Error *local_err = NULL; - char *id = (char *)qemu_opts_id(opts); - - assert(id); - vnc_display_init(id); - vnc_display_open(id, &local_err); - if (local_err != NULL) { - error_reportf_err(local_err, "Failed to start VNC server: "); - exit(1); - } - return 0; -} - -static void vnc_register_config(void) -{ - qemu_add_opts(&qemu_vnc_opts); -} -opts_init(vnc_register_config); diff --git a/qemu/ui/vnc.h b/qemu/ui/vnc.h deleted file mode 100644 index 81a326116..000000000 --- a/qemu/ui/vnc.h +++ /dev/null @@ -1,579 +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 "qemu/thread.h" -#include "ui/console.h" -#include "audio/audio.h" -#include "qemu/bitmap.h" -#include "crypto/tlssession.h" -#include "qemu/buffer.h" -#include "io/channel-socket.h" -#include "io/channel-tls.h" -#include <zlib.h> - -#include "keymaps.h" -#include "vnc-palette.h" -#include "vnc-enc-zrle.h" -#include "qapi-types.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 VncState VncState; -typedef struct VncJob VncJob; -typedef struct VncRect VncRect; -typedef struct VncRectEntry VncRectEntry; - -typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); - -typedef void VncWritePixels(VncState *vs, 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); - -/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented - * by one bit in the dirty bitmap, should be a power of 2 */ -#define VNC_DIRTY_PIXELS_PER_BIT 16 - -/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */ - -#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT) -#define VNC_MAX_HEIGHT 2048 - -/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */ -#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT) - -/* VNC_DIRTY_BPL (BPL = bits per line) might be greater than - * VNC_DIRTY_BITS due to alignment */ -#define VNC_DIRTY_BPL(x) (sizeof((x)->dirty) / VNC_MAX_HEIGHT * BITS_PER_BYTE) - -#define VNC_STAT_RECT 64 -#define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT) -#define VNC_STAT_ROWS (VNC_MAX_HEIGHT / VNC_STAT_RECT) - -#define VNC_AUTH_CHALLENGE_SIZE 16 - -typedef struct VncDisplay VncDisplay; - -#include "vnc-auth-vencrypt.h" -#ifdef CONFIG_VNC_SASL -#include "vnc-auth-sasl.h" -#endif -#include "vnc-ws.h" - -struct VncRectStat -{ - /* time of last 10 updates, to find update frequency */ - struct timeval times[10]; - int idx; - - double freq; /* Update frequency (in Hz) */ - bool updated; /* Already updated during this refresh */ -}; - -typedef struct VncRectStat VncRectStat; - -struct VncSurface -{ - struct timeval last_freq_check; - DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], - VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT); - VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS]; - pixman_image_t *fb; - pixman_format_code_t format; -}; - -typedef enum VncShareMode { - VNC_SHARE_MODE_CONNECTING = 1, - VNC_SHARE_MODE_SHARED, - VNC_SHARE_MODE_EXCLUSIVE, - VNC_SHARE_MODE_DISCONNECTED, -} VncShareMode; - -typedef enum VncSharePolicy { - VNC_SHARE_POLICY_IGNORE = 1, - VNC_SHARE_POLICY_ALLOW_EXCLUSIVE, - VNC_SHARE_POLICY_FORCE_SHARED, -} VncSharePolicy; - -struct VncDisplay -{ - QTAILQ_HEAD(, VncState) clients; - int num_connecting; - int num_shared; - int num_exclusive; - int connections_limit; - VncSharePolicy share_policy; - QIOChannelSocket *lsock; - guint lsock_tag; - QIOChannelSocket *lwebsock; - guint lwebsock_tag; - bool ws_enabled; - DisplaySurface *ds; - DisplayChangeListener dcl; - kbd_layout_t *kbd_layout; - int lock_key_sync; - QemuMutex mutex; - - QEMUCursor *cursor; - int cursor_msize; - uint8_t *cursor_mask; - - struct VncSurface guest; /* guest visible surface (aka ds->surface) */ - pixman_image_t *server; /* vnc server surface */ - - const char *id; - QTAILQ_ENTRY(VncDisplay) next; - bool enabled; - bool is_unix; - char *password; - time_t expires; - int auth; - int subauth; /* Used by VeNCrypt */ - int ws_auth; /* Used by websockets */ - bool ws_tls; /* Used by websockets */ - bool lossy; - bool non_adaptive; - QCryptoTLSCreds *tlscreds; - char *tlsaclname; -#ifdef CONFIG_VNC_SASL - VncDisplaySASL sasl; -#endif -}; - -typedef struct VncTight { - int type; - uint8_t quality; - uint8_t compression; - uint8_t pixel24; - Buffer tight; - Buffer tmp; - Buffer zlib; - Buffer gradient; -#ifdef CONFIG_VNC_JPEG - Buffer jpeg; -#endif -#ifdef CONFIG_VNC_PNG - Buffer png; -#endif - int levels[4]; - z_stream stream[4]; -} VncTight; - -typedef struct VncHextile { - VncSendHextileTile *send_tile; -} VncHextile; - -typedef struct VncZlib { - Buffer zlib; - Buffer tmp; - z_stream stream; - int level; -} VncZlib; - -typedef struct VncZrle { - int type; - Buffer fb; - Buffer zrle; - Buffer tmp; - Buffer zlib; - z_stream stream; - VncPalette palette; -} VncZrle; - -typedef struct VncZywrle { - int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT]; -} VncZywrle; - -struct VncRect -{ - int x; - int y; - int w; - int h; -}; - -struct VncRectEntry -{ - struct VncRect rect; - QLIST_ENTRY(VncRectEntry) next; -}; - -struct VncJob -{ - VncState *vs; - - QLIST_HEAD(, VncRectEntry) rectangles; - QTAILQ_ENTRY(VncJob) next; -}; - -struct VncState -{ - QIOChannelSocket *sioc; /* The underlying socket */ - QIOChannel *ioc; /* The channel currently used for I/O */ - guint ioc_tag; - gboolean disconnecting; - - DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS); - uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in - * vnc-jobs-async.c */ - - VncDisplay *vd; - int need_update; - int force_update; - int has_dirty; - uint32_t features; - int absolute; - int last_x; - int last_y; - uint32_t last_bmask; - int client_width; - int client_height; - VncShareMode share_mode; - - uint32_t vnc_encoding; - - int major; - int minor; - - int auth; - int subauth; /* Used by VeNCrypt */ - char challenge[VNC_AUTH_CHALLENGE_SIZE]; - QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */ -#ifdef CONFIG_VNC_SASL - VncStateSASL sasl; -#endif - bool encode_ws; - bool websocket; - - VncClientInfo *info; - - Buffer output; - Buffer input; - /* current output mode information */ - VncWritePixels *write_pixels; - PixelFormat client_pf; - pixman_format_code_t client_format; - bool client_be; - - CaptureVoiceOut *audio_cap; - struct audsettings as; - - VncReadEvent *read_handler; - size_t read_handler_expect; - /* input */ - uint8_t modifiers_state[256]; - QEMUPutLEDEntry *led; - - bool abort; - bool initialized; - QemuMutex output_mutex; - QEMUBH *bh; - Buffer jobs_buffer; - - /* Encoding specific, if you add something here, don't forget to - * update vnc_async_encoding_start() - */ - VncTight tight; - VncZlib zlib; - VncHextile hextile; - VncZrle zrle; - VncZywrle zywrle; - - 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_TIGHT_PNG 0xFFFFFEFC /* -260 */ -#define VNC_ENCODING_LED_STATE 0XFFFFFEFB /* -261 */ -#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_TYPE_PNG (0x0A << 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_TIGHT_PNG 8 -#define VNC_FEATURE_ZRLE 9 -#define VNC_FEATURE_ZYWRLE 10 -#define VNC_FEATURE_LED_STATE 11 - -#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) -#define VNC_FEATURE_TIGHT_PNG_MASK (1 << VNC_FEATURE_TIGHT_PNG) -#define VNC_FEATURE_ZRLE_MASK (1 << VNC_FEATURE_ZRLE) -#define VNC_FEATURE_ZYWRLE_MASK (1 << VNC_FEATURE_ZYWRLE) -#define VNC_FEATURE_LED_STATE_MASK (1 << VNC_FEATURE_LED_STATE) - - -/* 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 */ -gboolean vnc_client_io(QIOChannel *ioc, - GIOCondition condition, - void *opaque); - -ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen); -ssize_t 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); -void vnc_disconnect_finish(VncState *vs); -void vnc_init_state(VncState *vs); - - -/* Buffer I/O functions */ -uint32_t read_u32(uint8_t *data, size_t offset); - -/* Protocol stage functions */ -void vnc_client_error(VncState *vs); -ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp); - -void start_client_init(VncState *vs); -void start_auth_vnc(VncState *vs); - - -/* Misc helpers */ - -static inline uint32_t vnc_has_feature(VncState *vs, int feature) { - return (vs->features & (1 << feature)); -} - -/* Framebuffer */ -void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, - int32_t encoding); - -/* server fb is in PIXMAN_x8r8g8b8 */ -#define VNC_SERVER_FB_FORMAT PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8) -#define VNC_SERVER_FB_BITS (PIXMAN_FORMAT_BPP(VNC_SERVER_FB_FORMAT)) -#define VNC_SERVER_FB_BYTES ((VNC_SERVER_FB_BITS+7)/8) - -void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y); -int vnc_server_fb_stride(VncDisplay *vd); - -void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v); -double vnc_update_freq(VncState *vs, int x, int y, int w, int h); -void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h); - -/* Encodings */ -int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); - -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); -int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h); -void vnc_tight_clear(VncState *vs); - -int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); -int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); -void vnc_zrle_clear(VncState *vs); - -#endif /* __QEMU_VNC_H */ diff --git a/qemu/ui/vnc_keysym.h b/qemu/ui/vnc_keysym.h deleted file mode 100644 index 7fa2bc1f1..000000000 --- a/qemu/ui/vnc_keysym.h +++ /dev/null @@ -1,720 +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 */ - -/* latin 2 - Polish national characters */ -{ "eogonek", 0x1ea}, -{ "Eogonek", 0x1ca}, -{ "aogonek", 0x1b1}, -{ "Aogonek", 0x1a1}, -{ "sacute", 0x1b6}, -{ "Sacute", 0x1a6}, -{ "lstroke", 0x1b3}, -{ "Lstroke", 0x1a3}, -{ "zabovedot", 0x1bf}, -{ "Zabovedot", 0x1af}, -{ "zacute", 0x1bc}, -{ "Zacute", 0x1ac}, -{ "Odoubleacute", 0x1d5}, -{ "Udoubleacute", 0x1db}, -{ "cacute", 0x1e6}, -{ "Cacute", 0x1c6}, -{ "nacute", 0x1f1}, -{ "Nacute", 0x1d1}, -{ "odoubleacute", 0x1f5}, -{ "udoubleacute", 0x1fb}, - -/* Czech national characters */ -{ "ecaron", 0x1ec}, -{ "scaron", 0x1b9}, -{ "ccaron", 0x1e8}, -{ "rcaron", 0x1f8}, -{ "zcaron", 0x1be}, -{ "uring", 0x1f9}, - - /* 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}, - -{"abovedot", 0x01ff}, /* U+02D9 DOT ABOVE */ -{"amacron", 0x03e0}, /* U+0101 LATIN SMALL LETTER A WITH MACRON */ -{"Amacron", 0x03c0}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */ -{"Arabic_ain", 0x05d9}, /* U+0639 ARABIC LETTER AIN */ -{"Arabic_alef", 0x05c7}, /* U+0627 ARABIC LETTER ALEF */ -{"Arabic_alefmaksura", 0x05e9}, /* U+0649 ARABIC LETTER ALEF MAKSURA */ -{"Arabic_beh", 0x05c8}, /* U+0628 ARABIC LETTER BEH */ -{"Arabic_comma", 0x05ac}, /* U+060C ARABIC COMMA */ -{"Arabic_dad", 0x05d6}, /* U+0636 ARABIC LETTER DAD */ -{"Arabic_dal", 0x05cf}, /* U+062F ARABIC LETTER DAL */ -{"Arabic_damma", 0x05ef}, /* U+064F ARABIC DAMMA */ -{"Arabic_dammatan", 0x05ec}, /* U+064C ARABIC DAMMATAN */ -{"Arabic_fatha", 0x05ee}, /* U+064E ARABIC FATHA */ -{"Arabic_fathatan", 0x05eb}, /* U+064B ARABIC FATHATAN */ -{"Arabic_feh", 0x05e1}, /* U+0641 ARABIC LETTER FEH */ -{"Arabic_ghain", 0x05da}, /* U+063A ARABIC LETTER GHAIN */ -{"Arabic_ha", 0x05e7}, /* U+0647 ARABIC LETTER HEH */ -{"Arabic_hah", 0x05cd}, /* U+062D ARABIC LETTER HAH */ -{"Arabic_hamza", 0x05c1}, /* U+0621 ARABIC LETTER HAMZA */ -{"Arabic_hamzaonalef", 0x05c3}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */ -{"Arabic_hamzaonwaw", 0x05c4}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */ -{"Arabic_hamzaonyeh", 0x05c6}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */ -{"Arabic_hamzaunderalef", 0x05c5}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */ -{"Arabic_jeem", 0x05cc}, /* U+062C ARABIC LETTER JEEM */ -{"Arabic_kaf", 0x05e3}, /* U+0643 ARABIC LETTER KAF */ -{"Arabic_kasra", 0x05f0}, /* U+0650 ARABIC KASRA */ -{"Arabic_kasratan", 0x05ed}, /* U+064D ARABIC KASRATAN */ -{"Arabic_khah", 0x05ce}, /* U+062E ARABIC LETTER KHAH */ -{"Arabic_lam", 0x05e4}, /* U+0644 ARABIC LETTER LAM */ -{"Arabic_maddaonalef", 0x05c2}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */ -{"Arabic_meem", 0x05e5}, /* U+0645 ARABIC LETTER MEEM */ -{"Arabic_noon", 0x05e6}, /* U+0646 ARABIC LETTER NOON */ -{"Arabic_qaf", 0x05e2}, /* U+0642 ARABIC LETTER QAF */ -{"Arabic_question_mark", 0x05bf}, /* U+061F ARABIC QUESTION MARK */ -{"Arabic_ra", 0x05d1}, /* U+0631 ARABIC LETTER REH */ -{"Arabic_sad", 0x05d5}, /* U+0635 ARABIC LETTER SAD */ -{"Arabic_seen", 0x05d3}, /* U+0633 ARABIC LETTER SEEN */ -{"Arabic_semicolon", 0x05bb}, /* U+061B ARABIC SEMICOLON */ -{"Arabic_shadda", 0x05f1}, /* U+0651 ARABIC SHADDA */ -{"Arabic_sheen", 0x05d4}, /* U+0634 ARABIC LETTER SHEEN */ -{"Arabic_sukun", 0x05f2}, /* U+0652 ARABIC SUKUN */ -{"Arabic_tah", 0x05d7}, /* U+0637 ARABIC LETTER TAH */ -{"Arabic_tatweel", 0x05e0}, /* U+0640 ARABIC TATWEEL */ -{"Arabic_teh", 0x05ca}, /* U+062A ARABIC LETTER TEH */ -{"Arabic_tehmarbuta", 0x05c9}, /* U+0629 ARABIC LETTER TEH MARBUTA */ -{"Arabic_thal", 0x05d0}, /* U+0630 ARABIC LETTER THAL */ -{"Arabic_theh", 0x05cb}, /* U+062B ARABIC LETTER THEH */ -{"Arabic_waw", 0x05e8}, /* U+0648 ARABIC LETTER WAW */ -{"Arabic_yeh", 0x05ea}, /* U+064A ARABIC LETTER YEH */ -{"Arabic_zah", 0x05d8}, /* U+0638 ARABIC LETTER ZAH */ -{"Arabic_zain", 0x05d2}, /* U+0632 ARABIC LETTER ZAIN */ -{"breve", 0x01a2}, /* U+02D8 BREVE */ -{"caron", 0x01b7}, /* U+02C7 CARON */ -{"Ccaron", 0x01c8}, /* U+010C LATIN CAPITAL LETTER C WITH CARON */ -{"numerosign", 0x06b0}, /* U+2116 NUMERO SIGN */ -{"Cyrillic_a", 0x06c1}, /* U+0430 CYRILLIC SMALL LETTER A */ -{"Cyrillic_A", 0x06e1}, /* U+0410 CYRILLIC CAPITAL LETTER A */ -{"Cyrillic_be", 0x06c2}, /* U+0431 CYRILLIC SMALL LETTER BE */ -{"Cyrillic_BE", 0x06e2}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ -{"Cyrillic_che", 0x06de}, /* U+0447 CYRILLIC SMALL LETTER CHE */ -{"Cyrillic_CHE", 0x06fe}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ -{"Cyrillic_de", 0x06c4}, /* U+0434 CYRILLIC SMALL LETTER DE */ -{"Cyrillic_DE", 0x06e4}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ -{"Cyrillic_dzhe", 0x06af}, /* U+045F CYRILLIC SMALL LETTER DZHE */ -{"Cyrillic_DZHE", 0x06bf}, /* U+040F CYRILLIC CAPITAL LETTER DZHE */ -{"Cyrillic_e", 0x06dc}, /* U+044D CYRILLIC SMALL LETTER E */ -{"Cyrillic_E", 0x06fc}, /* U+042D CYRILLIC CAPITAL LETTER E */ -{"Cyrillic_ef", 0x06c6}, /* U+0444 CYRILLIC SMALL LETTER EF */ -{"Cyrillic_EF", 0x06e6}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ -{"Cyrillic_el", 0x06cc}, /* U+043B CYRILLIC SMALL LETTER EL */ -{"Cyrillic_EL", 0x06ec}, /* U+041B CYRILLIC CAPITAL LETTER EL */ -{"Cyrillic_em", 0x06cd}, /* U+043C CYRILLIC SMALL LETTER EM */ -{"Cyrillic_EM", 0x06ed}, /* U+041C CYRILLIC CAPITAL LETTER EM */ -{"Cyrillic_en", 0x06ce}, /* U+043D CYRILLIC SMALL LETTER EN */ -{"Cyrillic_EN", 0x06ee}, /* U+041D CYRILLIC CAPITAL LETTER EN */ -{"Cyrillic_er", 0x06d2}, /* U+0440 CYRILLIC SMALL LETTER ER */ -{"Cyrillic_ER", 0x06f2}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ -{"Cyrillic_es", 0x06d3}, /* U+0441 CYRILLIC SMALL LETTER ES */ -{"Cyrillic_ES", 0x06f3}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ -{"Cyrillic_ghe", 0x06c7}, /* U+0433 CYRILLIC SMALL LETTER GHE */ -{"Cyrillic_GHE", 0x06e7}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ -{"Cyrillic_ha", 0x06c8}, /* U+0445 CYRILLIC SMALL LETTER HA */ -{"Cyrillic_HA", 0x06e8}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ -{"Cyrillic_hardsign", 0x06df}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ -{"Cyrillic_HARDSIGN", 0x06ff}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ -{"Cyrillic_i", 0x06c9}, /* U+0438 CYRILLIC SMALL LETTER I */ -{"Cyrillic_I", 0x06e9}, /* U+0418 CYRILLIC CAPITAL LETTER I */ -{"Cyrillic_ie", 0x06c5}, /* U+0435 CYRILLIC SMALL LETTER IE */ -{"Cyrillic_IE", 0x06e5}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ -{"Cyrillic_io", 0x06a3}, /* U+0451 CYRILLIC SMALL LETTER IO */ -{"Cyrillic_IO", 0x06b3}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ -{"Cyrillic_je", 0x06a8}, /* U+0458 CYRILLIC SMALL LETTER JE */ -{"Cyrillic_JE", 0x06b8}, /* U+0408 CYRILLIC CAPITAL LETTER JE */ -{"Cyrillic_ka", 0x06cb}, /* U+043A CYRILLIC SMALL LETTER KA */ -{"Cyrillic_KA", 0x06eb}, /* U+041A CYRILLIC CAPITAL LETTER KA */ -{"Cyrillic_lje", 0x06a9}, /* U+0459 CYRILLIC SMALL LETTER LJE */ -{"Cyrillic_LJE", 0x06b9}, /* U+0409 CYRILLIC CAPITAL LETTER LJE */ -{"Cyrillic_nje", 0x06aa}, /* U+045A CYRILLIC SMALL LETTER NJE */ -{"Cyrillic_NJE", 0x06ba}, /* U+040A CYRILLIC CAPITAL LETTER NJE */ -{"Cyrillic_o", 0x06cf}, /* U+043E CYRILLIC SMALL LETTER O */ -{"Cyrillic_O", 0x06ef}, /* U+041E CYRILLIC CAPITAL LETTER O */ -{"Cyrillic_pe", 0x06d0}, /* U+043F CYRILLIC SMALL LETTER PE */ -{"Cyrillic_PE", 0x06f0}, /* U+041F CYRILLIC CAPITAL LETTER PE */ -{"Cyrillic_sha", 0x06db}, /* U+0448 CYRILLIC SMALL LETTER SHA */ -{"Cyrillic_SHA", 0x06fb}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ -{"Cyrillic_shcha", 0x06dd}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ -{"Cyrillic_SHCHA", 0x06fd}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ -{"Cyrillic_shorti", 0x06ca}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ -{"Cyrillic_SHORTI", 0x06ea}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ -{"Cyrillic_softsign", 0x06d8}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ -{"Cyrillic_SOFTSIGN", 0x06f8}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ -{"Cyrillic_te", 0x06d4}, /* U+0442 CYRILLIC SMALL LETTER TE */ -{"Cyrillic_TE", 0x06f4}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ -{"Cyrillic_tse", 0x06c3}, /* U+0446 CYRILLIC SMALL LETTER TSE */ -{"Cyrillic_TSE", 0x06e3}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ -{"Cyrillic_u", 0x06d5}, /* U+0443 CYRILLIC SMALL LETTER U */ -{"Cyrillic_U", 0x06f5}, /* U+0423 CYRILLIC CAPITAL LETTER U */ -{"Cyrillic_ve", 0x06d7}, /* U+0432 CYRILLIC SMALL LETTER VE */ -{"Cyrillic_VE", 0x06f7}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ -{"Cyrillic_ya", 0x06d1}, /* U+044F CYRILLIC SMALL LETTER YA */ -{"Cyrillic_YA", 0x06f1}, /* U+042F CYRILLIC CAPITAL LETTER YA */ -{"Cyrillic_yeru", 0x06d9}, /* U+044B CYRILLIC SMALL LETTER YERU */ -{"Cyrillic_YERU", 0x06f9}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ -{"Cyrillic_yu", 0x06c0}, /* U+044E CYRILLIC SMALL LETTER YU */ -{"Cyrillic_YU", 0x06e0}, /* U+042E CYRILLIC CAPITAL LETTER YU */ -{"Cyrillic_ze", 0x06da}, /* U+0437 CYRILLIC SMALL LETTER ZE */ -{"Cyrillic_ZE", 0x06fa}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ -{"Cyrillic_zhe", 0x06d6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ -{"Cyrillic_ZHE", 0x06f6}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ -{"doubleacute", 0x01bd}, /* U+02DD DOUBLE ACUTE ACCENT */ -{"doublelowquotemark", 0x0afe}, /* U+201E DOUBLE LOW-9 QUOTATION MARK */ -{"downarrow", 0x08fe}, /* U+2193 DOWNWARDS ARROW */ -{"dstroke", 0x01f0}, /* U+0111 LATIN SMALL LETTER D WITH STROKE */ -{"Dstroke", 0x01d0}, /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */ -{"eabovedot", 0x03ec}, /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */ -{"Eabovedot", 0x03cc}, /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */ -{"emacron", 0x03ba}, /* U+0113 LATIN SMALL LETTER E WITH MACRON */ -{"Emacron", 0x03aa}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */ -{"endash", 0x0aaa}, /* U+2013 EN DASH */ -{"eng", 0x03bf}, /* U+014B LATIN SMALL LETTER ENG */ -{"ENG", 0x03bd}, /* U+014A LATIN CAPITAL LETTER ENG */ -{"Execute", 0xff62}, /* Execute, run, do */ -{"F16", 0xffcd}, -{"F17", 0xffce}, -{"F18", 0xffcf}, -{"F19", 0xffd0}, -{"F20", 0xffd1}, -{"F21", 0xffd2}, -{"F22", 0xffd3}, -{"F23", 0xffd4}, -{"F24", 0xffd5}, -{"F25", 0xffd6}, -{"F26", 0xffd7}, -{"F27", 0xffd8}, -{"F28", 0xffd9}, -{"F29", 0xffda}, -{"F30", 0xffdb}, -{"F31", 0xffdc}, -{"F32", 0xffdd}, -{"F33", 0xffde}, -{"F34", 0xffdf}, -{"F35", 0xffe0}, -{"fiveeighths", 0x0ac5}, /* U+215D VULGAR FRACTION FIVE EIGHTHS */ -{"gbreve", 0x02bb}, /* U+011F LATIN SMALL LETTER G WITH BREVE */ -{"Gbreve", 0x02ab}, /* U+011E LATIN CAPITAL LETTER G WITH BREVE */ -{"gcedilla", 0x03bb}, /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */ -{"Gcedilla", 0x03ab}, /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */ -{"Greek_OMEGA", 0x07d9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ -{"Henkan_Mode", 0xff23}, /* Start/Stop Conversion */ -{"horizconnector", 0x08a3}, /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/ -{"hstroke", 0x02b1}, /* U+0127 LATIN SMALL LETTER H WITH STROKE */ -{"Hstroke", 0x02a1}, /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */ -{"Iabovedot", 0x02a9}, /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */ -{"idotless", 0x02b9}, /* U+0131 LATIN SMALL LETTER DOTLESS I */ -{"imacron", 0x03ef}, /* U+012B LATIN SMALL LETTER I WITH MACRON */ -{"Imacron", 0x03cf}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON */ -{"iogonek", 0x03e7}, /* U+012F LATIN SMALL LETTER I WITH OGONEK */ -{"Iogonek", 0x03c7}, /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */ -{"ISO_First_Group", 0xfe0c}, -{"ISO_Last_Group", 0xfe0e}, -{"ISO_Next_Group", 0xfe08}, -{"kana_a", 0x04a7}, /* U+30A1 KATAKANA LETTER SMALL A */ -{"kana_A", 0x04b1}, /* U+30A2 KATAKANA LETTER A */ -{"kana_CHI", 0x04c1}, /* U+30C1 KATAKANA LETTER TI */ -{"kana_closingbracket", 0x04a3}, /* U+300D RIGHT CORNER BRACKET */ -{"kana_comma", 0x04a4}, /* U+3001 IDEOGRAPHIC COMMA */ -{"kana_conjunctive", 0x04a5}, /* U+30FB KATAKANA MIDDLE DOT */ -{"kana_e", 0x04aa}, /* U+30A7 KATAKANA LETTER SMALL E */ -{"kana_E", 0x04b4}, /* U+30A8 KATAKANA LETTER E */ -{"kana_FU", 0x04cc}, /* U+30D5 KATAKANA LETTER HU */ -{"kana_fullstop", 0x04a1}, /* U+3002 IDEOGRAPHIC FULL STOP */ -{"kana_HA", 0x04ca}, /* U+30CF KATAKANA LETTER HA */ -{"kana_HE", 0x04cd}, /* U+30D8 KATAKANA LETTER HE */ -{"kana_HI", 0x04cb}, /* U+30D2 KATAKANA LETTER HI */ -{"kana_HO", 0x04ce}, /* U+30DB KATAKANA LETTER HO */ -{"kana_i", 0x04a8}, /* U+30A3 KATAKANA LETTER SMALL I */ -{"kana_I", 0x04b2}, /* U+30A4 KATAKANA LETTER I */ -{"kana_KA", 0x04b6}, /* U+30AB KATAKANA LETTER KA */ -{"kana_KE", 0x04b9}, /* U+30B1 KATAKANA LETTER KE */ -{"kana_KI", 0x04b7}, /* U+30AD KATAKANA LETTER KI */ -{"kana_KO", 0x04ba}, /* U+30B3 KATAKANA LETTER KO */ -{"kana_KU", 0x04b8}, /* U+30AF KATAKANA LETTER KU */ -{"kana_MA", 0x04cf}, /* U+30DE KATAKANA LETTER MA */ -{"kana_ME", 0x04d2}, /* U+30E1 KATAKANA LETTER ME */ -{"kana_MI", 0x04d0}, /* U+30DF KATAKANA LETTER MI */ -{"kana_MO", 0x04d3}, /* U+30E2 KATAKANA LETTER MO */ -{"kana_MU", 0x04d1}, /* U+30E0 KATAKANA LETTER MU */ -{"kana_N", 0x04dd}, /* U+30F3 KATAKANA LETTER N */ -{"kana_NA", 0x04c5}, /* U+30CA KATAKANA LETTER NA */ -{"kana_NE", 0x04c8}, /* U+30CD KATAKANA LETTER NE */ -{"kana_NI", 0x04c6}, /* U+30CB KATAKANA LETTER NI */ -{"kana_NO", 0x04c9}, /* U+30CE KATAKANA LETTER NO */ -{"kana_NU", 0x04c7}, /* U+30CC KATAKANA LETTER NU */ -{"kana_o", 0x04ab}, /* U+30A9 KATAKANA LETTER SMALL O */ -{"kana_O", 0x04b5}, /* U+30AA KATAKANA LETTER O */ -{"kana_openingbracket", 0x04a2}, /* U+300C LEFT CORNER BRACKET */ -{"kana_RA", 0x04d7}, /* U+30E9 KATAKANA LETTER RA */ -{"kana_RE", 0x04da}, /* U+30EC KATAKANA LETTER RE */ -{"kana_RI", 0x04d8}, /* U+30EA KATAKANA LETTER RI */ -{"kana_RU", 0x04d9}, /* U+30EB KATAKANA LETTER RU */ -{"kana_SA", 0x04bb}, /* U+30B5 KATAKANA LETTER SA */ -{"kana_SE", 0x04be}, /* U+30BB KATAKANA LETTER SE */ -{"kana_SHI", 0x04bc}, /* U+30B7 KATAKANA LETTER SI */ -{"kana_SO", 0x04bf}, /* U+30BD KATAKANA LETTER SO */ -{"kana_SU", 0x04bd}, /* U+30B9 KATAKANA LETTER SU */ -{"kana_TA", 0x04c0}, /* U+30BF KATAKANA LETTER TA */ -{"kana_TE", 0x04c3}, /* U+30C6 KATAKANA LETTER TE */ -{"kana_TO", 0x04c4}, /* U+30C8 KATAKANA LETTER TO */ -{"kana_tsu", 0x04af}, /* U+30C3 KATAKANA LETTER SMALL TU */ -{"kana_TSU", 0x04c2}, /* U+30C4 KATAKANA LETTER TU */ -{"kana_u", 0x04a9}, /* U+30A5 KATAKANA LETTER SMALL U */ -{"kana_U", 0x04b3}, /* U+30A6 KATAKANA LETTER U */ -{"kana_WA", 0x04dc}, /* U+30EF KATAKANA LETTER WA */ -{"kana_WO", 0x04a6}, /* U+30F2 KATAKANA LETTER WO */ -{"kana_ya", 0x04ac}, /* U+30E3 KATAKANA LETTER SMALL YA */ -{"kana_YA", 0x04d4}, /* U+30E4 KATAKANA LETTER YA */ -{"kana_yo", 0x04ae}, /* U+30E7 KATAKANA LETTER SMALL YO */ -{"kana_YO", 0x04d6}, /* U+30E8 KATAKANA LETTER YO */ -{"kana_yu", 0x04ad}, /* U+30E5 KATAKANA LETTER SMALL YU */ -{"kana_YU", 0x04d5}, /* U+30E6 KATAKANA LETTER YU */ -{"Kanji", 0xff21}, /* Kanji, Kanji convert */ -{"kcedilla", 0x03f3}, /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */ -{"Kcedilla", 0x03d3}, /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */ -{"kra", 0x03a2}, /* U+0138 LATIN SMALL LETTER KRA */ -{"lcedilla", 0x03b6}, /* U+013C LATIN SMALL LETTER L WITH CEDILLA */ -{"Lcedilla", 0x03a6}, /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */ -{"leftarrow", 0x08fb}, /* U+2190 LEFTWARDS ARROW */ -{"leftdoublequotemark", 0x0ad2}, /* U+201C LEFT DOUBLE QUOTATION MARK */ -{"Macedonia_dse", 0x06a5}, /* U+0455 CYRILLIC SMALL LETTER DZE */ -{"Macedonia_DSE", 0x06b5}, /* U+0405 CYRILLIC CAPITAL LETTER DZE */ -{"Macedonia_gje", 0x06a2}, /* U+0453 CYRILLIC SMALL LETTER GJE */ -{"Macedonia_GJE", 0x06b2}, /* U+0403 CYRILLIC CAPITAL LETTER GJE */ -{"Macedonia_kje", 0x06ac}, /* U+045C CYRILLIC SMALL LETTER KJE */ -{"Macedonia_KJE", 0x06bc}, /* U+040C CYRILLIC CAPITAL LETTER KJE */ -{"ncedilla", 0x03f1}, /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */ -{"Ncedilla", 0x03d1}, /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */ -{"oe", 0x13bd}, /* U+0153 LATIN SMALL LIGATURE OE */ -{"OE", 0x13bc}, /* U+0152 LATIN CAPITAL LIGATURE OE */ -{"ogonek", 0x01b2}, /* U+02DB OGONEK */ -{"omacron", 0x03f2}, /* U+014D LATIN SMALL LETTER O WITH MACRON */ -{"Omacron", 0x03d2}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON */ -{"oneeighth", 0x0ac3}, /* U+215B VULGAR FRACTION ONE EIGHTH */ -{"rcedilla", 0x03b3}, /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */ -{"Rcedilla", 0x03a3}, /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */ -{"rightarrow", 0x08fd}, /* U+2192 RIGHTWARDS ARROW */ -{"rightdoublequotemark", 0x0ad3}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ -{"Scaron", 0x01a9}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON */ -{"scedilla", 0x01ba}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA */ -{"Scedilla", 0x01aa}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */ -{"semivoicedsound", 0x04df}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ -{"seveneighths", 0x0ac6}, /* U+215E VULGAR FRACTION SEVEN EIGHTHS */ -{"Thai_baht", 0x0ddf}, /* U+0E3F THAI CURRENCY SYMBOL BAHT */ -{"Thai_bobaimai", 0x0dba}, /* U+0E1A THAI CHARACTER BO BAIMAI */ -{"Thai_chochan", 0x0da8}, /* U+0E08 THAI CHARACTER CHO CHAN */ -{"Thai_chochang", 0x0daa}, /* U+0E0A THAI CHARACTER CHO CHANG */ -{"Thai_choching", 0x0da9}, /* U+0E09 THAI CHARACTER CHO CHING */ -{"Thai_chochoe", 0x0dac}, /* U+0E0C THAI CHARACTER CHO CHOE */ -{"Thai_dochada", 0x0dae}, /* U+0E0E THAI CHARACTER DO CHADA */ -{"Thai_dodek", 0x0db4}, /* U+0E14 THAI CHARACTER DO DEK */ -{"Thai_fofa", 0x0dbd}, /* U+0E1D THAI CHARACTER FO FA */ -{"Thai_fofan", 0x0dbf}, /* U+0E1F THAI CHARACTER FO FAN */ -{"Thai_hohip", 0x0dcb}, /* U+0E2B THAI CHARACTER HO HIP */ -{"Thai_honokhuk", 0x0dce}, /* U+0E2E THAI CHARACTER HO NOKHUK */ -{"Thai_khokhai", 0x0da2}, /* U+0E02 THAI CHARACTER KHO KHAI */ -{"Thai_khokhon", 0x0da5}, /* U+0E05 THAI CHARACTER KHO KHON */ -{"Thai_khokhuat", 0x0da3}, /* U+0E03 THAI CHARACTER KHO KHUAT */ -{"Thai_khokhwai", 0x0da4}, /* U+0E04 THAI CHARACTER KHO KHWAI */ -{"Thai_khorakhang", 0x0da6}, /* U+0E06 THAI CHARACTER KHO RAKHANG */ -{"Thai_kokai", 0x0da1}, /* U+0E01 THAI CHARACTER KO KAI */ -{"Thai_lakkhangyao", 0x0de5}, /* U+0E45 THAI CHARACTER LAKKHANGYAO */ -{"Thai_lekchet", 0x0df7}, /* U+0E57 THAI DIGIT SEVEN */ -{"Thai_lekha", 0x0df5}, /* U+0E55 THAI DIGIT FIVE */ -{"Thai_lekhok", 0x0df6}, /* U+0E56 THAI DIGIT SIX */ -{"Thai_lekkao", 0x0df9}, /* U+0E59 THAI DIGIT NINE */ -{"Thai_leknung", 0x0df1}, /* U+0E51 THAI DIGIT ONE */ -{"Thai_lekpaet", 0x0df8}, /* U+0E58 THAI DIGIT EIGHT */ -{"Thai_leksam", 0x0df3}, /* U+0E53 THAI DIGIT THREE */ -{"Thai_leksi", 0x0df4}, /* U+0E54 THAI DIGIT FOUR */ -{"Thai_leksong", 0x0df2}, /* U+0E52 THAI DIGIT TWO */ -{"Thai_leksun", 0x0df0}, /* U+0E50 THAI DIGIT ZERO */ -{"Thai_lochula", 0x0dcc}, /* U+0E2C THAI CHARACTER LO CHULA */ -{"Thai_loling", 0x0dc5}, /* U+0E25 THAI CHARACTER LO LING */ -{"Thai_lu", 0x0dc6}, /* U+0E26 THAI CHARACTER LU */ -{"Thai_maichattawa", 0x0deb}, /* U+0E4B THAI CHARACTER MAI CHATTAWA */ -{"Thai_maiek", 0x0de8}, /* U+0E48 THAI CHARACTER MAI EK */ -{"Thai_maihanakat", 0x0dd1}, /* U+0E31 THAI CHARACTER MAI HAN-AKAT */ -{"Thai_maitaikhu", 0x0de7}, /* U+0E47 THAI CHARACTER MAITAIKHU */ -{"Thai_maitho", 0x0de9}, /* U+0E49 THAI CHARACTER MAI THO */ -{"Thai_maitri", 0x0dea}, /* U+0E4A THAI CHARACTER MAI TRI */ -{"Thai_maiyamok", 0x0de6}, /* U+0E46 THAI CHARACTER MAIYAMOK */ -{"Thai_moma", 0x0dc1}, /* U+0E21 THAI CHARACTER MO MA */ -{"Thai_ngongu", 0x0da7}, /* U+0E07 THAI CHARACTER NGO NGU */ -{"Thai_nikhahit", 0x0ded}, /* U+0E4D THAI CHARACTER NIKHAHIT */ -{"Thai_nonen", 0x0db3}, /* U+0E13 THAI CHARACTER NO NEN */ -{"Thai_nonu", 0x0db9}, /* U+0E19 THAI CHARACTER NO NU */ -{"Thai_oang", 0x0dcd}, /* U+0E2D THAI CHARACTER O ANG */ -{"Thai_paiyannoi", 0x0dcf}, /* U+0E2F THAI CHARACTER PAIYANNOI */ -{"Thai_phinthu", 0x0dda}, /* U+0E3A THAI CHARACTER PHINTHU */ -{"Thai_phophan", 0x0dbe}, /* U+0E1E THAI CHARACTER PHO PHAN */ -{"Thai_phophung", 0x0dbc}, /* U+0E1C THAI CHARACTER PHO PHUNG */ -{"Thai_phosamphao", 0x0dc0}, /* U+0E20 THAI CHARACTER PHO SAMPHAO */ -{"Thai_popla", 0x0dbb}, /* U+0E1B THAI CHARACTER PO PLA */ -{"Thai_rorua", 0x0dc3}, /* U+0E23 THAI CHARACTER RO RUA */ -{"Thai_ru", 0x0dc4}, /* U+0E24 THAI CHARACTER RU */ -{"Thai_saraa", 0x0dd0}, /* U+0E30 THAI CHARACTER SARA A */ -{"Thai_saraaa", 0x0dd2}, /* U+0E32 THAI CHARACTER SARA AA */ -{"Thai_saraae", 0x0de1}, /* U+0E41 THAI CHARACTER SARA AE */ -{"Thai_saraaimaimalai", 0x0de4}, /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */ -{"Thai_saraaimaimuan", 0x0de3}, /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */ -{"Thai_saraam", 0x0dd3}, /* U+0E33 THAI CHARACTER SARA AM */ -{"Thai_sarae", 0x0de0}, /* U+0E40 THAI CHARACTER SARA E */ -{"Thai_sarai", 0x0dd4}, /* U+0E34 THAI CHARACTER SARA I */ -{"Thai_saraii", 0x0dd5}, /* U+0E35 THAI CHARACTER SARA II */ -{"Thai_sarao", 0x0de2}, /* U+0E42 THAI CHARACTER SARA O */ -{"Thai_sarau", 0x0dd8}, /* U+0E38 THAI CHARACTER SARA U */ -{"Thai_saraue", 0x0dd6}, /* U+0E36 THAI CHARACTER SARA UE */ -{"Thai_sarauee", 0x0dd7}, /* U+0E37 THAI CHARACTER SARA UEE */ -{"Thai_sarauu", 0x0dd9}, /* U+0E39 THAI CHARACTER SARA UU */ -{"Thai_sorusi", 0x0dc9}, /* U+0E29 THAI CHARACTER SO RUSI */ -{"Thai_sosala", 0x0dc8}, /* U+0E28 THAI CHARACTER SO SALA */ -{"Thai_soso", 0x0dab}, /* U+0E0B THAI CHARACTER SO SO */ -{"Thai_sosua", 0x0dca}, /* U+0E2A THAI CHARACTER SO SUA */ -{"Thai_thanthakhat", 0x0dec}, /* U+0E4C THAI CHARACTER THANTHAKHAT */ -{"Thai_thonangmontho", 0x0db1}, /* U+0E11 THAI CHARACTER THO NANGMONTHO */ -{"Thai_thophuthao", 0x0db2}, /* U+0E12 THAI CHARACTER THO PHUTHAO */ -{"Thai_thothahan", 0x0db7}, /* U+0E17 THAI CHARACTER THO THAHAN */ -{"Thai_thothan", 0x0db0}, /* U+0E10 THAI CHARACTER THO THAN */ -{"Thai_thothong", 0x0db8}, /* U+0E18 THAI CHARACTER THO THONG */ -{"Thai_thothung", 0x0db6}, /* U+0E16 THAI CHARACTER THO THUNG */ -{"Thai_topatak", 0x0daf}, /* U+0E0F THAI CHARACTER TO PATAK */ -{"Thai_totao", 0x0db5}, /* U+0E15 THAI CHARACTER TO TAO */ -{"Thai_wowaen", 0x0dc7}, /* U+0E27 THAI CHARACTER WO WAEN */ -{"Thai_yoyak", 0x0dc2}, /* U+0E22 THAI CHARACTER YO YAK */ -{"Thai_yoying", 0x0dad}, /* U+0E0D THAI CHARACTER YO YING */ -{"threeeighths", 0x0ac4}, /* U+215C VULGAR FRACTION THREE EIGHTHS */ -{"trademark", 0x0ac9}, /* U+2122 TRADE MARK SIGN */ -{"tslash", 0x03bc}, /* U+0167 LATIN SMALL LETTER T WITH STROKE */ -{"Tslash", 0x03ac}, /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */ -{"umacron", 0x03fe}, /* U+016B LATIN SMALL LETTER U WITH MACRON */ -{"Umacron", 0x03de}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON */ -{"uogonek", 0x03f9}, /* U+0173 LATIN SMALL LETTER U WITH OGONEK */ -{"Uogonek", 0x03d9}, /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */ -{"uparrow", 0x08fc}, /* U+2191 UPWARDS ARROW */ -{"voicedsound", 0x04de}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ -{"Zcaron", 0x01ae}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON */ - -{NULL,0}, -}; diff --git a/qemu/ui/x_keymap.c b/qemu/ui/x_keymap.c deleted file mode 100644 index 27884851d..000000000 --- a/qemu/ui/x_keymap.c +++ /dev/null @@ -1,169 +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/osdep.h" -#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] = { - 0x73, /* 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 - ???? */ - 0x7e, /* 129 EVDEV - KP_COMMA (brazilian) */ - 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/qemu/ui/x_keymap.h b/qemu/ui/x_keymap.h deleted file mode 100644 index afde2e94b..000000000 --- a/qemu/ui/x_keymap.h +++ /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 - -uint8_t translate_xfree86_keycode(const int key); - -uint8_t translate_evdev_keycode(const int key); - -#endif |