qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] ui/cocoa: Adding cursor support


From: Chen Zhang
Subject: [Qemu-devel] [PATCH] ui/cocoa: Adding cursor support
Date: Tue, 12 Mar 2019 09:47:02 +0800

This patch added cocoa_mouse_set() and cocoa_cursor_define(),
supporting virtio-gpu simple rendering on macOS host.

Image content, rect and visibility of the cursor buffer were added as
ivars in QemuCocoaView class. Corresponding accessors were added.

Note that the rect of the cursor was in coordinates of the QEMU
screen, not the NSScreen or the NSView, for convenience of blending.

Signed-off-by: Chen Zhang <address@hidden>
---
 ui/cocoa.m | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index 420b2411c1..8beed6e514 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -334,6 +334,9 @@ static void handleAnyDeviceErrors(Error * err)
     BOOL isFullscreen;
     BOOL isAbsoluteEnabled;
     BOOL isMouseDeassociated;
+    CGRect cursorRect;
+    CGImageRef cursorImage;
+    BOOL cursorVisible;
 }
 - (void) switchSurface:(pixman_image_t *)image;
 - (void) grabMouse;
@@ -362,6 +365,12 @@ static void handleAnyDeviceErrors(Error * err)
 - (float) cdy;
 - (QEMUScreen) gscreen;
 - (void) raiseAllKeys;
+- (CGRect) cursorRect;
+- (void) setCursorRect:(CGRect)rect;
+- (CGImageRef) cursorImage;
+- (void) setCursorImage:(CGImageRef)image;
+- (BOOL) isCursorVisible;
+- (void) setCursorVisible:(BOOL)visible;
 @end
 
 QemuCocoaView *cocoaView;
@@ -392,6 +401,10 @@ QemuCocoaView *cocoaView;
         pixman_image_unref(pixman_image);
     }
 
+    if (cursorImage) {
+        CGImageRelease(cursorImage);
+    }
+
     [super dealloc];
 }
 
@@ -479,6 +492,10 @@ QemuCocoaView *cocoaView;
                                                         );
             CGContextDrawImage (viewContextRef, cgrect(rectList[i]), 
clipImageRef);
             CGImageRelease (clipImageRef);
+
+        }
+        if (cursorVisible && cursorImage && NSIntersectsRect(rect, 
cursorRect)) {
+            CGContextDrawImage (viewContextRef, cursorRect, cursorImage);
         }
         CGImageRelease (imageRef);
     }
@@ -987,6 +1004,19 @@ 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;}
+
 /*
  * Makes the target think all down keys are being released.
  * This prevents a stuck key problem, since we will not see
@@ -1830,6 +1860,53 @@ 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;
+    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, c->data, 
c->width * 4 * c->height, NULL);
+
+    CGImageRef img = CGImageCreate(c->width, c->height,
+                                   bitsPerComponent, bitsPerPixel, c->width * 
bitsPerComponent / 2,
+#ifdef __LITTLE_ENDIAN__
+                                   
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 
10.4
+                                   kCGBitmapByteOrder32Little | 
kCGImageAlphaFirst,
+#else
+                                   CGColorSpaceCreateDeviceRGB(), //colorspace 
for OS X < 10.4 (actually ppc)
+                                   kCGImageAlphaFirst, //bitmapInfo
+#endif
+                                   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];
+        CGRect rect = [cocoaView cursorRect];
+        // Mark old cursor rect as dirty
+        [cocoaView setNeedsDisplayInRect:rect];
+        rect.origin = CGPointMake(x, screen.height - (y + rect.size.height));
+        [cocoaView setCursorRect:rect];
+        [cocoaView setCursorVisible:visible ? YES : NO];
+        // Mark new cursor rect as dirty
+        [cocoaView setNeedsDisplayInRect:rect];
+    });
+    [pool release];
+}
+
 static void cocoa_cleanup(void)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
@@ -1841,6 +1918,8 @@ static const DisplayChangeListenerOps dcl_ops = {
     .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 void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
-- 
2.19.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]