[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] ui/cocoa: Implement dcl operators for guest cursor
From: |
Zhang Chen |
Subject: |
[PATCH] ui/cocoa: Implement dcl operators for guest cursor |
Date: |
Tue, 10 Aug 2021 17:17:06 +0800 |
In this patch, two dcl operators were implemented for Cocoa
display, to prepare, update and draw guest cursor on screen canvas.
After this implementation, Cocoa display could support virtio-vga
device, which is better supported in guest side, especially for Linux.
In contrast to the default vga device, virtio-vga with dcl operators
for cursors showed less flicker in cursor drawing.
Two fields were added in the struct QemuScreen to pass dimensions to
dcl operators.
Signed-off-by: Zhang Chen <tgfbeta@me.com>
---
ui/cocoa.m | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 68a6302184..9d3a8eac28 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -73,6 +73,8 @@
typedef struct {
int width;
int height;
+ int bitsPerComponent;
+ int bitsPerPixel;
} QEMUScreen;
static void cocoa_update(DisplayChangeListener *dcl,
@@ -83,12 +85,19 @@ static void cocoa_switch(DisplayChangeListener *dcl,
static void cocoa_refresh(DisplayChangeListener *dcl);
+static void cocoa_mouse_set(DisplayChangeListener *dcl,
+ int x, int y, int visible);
+
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c);
+
static NSWindow *normalWindow, *about_window;
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "cocoa",
.dpy_gfx_update = cocoa_update,
.dpy_gfx_switch = cocoa_switch,
.dpy_refresh = cocoa_refresh,
+ .dpy_mouse_set = cocoa_mouse_set,
+ .dpy_cursor_define = cocoa_cursor_define,
};
static DisplayChangeListener dcl = {
.ops = &dcl_ops,
@@ -309,6 +318,9 @@ static void handleAnyDeviceErrors(Error * err)
BOOL isMouseGrabbed;
BOOL isFullscreen;
BOOL isAbsoluteEnabled;
+ CGRect cursorRect;
+ CGImageRef cursorImage;
+ BOOL cursorVisible;
}
- (void) switchSurface:(pixman_image_t *)image;
- (void) grabMouse;
@@ -344,6 +356,8 @@ QemuCocoaView *cocoaView;
self = [super initWithFrame:frameRect];
if (self) {
+ screen.bitsPerComponent = 8;
+ screen.bitsPerPixel = 32;
screen.width = frameRect.size.width;
screen.height = frameRect.size.height;
kbd = qkbd_state_init(dcl.con);
@@ -484,6 +498,12 @@ QemuCocoaView *cocoaView;
);
CGContextDrawImage (viewContextRef, cgrect(rectList[i]),
clipImageRef);
CGImageRelease (clipImageRef);
+
+ }
+ CGRect cursorDrawRect = stretch_video ?
+ [self
convertRectFromQemuScreen:cursorRect] : cursorRect;
+ if (cursorVisible && cursorImage && NSIntersectsRect(rect,
cursorDrawRect)) {
+ CGContextDrawImage (viewContextRef, cursorDrawRect, cursorImage);
}
CGImageRelease (imageRef);
CGDataProviderRelease(dataProviderRef);
@@ -1075,6 +1095,28 @@ QemuCocoaView *cocoaView;
- (float) cdy {return cdy;}
- (QEMUScreen) gscreen {return screen;}
+- (CGRect) cursorRect {return cursorRect;}
+- (void) setCursorRect:(CGRect)rect {cursorRect = rect;}
+- (CGImageRef) cursorImage {return cursorImage;}
+- (void) setCursorImage:(CGImageRef)image
+{
+ if (cursorImage && cursorImage != image) {
+ CGImageRelease(cursorImage);
+ }
+ cursorImage = image;
+}
+- (BOOL) isCursorVisible {return cursorVisible;}
+- (void) setCursorVisible:(BOOL)visible {cursorVisible = visible;}
+
+- (CGRect) convertRectFromQemuScreen:(CGRect)rect
+{
+ CGRect viewRect = rect;
+ viewRect.origin.x *= cdx;
+ viewRect.origin.y *= cdy;
+ viewRect.size.width *= cdx;
+ viewRect.size.height *= cdy;
+ return viewRect;
+}
/*
* Makes the target think all down keys are being released.
* This prevents a stuck key problem, since we will not see
@@ -2022,6 +2064,63 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
[pool release];
}
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c)
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int bitsPerComponent = [cocoaView gscreen].bitsPerComponent;
+ int bitsPerPixel = [cocoaView gscreen].bitsPerPixel;
+ int stride = c->width * bitsPerComponent / 2;
+ CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, c->data,
c->width * 4 * c->height, NULL);
+
+ CGImageRef img = CGImageCreate(
+ c->width,
+ c->height,
+ bitsPerComponent,
+ bitsPerPixel,
+ stride,
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst,
+ provider,
+ NULL,
+ 0,
+ kCGRenderingIntentDefault
+ );
+
+ CGDataProviderRelease(provider);
+ CGFloat width = c->width;
+ CGFloat height = c->height;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [cocoaView setCursorImage:img];
+ CGRect rect = [cocoaView cursorRect];
+ rect.size = CGSizeMake(width, height);
+ [cocoaView setCursorRect:rect];
+ });
+ [pool release];
+}
+
+static void cocoa_mouse_set(DisplayChangeListener *dcl,
+ int x, int y, int visible)
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ QEMUScreen screen = [cocoaView gscreen];
+ // Mark old cursor rect as dirty
+ CGRect rect = [cocoaView cursorRect];
+ CGRect dirtyRect = stretch_video ?
+ [cocoaView convertRectFromQemuScreen:rect] : rect;
+ [cocoaView setNeedsDisplayInRect:dirtyRect];
+ // Update rect for cursor sprite
+ rect.origin = CGPointMake(x, screen.height - (y + rect.size.height));
+ [cocoaView setCursorRect:rect];
+ [cocoaView setCursorVisible:visible ? YES : NO];
+ // Mark new cursor rect as dirty
+ dirtyRect = stretch_video ?
+ [cocoaView convertRectFromQemuScreen:rect] : rect;
+ [cocoaView setNeedsDisplayInRect:dirtyRect];
+ });
+ [pool release];
+}
+
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
{
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
--
2.30.2