ui: spice bugfixes.
ui: first batch of cocoa updates. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmAwNO4ACgkQTLbY7tPo cTh1bg/9HFDW5uJCWgZUX4xFiTYspJAR9OmMKmV/8oPSZEgBpB6Pk8KMHUW/FAIc C7h0x7MQPccDk44zBO7CR4rJgPN1V3n4ws6xXtsnjLh+EoDxmC3mUYv7AQIRQL+7 cF4wBABB2uKJeBNG3yHzLE9KWnHj7jCmSOqC6HQs/erm30fxxLYgWlSpLcLTrga+ DPbCoZbmh1GE4NNBf6HdoBjwwTSAACgrs1nUsie9PsHsTO4EZu2DdVqC+bL63n7G hVDxiMYhNUZEWn8uRZY0S6O1qXkXTXmMruUqGb4uiwcBIHo+EyuWfHDU4hPcz+UE awbbt4kkv4MhNQi154271X4z0rwK64ox7R3ut+kZaCquuTI7bzKN+zPqU0ZkfpJm rhT83NcrKh523xHBOimxjMSBmnhyIC9vFmI6kpnRxNCF4o6bKmZwHRTovgAYtG1O YJjDlV075ZbGZZD8DEZkWjinNu8w/zcme+Ppu7XXNggf3dSWwYWbWRtRNCmhDadS zn6PrFrO8nl0y0GYT8mwtacFgkyX593hllmhSYQK075ISvgfORUhZ5C0eMPY2w3H RXCWkkbHTaY4N6Fm+OfVBRTFS1rPkWyVOUraydHwi8XdLfCCC3YytYqxslCVa9hu SkIQkGOUzTIRiGekCDo4wZwCmUboHxQeJrpLnBHRArnTsNc6Pow= =ZdZ1 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/ui-20210219-pull-request' into staging ui: spice bugfixes. ui: first batch of cocoa updates. # gpg: Signature made Fri 19 Feb 2021 22:00:14 GMT # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/ui-20210219-pull-request: ui/console: Remove dpy_gl_ctx_get_current ui/cocoa: Statically allocate dcl ui/cocoa: Interpret left button down as is when command is pressed spice-app: avoid crash when core spice module doesn't loaded ui/cocoa: Do not copy members of pixman image ui/cocoa: Support unique keys of JIS keyboards spice: flush drawing before notifying client spice: flush on GL update before notifying client Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d6798cc01d
@ -147,7 +147,6 @@ void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
|
||||
void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
|
||||
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
||||
void gtk_gl_area_init(void);
|
||||
QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl);
|
||||
int gd_gl_area_make_current(DisplayChangeListener *dcl,
|
||||
QEMUGLContext ctx);
|
||||
|
||||
|
126
ui/cocoa.m
126
ui/cocoa.m
@ -70,12 +70,26 @@
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int bitsPerComponent;
|
||||
int bitsPerPixel;
|
||||
} QEMUScreen;
|
||||
|
||||
static void cocoa_update(DisplayChangeListener *dcl,
|
||||
int x, int y, int w, int h);
|
||||
|
||||
static void cocoa_switch(DisplayChangeListener *dcl,
|
||||
DisplaySurface *surface);
|
||||
|
||||
static void cocoa_refresh(DisplayChangeListener *dcl);
|
||||
|
||||
NSWindow *normalWindow, *about_window;
|
||||
static DisplayChangeListener *dcl;
|
||||
static const DisplayChangeListenerOps dcl_ops = {
|
||||
.dpy_name = "cocoa",
|
||||
.dpy_gfx_update = cocoa_update,
|
||||
.dpy_gfx_switch = cocoa_switch,
|
||||
.dpy_refresh = cocoa_refresh,
|
||||
};
|
||||
static DisplayChangeListener dcl = {
|
||||
.ops = &dcl_ops,
|
||||
};
|
||||
static int last_buttons;
|
||||
static int cursor_hide = 1;
|
||||
|
||||
@ -240,6 +254,13 @@ const int mac_to_qkeycode_map[] = {
|
||||
[kVK_F14] = Q_KEY_CODE_SCROLL_LOCK,
|
||||
[kVK_F15] = Q_KEY_CODE_PAUSE,
|
||||
|
||||
// JIS keyboards only
|
||||
[kVK_JIS_Yen] = Q_KEY_CODE_YEN,
|
||||
[kVK_JIS_Underscore] = Q_KEY_CODE_RO,
|
||||
[kVK_JIS_KeypadComma] = Q_KEY_CODE_KP_COMMA,
|
||||
[kVK_JIS_Eisu] = Q_KEY_CODE_MUHENKAN,
|
||||
[kVK_JIS_Kana] = Q_KEY_CODE_HENKAN,
|
||||
|
||||
/*
|
||||
* The eject and volume keys can't be used here because they are handled at
|
||||
* a lower level than what an Application can see.
|
||||
@ -284,7 +305,6 @@ static void handleAnyDeviceErrors(Error * err)
|
||||
QEMUScreen screen;
|
||||
NSWindow *fullScreenWindow;
|
||||
float cx,cy,cw,ch,cdx,cdy;
|
||||
CGDataProviderRef dataProviderRef;
|
||||
pixman_image_t *pixman_image;
|
||||
BOOL modifiers_state[256];
|
||||
BOOL isMouseGrabbed;
|
||||
@ -331,8 +351,6 @@ QemuCocoaView *cocoaView;
|
||||
self = [super initWithFrame:frameRect];
|
||||
if (self) {
|
||||
|
||||
screen.bitsPerComponent = 8;
|
||||
screen.bitsPerPixel = 32;
|
||||
screen.width = frameRect.size.width;
|
||||
screen.height = frameRect.size.height;
|
||||
|
||||
@ -344,8 +362,7 @@ QemuCocoaView *cocoaView;
|
||||
{
|
||||
COCOA_DEBUG("QemuCocoaView: dealloc\n");
|
||||
|
||||
if (dataProviderRef) {
|
||||
CGDataProviderRelease(dataProviderRef);
|
||||
if (pixman_image) {
|
||||
pixman_image_unref(pixman_image);
|
||||
}
|
||||
|
||||
@ -424,18 +441,28 @@ QemuCocoaView *cocoaView;
|
||||
CGContextSetShouldAntialias (viewContextRef, NO);
|
||||
|
||||
// draw screen bitmap directly to Core Graphics context
|
||||
if (!dataProviderRef) {
|
||||
if (!pixman_image) {
|
||||
// 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 {
|
||||
int w = pixman_image_get_width(pixman_image);
|
||||
int h = pixman_image_get_height(pixman_image);
|
||||
int bitsPerPixel = PIXMAN_FORMAT_BPP(pixman_image_get_format(pixman_image));
|
||||
int bitsPerComponent = DIV_ROUND_UP(bitsPerPixel, 8) * 2;
|
||||
CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(
|
||||
NULL,
|
||||
pixman_image_get_data(pixman_image),
|
||||
w * 4 * h,
|
||||
NULL
|
||||
);
|
||||
CGImageRef imageRef = CGImageCreate(
|
||||
screen.width, //width
|
||||
screen.height, //height
|
||||
screen.bitsPerComponent, //bitsPerComponent
|
||||
screen.bitsPerPixel, //bitsPerPixel
|
||||
(screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
|
||||
w, //width
|
||||
h, //height
|
||||
bitsPerComponent, //bitsPerComponent
|
||||
bitsPerPixel, //bitsPerPixel
|
||||
(w * (bitsPerComponent/2)), //bytesPerRow
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
|
||||
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
|
||||
@ -458,7 +485,7 @@ QemuCocoaView *cocoaView;
|
||||
[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.origin.y = (float)h - (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(
|
||||
@ -469,6 +496,7 @@ QemuCocoaView *cocoaView;
|
||||
CGImageRelease (clipImageRef);
|
||||
}
|
||||
CGImageRelease (imageRef);
|
||||
CGDataProviderRelease(dataProviderRef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +539,6 @@ QemuCocoaView *cocoaView;
|
||||
|
||||
int w = pixman_image_get_width(image);
|
||||
int h = pixman_image_get_height(image);
|
||||
pixman_format_code_t image_format = pixman_image_get_format(image);
|
||||
/* 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.
|
||||
@ -529,17 +556,11 @@ QemuCocoaView *cocoaView;
|
||||
}
|
||||
|
||||
// update screenBuffer
|
||||
if (dataProviderRef) {
|
||||
CGDataProviderRelease(dataProviderRef);
|
||||
if (pixman_image) {
|
||||
pixman_image_unref(pixman_image);
|
||||
}
|
||||
|
||||
//sync host window color space with guests
|
||||
screen.bitsPerPixel = PIXMAN_FORMAT_BPP(image_format);
|
||||
screen.bitsPerComponent = DIV_ROUND_UP(screen.bitsPerPixel, 8) * 2;
|
||||
|
||||
pixman_image = image;
|
||||
dataProviderRef = CGDataProviderCreateWithData(NULL, pixman_image_get_data(image), w * 4 * h, NULL);
|
||||
|
||||
// update windows
|
||||
if (isFullscreen) {
|
||||
@ -602,15 +623,15 @@ QemuCocoaView *cocoaView;
|
||||
// Toggle the stored state.
|
||||
modifiers_state[keycode] = !modifiers_state[keycode];
|
||||
// Send a keyup or keydown depending on the state.
|
||||
qemu_input_event_send_key_qcode(dcl->con, keycode, modifiers_state[keycode]);
|
||||
qemu_input_event_send_key_qcode(dcl.con, keycode, modifiers_state[keycode]);
|
||||
}
|
||||
|
||||
- (void) toggleStatefulModifier: (int)keycode {
|
||||
// Toggle the stored state.
|
||||
modifiers_state[keycode] = !modifiers_state[keycode];
|
||||
// Generate keydown and keyup.
|
||||
qemu_input_event_send_key_qcode(dcl->con, keycode, true);
|
||||
qemu_input_event_send_key_qcode(dcl->con, keycode, false);
|
||||
qemu_input_event_send_key_qcode(dcl.con, keycode, true);
|
||||
qemu_input_event_send_key_qcode(dcl.con, keycode, false);
|
||||
}
|
||||
|
||||
// Does the work of sending input to the monitor
|
||||
@ -794,7 +815,7 @@ QemuCocoaView *cocoaView;
|
||||
}
|
||||
|
||||
if (qemu_console_is_graphic(NULL)) {
|
||||
qemu_input_event_send_key_qcode(dcl->con, keycode, true);
|
||||
qemu_input_event_send_key_qcode(dcl.con, keycode, true);
|
||||
} else {
|
||||
[self handleMonitorInput: event];
|
||||
}
|
||||
@ -809,7 +830,7 @@ QemuCocoaView *cocoaView;
|
||||
}
|
||||
|
||||
if (qemu_console_is_graphic(NULL)) {
|
||||
qemu_input_event_send_key_qcode(dcl->con, keycode, false);
|
||||
qemu_input_event_send_key_qcode(dcl.con, keycode, false);
|
||||
}
|
||||
break;
|
||||
case NSEventTypeMouseMoved:
|
||||
@ -830,11 +851,7 @@ QemuCocoaView *cocoaView;
|
||||
mouse_event = true;
|
||||
break;
|
||||
case NSEventTypeLeftMouseDown:
|
||||
if ([event modifierFlags] & NSEventModifierFlagCommand) {
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
} else {
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
}
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
mouse_event = true;
|
||||
break;
|
||||
case NSEventTypeRightMouseDown:
|
||||
@ -846,11 +863,7 @@ QemuCocoaView *cocoaView;
|
||||
mouse_event = true;
|
||||
break;
|
||||
case NSEventTypeLeftMouseDragged:
|
||||
if ([event modifierFlags] & NSEventModifierFlagCommand) {
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
} else {
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
}
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
mouse_event = true;
|
||||
break;
|
||||
case NSEventTypeRightMouseDragged:
|
||||
@ -895,9 +908,9 @@ QemuCocoaView *cocoaView;
|
||||
/* Determine if this is a scroll up or scroll down event */
|
||||
buttons = ([event deltaY] > 0) ?
|
||||
INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
|
||||
qemu_input_queue_btn(dcl->con, buttons, true);
|
||||
qemu_input_queue_btn(dcl.con, buttons, true);
|
||||
qemu_input_event_sync();
|
||||
qemu_input_queue_btn(dcl->con, buttons, false);
|
||||
qemu_input_queue_btn(dcl.con, buttons, false);
|
||||
qemu_input_event_sync();
|
||||
}
|
||||
/*
|
||||
@ -925,7 +938,7 @@ QemuCocoaView *cocoaView;
|
||||
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
||||
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON
|
||||
};
|
||||
qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
|
||||
qemu_input_update_buttons(dcl.con, bmap, last_buttons, buttons);
|
||||
last_buttons = buttons;
|
||||
}
|
||||
if (isMouseGrabbed) {
|
||||
@ -935,12 +948,12 @@ QemuCocoaView *cocoaView;
|
||||
* clicks in the titlebar.
|
||||
*/
|
||||
if ([self screenContainsPoint:p]) {
|
||||
qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, 0, screen.width);
|
||||
qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, 0, screen.height);
|
||||
qemu_input_queue_abs(dcl.con, INPUT_AXIS_X, p.x, 0, screen.width);
|
||||
qemu_input_queue_abs(dcl.con, INPUT_AXIS_Y, screen.height - p.y, 0, 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]);
|
||||
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 {
|
||||
return false;
|
||||
@ -1009,7 +1022,7 @@ QemuCocoaView *cocoaView;
|
||||
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);
|
||||
qemu_input_event_send_key_qcode(dcl.con, index, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1836,19 +1849,6 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
|
||||
[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,
|
||||
};
|
||||
|
||||
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
{
|
||||
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
|
||||
@ -1869,14 +1869,8 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
cursor_hide = 0;
|
||||
}
|
||||
|
||||
dcl = g_malloc0(sizeof(DisplayChangeListener));
|
||||
|
||||
// register vga output callbacks
|
||||
dcl->ops = &dcl_ops;
|
||||
register_displaychangelistener(dcl);
|
||||
|
||||
// register cleanup function
|
||||
atexit(cocoa_cleanup);
|
||||
register_displaychangelistener(&dcl);
|
||||
}
|
||||
|
||||
static QemuDisplay qemu_display_cocoa = {
|
||||
|
@ -239,11 +239,6 @@ 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)
|
||||
{
|
||||
|
@ -129,6 +129,7 @@ static void spice_app_atexit(void)
|
||||
static void spice_app_display_early_init(DisplayOptions *opts)
|
||||
{
|
||||
QemuOpts *qopts;
|
||||
QemuOptsList *list;
|
||||
GError *err = NULL;
|
||||
|
||||
if (opts->has_full_screen) {
|
||||
@ -159,11 +160,16 @@ static void spice_app_display_early_init(DisplayOptions *opts)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
list = qemu_find_opts("spice");
|
||||
if (list == NULL) {
|
||||
error_report("spice-app missing spice support");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
type_register(&char_vc_type_info);
|
||||
|
||||
sock_path = g_strjoin("", app_dir, "/", "spice.sock", NULL);
|
||||
qopts = qemu_opts_create(qemu_find_opts("spice"), NULL, 0, &error_abort);
|
||||
qopts = qemu_opts_create(list, NULL, 0, &error_abort);
|
||||
qemu_opt_set(qopts, "disable-ticketing", "on", &error_abort);
|
||||
qemu_opt_set(qopts, "unix", "on", &error_abort);
|
||||
qemu_opt_set(qopts, "addr", sock_path, &error_abort);
|
||||
|
@ -846,6 +846,7 @@ static void spice_gl_refresh(DisplayChangeListener *dcl)
|
||||
graphic_hw_update(dcl->con);
|
||||
if (ssd->gl_updates && ssd->have_surface) {
|
||||
qemu_spice_gl_block(ssd, true);
|
||||
glFlush();
|
||||
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
|
||||
spice_qxl_gl_draw_async(&ssd->qxl, 0, 0,
|
||||
surface_width(ssd->ds),
|
||||
@ -1087,6 +1088,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
|
||||
|
||||
trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y);
|
||||
qemu_spice_gl_block(ssd, true);
|
||||
glFlush();
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user