Browse Source

ui/cocoa: Update cursor

Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
Akihiko Odaki 4 years ago
parent
commit
b3ebe68e23
1 changed files with 296 additions and 46 deletions
  1. 296 46
      ui/cocoa.m

+ 296 - 46
ui/cocoa.m

@@ -78,6 +78,10 @@
 
 
 typedef struct CocoaListener {
 typedef struct CocoaListener {
     DisplayChangeListener dcl;
     DisplayChangeListener dcl;
+    QEMUCursor *cursor;
+    int mouse_x;
+    int mouse_y;
+    int mouse_on;
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
     uint32_t gl_scanout_id;
     uint32_t gl_scanout_id;
     bool gl_scanout_y0_top;
     bool gl_scanout_y0_top;
@@ -95,12 +99,15 @@ @interface QemuCocoaPasteboardTypeOwner : NSObject<NSPasteboardTypeOwner>
 static void cocoa_switch(DisplayChangeListener *dcl,
 static void cocoa_switch(DisplayChangeListener *dcl,
                          DisplaySurface *surface);
                          DisplaySurface *surface);
 
 
+static void cocoa_cursor_update(void);
+
 static NSWindow *normalWindow;
 static NSWindow *normalWindow;
 static CocoaListener *active_listener;
 static CocoaListener *active_listener;
 static CocoaListener *listeners;
 static CocoaListener *listeners;
 static size_t listeners_count;
 static size_t listeners_count;
 static DisplaySurface *surface;
 static DisplaySurface *surface;
-static QemuMutex surface_mutex;
+static QemuMutex draw_mutex;
+static CGImageRef cursor_cgimage;
 static QKbdState *kbd;
 static QKbdState *kbd;
 static int cursor_hide = 1;
 static int cursor_hide = 1;
 static int left_command_key_enabled = 1;
 static int left_command_key_enabled = 1;
@@ -119,7 +126,8 @@ static void cocoa_switch(DisplayChangeListener *dcl,
 
 
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
 
 
-static bool gl_surface_dirty;
+static GLuint cursor_texture;
+static bool gl_dirty;
 static QEMUGLContext view_ctx;
 static QEMUGLContext view_ctx;
 
 
 #ifdef CONFIG_EGL
 #ifdef CONFIG_EGL
@@ -129,6 +137,8 @@ static void cocoa_switch(DisplayChangeListener *dcl,
 static void cocoa_gl_switch(DisplayChangeListener *dcl,
 static void cocoa_gl_switch(DisplayChangeListener *dcl,
                             DisplaySurface *new_surface);
                             DisplaySurface *new_surface);
 
 
+static void cocoa_gl_cursor_update(void);
+
 static bool cocoa_gl_is_compatible_dcl(DisplayGLCtx *dgc,
 static bool cocoa_gl_is_compatible_dcl(DisplayGLCtx *dgc,
                                        DisplayChangeListener *dcl);
                                        DisplayChangeListener *dcl);
 
 
@@ -208,6 +218,7 @@ static bool bool_with_iothread_lock(BoolCodeBlock block)
     qemu_cleanup();
     qemu_cleanup();
     qkbd_state_free(kbd);
     qkbd_state_free(kbd);
     [cbowner release];
     [cbowner release];
+    CGImageRelease(cursor_cgimage);
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
     qemu_gl_fini_shader(dgc.gls);
     qemu_gl_fini_shader(dgc.gls);
     if (view_ctx) {
     if (view_ctx) {
@@ -245,6 +256,20 @@ static void handleAnyDeviceErrors(Error * err)
     }
     }
 }
 }
 
 
+static CGRect compute_cursor_clip_rect(int screen_height,
+                                       int given_mouse_x, int given_mouse_y,
+                                       int cursor_width, int cursor_height)
+{
+    CGRect rect;
+
+    rect.origin.x = MAX(0, -given_mouse_x);
+    rect.origin.y = 0;
+    rect.size.width = MIN(cursor_width, cursor_width + given_mouse_x);
+    rect.size.height = cursor_height - rect.origin.x;
+
+    return rect;
+}
+
 /*
 /*
  ------------------------------------------------------
  ------------------------------------------------------
     QemuCocoaView
     QemuCocoaView
@@ -376,11 +401,13 @@ - (void) selectConsoleLocked:(unsigned int)index
 
 
     if (display_opengl) {
     if (display_opengl) {
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
+        cocoa_gl_cursor_update();
         cocoa_gl_switch(&active_listener->dcl, new_surface);
         cocoa_gl_switch(&active_listener->dcl, new_surface);
 #else
 #else
         g_assert_not_reached();
         g_assert_not_reached();
 #endif
 #endif
     } else {
     } else {
+        cocoa_cursor_update();
         cocoa_switch(&active_listener->dcl, new_surface);
         cocoa_switch(&active_listener->dcl, new_surface);
     }
     }
 
 
@@ -403,6 +430,21 @@ - (void) unhideCursor
     [NSCursor unhide];
     [NSCursor unhide];
 }
 }
 
 
+- (CGRect) convertCursorClipRectToDraw:(CGRect)rect
+                          screenHeight:(int)screen_height
+                                mouseX:(int)given_mouse_x
+                                mouseY:(int)given_mouse_y
+{
+    CGFloat d = [self frame].size.height / (CGFloat)screen_height;
+
+    rect.origin.x = (rect.origin.x + given_mouse_x) * d;
+    rect.origin.y = (screen_height - rect.origin.y - given_mouse_y - rect.size.height) * d;
+    rect.size.width *= d;
+    rect.size.height *= d;
+
+    return rect;
+}
+
 - (void) drawRect:(NSRect) rect
 - (void) drawRect:(NSRect) rect
 {
 {
     COCOA_DEBUG("QemuCocoaView: drawRect\n");
     COCOA_DEBUG("QemuCocoaView: drawRect\n");
@@ -419,7 +461,7 @@ - (void) drawRect:(NSRect) rect
     CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
     CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
     CGContextSetShouldAntialias (viewContextRef, NO);
     CGContextSetShouldAntialias (viewContextRef, NO);
 
 
-    qemu_mutex_lock(&surface_mutex);
+    qemu_mutex_lock(&draw_mutex);
 
 
     // draw screen bitmap directly to Core Graphics context
     // draw screen bitmap directly to Core Graphics context
     if (!surface) {
     if (!surface) {
@@ -475,9 +517,29 @@ - (void) drawRect:(NSRect) rect
         }
         }
         CGImageRelease (imageRef);
         CGImageRelease (imageRef);
         CGDataProviderRelease(dataProviderRef);
         CGDataProviderRelease(dataProviderRef);
+
+        if (active_listener->mouse_on) {
+            size_t cursor_width = CGImageGetWidth(cursor_cgimage);
+            size_t cursor_height = CGImageGetHeight(cursor_cgimage);
+            int mouse_x = active_listener->mouse_x;
+            int mouse_y = active_listener->mouse_y;
+            clipRect = compute_cursor_clip_rect(h, mouse_x, mouse_y,
+                                                cursor_width,
+                                                cursor_height);
+            CGRect drawRect = [self convertCursorClipRectToDraw:clipRect
+                                                   screenHeight:h
+                                                         mouseX:mouse_x
+                                                         mouseY:mouse_y];
+            clipImageRef = CGImageCreateWithImageInRect(
+                                                        cursor_cgimage,
+                                                        clipRect
+                                                        );
+            CGContextDrawImage(viewContextRef, drawRect, clipImageRef);
+            CGImageRelease (clipImageRef);
+        }
     }
     }
 
 
-    qemu_mutex_unlock(&surface_mutex);
+    qemu_mutex_unlock(&draw_mutex);
 }
 }
 
 
 - (NSSize) computeUnzoomedSize
 - (NSSize) computeUnzoomedSize
@@ -1872,13 +1934,13 @@ static void cocoa_update(DisplayChangeListener *dcl,
     COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
     COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
 
 
     dispatch_async(dispatch_get_main_queue(), ^{
     dispatch_async(dispatch_get_main_queue(), ^{
-        qemu_mutex_lock(&surface_mutex);
+        qemu_mutex_lock(&draw_mutex);
         if (updated != surface) {
         if (updated != surface) {
-            qemu_mutex_unlock(&surface_mutex);
+            qemu_mutex_unlock(&draw_mutex);
             return;
             return;
         }
         }
         int full_height = surface_height(surface);
         int full_height = surface_height(surface);
-        qemu_mutex_unlock(&surface_mutex);
+        qemu_mutex_unlock(&draw_mutex);
 
 
         CGFloat d = [cocoaView frame].size.height / full_height;
         CGFloat d = [cocoaView frame].size.height / full_height;
         NSRect rect = NSMakeRect(x * d, (full_height - y - h) * d, w * d, h * d);
         NSRect rect = NSMakeRect(x * d, (full_height - y - h) * d, w * d, h * d);
@@ -1895,15 +1957,15 @@ static void cocoa_switch(DisplayChangeListener *dcl,
         return;
         return;
     }
     }
 
 
-    qemu_mutex_lock(&surface_mutex);
+    qemu_mutex_lock(&draw_mutex);
     surface = new_surface;
     surface = new_surface;
-    qemu_mutex_unlock(&surface_mutex);
+    qemu_mutex_unlock(&draw_mutex);
 
 
     dispatch_async(dispatch_get_main_queue(), ^{
     dispatch_async(dispatch_get_main_queue(), ^{
-        qemu_mutex_lock(&surface_mutex);
+        qemu_mutex_lock(&draw_mutex);
         int w = surface_width(surface);
         int w = surface_width(surface);
         int h = surface_height(surface);
         int h = surface_height(surface);
-        qemu_mutex_unlock(&surface_mutex);
+        qemu_mutex_unlock(&draw_mutex);
 
 
         [cocoaView updateScreenWidth:w height:h];
         [cocoaView updateScreenWidth:w height:h];
     });
     });
@@ -1946,11 +2008,136 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
     [pool release];
     [pool release];
 }
 }
 
 
+static void cocoa_mouse_set(DisplayChangeListener *dcl, int x, int y, int on)
+{
+    CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
+
+    qemu_mutex_lock(&draw_mutex);
+    int full_height = surface_height(surface);
+    int old_x = listener->mouse_x;
+    int old_y = listener->mouse_y;
+    listener->mouse_x = x;
+    listener->mouse_y = y;
+    listener->mouse_on = on;
+    qemu_mutex_unlock(&draw_mutex);
+
+    if (listener == active_listener && cursor_cgimage) {
+        size_t cursor_width = CGImageGetWidth(cursor_cgimage);
+        size_t cursor_height = CGImageGetHeight(cursor_cgimage);
+
+        dispatch_async(dispatch_get_main_queue(), ^{
+            CGRect clip_rect = compute_cursor_clip_rect(full_height,
+                                                        old_x, old_y,
+                                                        cursor_width,
+                                                        cursor_height);
+            CGRect draw_rect =
+                [cocoaView convertCursorClipRectToDraw:clip_rect
+                                          screenHeight:full_height
+                                                mouseX:old_x
+                                                mouseY:old_y];
+            [cocoaView setNeedsDisplayInRect:draw_rect];
+
+            clip_rect = compute_cursor_clip_rect(full_height, x, y,
+                                                        cursor_width,
+                                                        cursor_height);
+            draw_rect =
+                [cocoaView convertCursorClipRectToDraw:clip_rect
+                                          screenHeight:full_height
+                                                mouseX:x
+                                                mouseY:y];
+            [cocoaView setNeedsDisplayInRect:draw_rect];
+        });
+    }
+}
+
+static void cocoa_cursor_update()
+{
+    CGImageRef old_image = cursor_cgimage;
+    CGImageRef new_image;
+
+    if (active_listener->cursor) {
+        CGDataProviderRef provider = CGDataProviderCreateWithData(
+            NULL,
+            active_listener->cursor->data,
+            active_listener->cursor->width * active_listener->cursor->height * 4,
+            NULL
+        );
+
+        new_image = CGImageCreate(
+            active_listener->cursor->width, //width
+            active_listener->cursor->height, //height
+            8, //bitsPerComponent
+            32, //bitsPerPixel
+            active_listener->cursor->width * 4, //bytesPerRow
+            CGColorSpaceCreateWithName(kCGColorSpaceSRGB), //colorspace
+            kCGBitmapByteOrder32Little | kCGImageAlphaFirst, //bitmapInfo
+            provider, //provider
+            NULL, //decode
+            0, //interpolate
+            kCGRenderingIntentDefault //intent
+        );
+
+        CGDataProviderRelease(provider);
+    } else {
+        new_image = NULL;
+    }
+
+    qemu_mutex_lock(&draw_mutex);
+    cursor_cgimage = new_image;
+    qemu_mutex_unlock(&draw_mutex);
+
+    CGImageRelease(old_image);
+}
+
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *cursor)
+{
+    CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
+
+    listener->cursor = cursor;
+
+    if (listener == active_listener) {
+        int full_height = surface_height(surface);
+        int width = cursor->width;
+        int height = cursor->height;
+        int x = listener->mouse_x;
+        int y = listener->mouse_y;
+        size_t old_width;
+        size_t old_height;
+
+        if (cursor_cgimage) {
+            old_width = CGImageGetWidth(cursor_cgimage);
+            old_height = CGImageGetHeight(cursor_cgimage);
+        } else {
+            old_width = 0;
+            old_height = 0;
+        }
+
+        cocoa_cursor_update();
+
+        dispatch_async(dispatch_get_main_queue(), ^{
+            CGFloat d = [cocoaView frame].size.height / full_height;
+            NSRect rect;
+
+            rect.origin.x = d * x;
+            rect.origin.y = d * (full_height - y - old_height);
+            rect.size.width = d * old_width;
+            rect.size.height = d * old_height;
+            [cocoaView setNeedsDisplayInRect:rect];
+
+            rect.size.width = d * width;
+            rect.size.height = d * height;
+            [cocoaView setNeedsDisplayInRect:rect];
+        });
+    }
+}
+
 static const DisplayChangeListenerOps dcl_ops = {
 static const DisplayChangeListenerOps dcl_ops = {
     .dpy_name          = "cocoa",
     .dpy_name          = "cocoa",
     .dpy_gfx_update = cocoa_update,
     .dpy_gfx_update = cocoa_update,
     .dpy_gfx_switch = cocoa_switch,
     .dpy_gfx_switch = cocoa_switch,
     .dpy_refresh = cocoa_refresh,
     .dpy_refresh = cocoa_refresh,
+    .dpy_mouse_set = cocoa_mouse_set,
+    .dpy_cursor_define = cocoa_cursor_define,
 };
 };
 
 
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
@@ -2058,16 +2245,38 @@ static void cocoa_gl_update(DisplayChangeListener *dcl,
 {
 {
     CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
     CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
 
 
-    if (listener != active_listener || listener->gl_scanout_id) {
+    if (listener != active_listener) {
         return;
         return;
     }
     }
 
 
     with_view_ctx(^{
     with_view_ctx(^{
         surface_gl_update_texture(dgc.gls, surface, x, y, w, h);
         surface_gl_update_texture(dgc.gls, surface, x, y, w, h);
-        gl_surface_dirty = true;
+        gl_dirty = true;
     });
     });
 }
 }
 
 
+static void cocoa_gl_cursor_render()
+{
+    if (!active_listener->mouse_on) {
+        return;
+    }
+
+    NSSize size = [cocoaView convertSizeToBacking:[cocoaView frame].size];
+    CGFloat d = size.height / surface_height(surface);
+
+    glViewport(
+        d * active_listener->mouse_x,
+        size.height - d * (active_listener->mouse_y + active_listener->cursor->height),
+        d * active_listener->cursor->width,
+        d * active_listener->cursor->height
+    );
+    glBindTexture(GL_TEXTURE_2D, cursor_texture);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    qemu_gl_run_texture_blit(dgc.gls, false);
+    glDisable(GL_BLEND);
+}
+
 static void cocoa_gl_switch(DisplayChangeListener *dcl,
 static void cocoa_gl_switch(DisplayChangeListener *dcl,
                             DisplaySurface *new_surface)
                             DisplaySurface *new_surface)
 {
 {
@@ -2083,21 +2292,39 @@ static void cocoa_gl_switch(DisplayChangeListener *dcl,
     });
     });
 
 
     cocoa_switch(dcl, new_surface);
     cocoa_switch(dcl, new_surface);
-    gl_surface_dirty = true;
+    gl_dirty = true;
 }
 }
 
 
 static void cocoa_gl_refresh(DisplayChangeListener *dcl)
 static void cocoa_gl_refresh(DisplayChangeListener *dcl)
 {
 {
+    CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
+
+    if (listener != active_listener) {
+        return;
+    }
+
     cocoa_refresh(dcl);
     cocoa_refresh(dcl);
 
 
-    if (gl_surface_dirty) {
-        gl_surface_dirty = false;
+    if (gl_dirty) {
+        gl_dirty = false;
 
 
         with_view_ctx(^{
         with_view_ctx(^{
             NSSize size = [cocoaView convertSizeToBacking:[cocoaView frame].size];
             NSSize size = [cocoaView convertSizeToBacking:[cocoaView frame].size];
 
 
-            surface_gl_setup_viewport(dgc.gls, surface, size.width, size.height);
-            surface_gl_render_texture(dgc.gls, surface);
+            if (listener->gl_scanout_id) {
+                glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+                glViewport(0, 0, size.width, size.height);
+                glBindTexture(GL_TEXTURE_2D, active_listener->gl_scanout_id);
+                qemu_gl_run_texture_blit(dgc.gls,
+                                         active_listener->gl_scanout_y0_top);
+            } else {
+                surface_gl_setup_viewport(dgc.gls, surface,
+                                          size.width, size.height);
+                glBindTexture(GL_TEXTURE_2D, surface->texture);
+                surface_gl_render_texture(dgc.gls, surface);
+            }
+
+            cocoa_gl_cursor_render();
             cocoa_gl_flush();
             cocoa_gl_flush();
         });
         });
     }
     }
@@ -2109,13 +2336,40 @@ static void cocoa_gl_scanout_disable(DisplayChangeListener *dcl)
 
 
     listener->gl_scanout_id = 0;
     listener->gl_scanout_id = 0;
 
 
-    if (listener == active_listener && surface) {
+    if (listener == active_listener) {
+        gl_dirty = surface != NULL;
+    }
+}
+
+static void cocoa_gl_cursor_update()
+{
+    if (active_listener->cursor) {
         with_view_ctx(^{
         with_view_ctx(^{
-            surface_gl_destroy_texture(dgc.gls, surface);
-            surface_gl_create_texture(dgc.gls, surface);
+            glBindTexture(GL_TEXTURE_2D, cursor_texture);
+            glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
+                          active_listener->cursor->width);
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                         epoxy_is_desktop_gl() ? GL_RGBA : GL_BGRA,
+                         active_listener->cursor->width,
+                         active_listener->cursor->height,
+                         0, GL_BGRA, GL_UNSIGNED_BYTE,
+                         active_listener->cursor->data);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
         });
         });
+    }
+
+    gl_dirty = true;
+}
 
 
-        gl_surface_dirty = true;
+static void cocoa_gl_cursor_define(DisplayChangeListener *dcl, QEMUCursor *cursor)
+{
+    CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
+
+    listener->cursor = cursor;
+
+    if (listener == active_listener) {
+        cocoa_gl_cursor_update();
     }
     }
 }
 }
 
 
@@ -2131,35 +2385,28 @@ static void cocoa_gl_scanout_texture(DisplayChangeListener *dcl,
 
 
     listener->gl_scanout_id = backing_id;
     listener->gl_scanout_id = backing_id;
     listener->gl_scanout_y0_top = backing_y_0_top;
     listener->gl_scanout_y0_top = backing_y_0_top;
-
-    if (listener == active_listener) {
-        gl_surface_dirty = false;
-    }
+    gl_dirty = true;
 }
 }
 
 
-static void cocoa_gl_scanout_flush()
+static void cocoa_gl_scanout_flush(DisplayChangeListener *dcl,
+                                   uint32_t x, uint32_t y,
+                                   uint32_t w, uint32_t h)
 {
 {
-    if (!active_listener->gl_scanout_id) {
-        return;
+    if (container_of(dcl, CocoaListener, dcl) == active_listener) {
+        gl_dirty = true;
     }
     }
-
-    with_view_ctx(^{
-        NSSize size = [cocoaView convertSizeToBacking:[cocoaView frame].size];
-
-        glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
-        glViewport(0, 0, size.width, size.height);
-        glBindTexture(GL_TEXTURE_2D, active_listener->gl_scanout_id);
-        qemu_gl_run_texture_blit(dgc.gls, active_listener->gl_scanout_y0_top);
-        cocoa_gl_flush();
-    });
 }
 }
 
 
-static void cocoa_gl_scanout_flush_proxy(DisplayChangeListener *dcl,
-                                         uint32_t x, uint32_t y,
-                                         uint32_t w, uint32_t h)
+static void cocoa_gl_mouse_set(DisplayChangeListener *dcl, int x, int y, int on)
 {
 {
-    if (container_of(dcl, CocoaListener, dcl) == active_listener) {
-        cocoa_gl_scanout_flush();
+    CocoaListener *listener = container_of(dcl, CocoaListener, dcl);
+
+    listener->mouse_x = x;
+    listener->mouse_y = y;
+    listener->mouse_on = on;
+
+    if (listener == active_listener) {
+        gl_dirty = true;
     }
     }
 }
 }
 
 
@@ -2169,10 +2416,12 @@ static void cocoa_gl_scanout_flush_proxy(DisplayChangeListener *dcl,
     .dpy_gfx_switch         = cocoa_gl_switch,
     .dpy_gfx_switch         = cocoa_gl_switch,
     .dpy_gfx_check_format   = console_gl_check_format,
     .dpy_gfx_check_format   = console_gl_check_format,
     .dpy_refresh            = cocoa_gl_refresh,
     .dpy_refresh            = cocoa_gl_refresh,
+    .dpy_mouse_set          = cocoa_gl_mouse_set,
+    .dpy_cursor_define      = cocoa_gl_cursor_define,
 
 
     .dpy_gl_scanout_disable = cocoa_gl_scanout_disable,
     .dpy_gl_scanout_disable = cocoa_gl_scanout_disable,
     .dpy_gl_scanout_texture = cocoa_gl_scanout_texture,
     .dpy_gl_scanout_texture = cocoa_gl_scanout_texture,
-    .dpy_gl_update          = cocoa_gl_scanout_flush_proxy,
+    .dpy_gl_update          = cocoa_gl_scanout_flush,
 };
 };
 
 
 static bool cocoa_gl_is_compatible_dcl(DisplayGLCtx *dgc,
 static bool cocoa_gl_is_compatible_dcl(DisplayGLCtx *dgc,
@@ -2212,7 +2461,7 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
     appController = [[QemuCocoaAppController alloc] init];
     appController = [[QemuCocoaAppController alloc] init];
     [NSApp setDelegate:appController];
     [NSApp setDelegate:appController];
 
 
-    qemu_mutex_init(&surface_mutex);
+    qemu_mutex_init(&draw_mutex);
 
 
     if (display_opengl) {
     if (display_opengl) {
 #ifdef CONFIG_OPENGL
 #ifdef CONFIG_OPENGL
@@ -2249,6 +2498,7 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
         }
         }
 
 
         dgc.gls = qemu_gl_init_shader();
         dgc.gls = qemu_gl_init_shader();
+        glGenTextures(1, &cursor_texture);
 
 
         // register vga output callbacks
         // register vga output callbacks
         ops = &dcl_gl_ops;
         ops = &dcl_gl_ops;