diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-12-29 16:09:43 +0100 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-12-29 16:39:54 +0100 |
commit | 645250e1cd8ce9bc1faea599df7a1b05836bfeb8 (patch) | |
tree | c6311afab3900d2dd2aecbfbe1ac348d0e48c428 /plugingui/nativewindow_cocoa.mm | |
parent | dce64999d3325c5b55499d6ba657066efa48fbff (diff) |
Split UI code into application/plugin UI and UI library.
Diffstat (limited to 'plugingui/nativewindow_cocoa.mm')
-rw-r--r-- | plugingui/nativewindow_cocoa.mm | 832 |
1 files changed, 0 insertions, 832 deletions
diff --git a/plugingui/nativewindow_cocoa.mm b/plugingui/nativewindow_cocoa.mm deleted file mode 100644 index 7b6ecc8..0000000 --- a/plugingui/nativewindow_cocoa.mm +++ /dev/null @@ -1,832 +0,0 @@ -/* -*- Mode: ObjC; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * nativewindow_cocoa.mm - * - * Fri Dec 2 20:31:03 CET 2016 - * Copyright 2016 Bent Bisballe Nyeng - * deva@aasimon.org - ****************************************************************************/ - -/* - * This file is part of DrumGizmo. - * - * DrumGizmo 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 3 of the License, or - * (at your option) any later version. - * - * DrumGizmo 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 DrumGizmo; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ -#include "nativewindow_cocoa.h" - -#include "guievent.h" - -#include <stdio.h> -#include <unistd.h> - -#import <Cocoa/Cocoa.h> - -#include "window.h" - -#include <Availability.h> - -#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED -#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101300 // Before MacOSX 10.13 (High-Sierra) -#define STYLE_MASK \ - (NSClosableWindowMask | \ - NSTitledWindowMask | \ - NSResizableWindowMask) -#define IMAGE_FLAGS \ - (kCGBitmapByteOrder32Big | \ - kCGImageAlphaPremultipliedLast) -#define EVENT_MASK \ - NSAnyEventMask -#else -#define STYLE_MASK \ - (NSWindowStyleMaskClosable | \ - NSWindowStyleMaskTitled | \ - NSWindowStyleMaskResizable) -#define IMAGE_FLAGS \ - (kCGImageByteOrder32Big | \ - kCGImageAlphaPremultipliedLast) -#define EVENT_MASK \ - NSEventMaskAny -#endif - -#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101400 // Before MacOSX 10.14 (Mojave) -// Nothing here yet... -#endif -#endif - -@interface DGListener : NSWindow -{ -@public - NSWindow* window; - GUI::NativeWindowCocoa* native; -} - -- (id) initWithWindow:(NSWindow*)ref - native:(GUI::NativeWindowCocoa*)_native; -- (void) dealloc; -- (void) windowDidResize; -- (void) windowWillResize; -- (void) windowWillClose; -- (void) unbindNative; -@end - -@implementation DGListener -- (id) initWithWindow:(NSWindow*)ref - native:(GUI::NativeWindowCocoa*)_native -{ - [super init]; - - native = _native; - window = ref; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(windowDidResize) - name:NSWindowDidResizeNotification - object:ref]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(windowWillResize) - name:NSWindowWillStartLiveResizeNotification - object:ref]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(windowWillClose) - name:NSWindowWillCloseNotification - object:ref]; - - [self windowWillResize]; // trigger to get the initial size as a size change - - return self; -} - -- (void) dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (void)windowDidResize -{ - if(!native) - { - return; - } - - native->resized(); -} - -- (void)windowWillResize -{ - if(!native) - { - return; - } - - native->resized(); -} - -- (void) windowWillClose -{ - if(!native) - { - return; - } - - auto closeEvent = std::make_shared<GUI::CloseEvent>(); - native->pushBackEvent(closeEvent); -} - -- (void) unbindNative -{ - native = nullptr; -} -@end - -@interface DGView : NSView -{ - int colorBits; - int depthBits; - -@private - GUI::NativeWindowCocoa* native; - NSTrackingArea* trackingArea; -} - -//- (id) initWithFrame:(NSRect)frame -// colorBits:(int)numColorBits -// depthBits:(int)numDepthBits; -- (void) updateTrackingAreas; - -- (void) mouseEntered:(NSEvent *)event; -- (void) mouseExited:(NSEvent *)event; -- (void) mouseMoved:(NSEvent*)event; -- (void) mouseDown:(NSEvent*)event; -- (void) mouseUp:(NSEvent*)event; -- (void) rightMouseDown:(NSEvent*)event; -- (void) rightMouseUp:(NSEvent*)event; -- (void) otherMouseDown:(NSEvent*)event; -- (void) otherMouseUp:(NSEvent*)event; -- (void) mouseDragged:(NSEvent*)event; -- (void) rightMouseDragged:(NSEvent*)event; -- (void) otherMouseDragged:(NSEvent*)event; -- (void) scrollWheel:(NSEvent*)event; -- (void) keyDown:(NSEvent*)event; -- (void) keyUp:(NSEvent*)event; - -- (void) dealloc; -- (void) bindNative:(GUI::NativeWindowCocoa*)native; -- (void) unbindNative; -@end - -@implementation DGView -//- (id) initWithFrame:(NSRect)frame -// colorBits:(int)numColorBits -// depthBits:(int)numDepthBits -//{ -// [super init]; -// [self updateTrackingAreas]; -// return self; -//} - -- (void) updateTrackingAreas -{ - if(trackingArea != nil) - { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - int opts = - NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved | - NSTrackingActiveAlways; - - trackingArea = - [[NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; -} - -- (void) mouseEntered:(NSEvent *)event -{ - [super mouseEntered:event]; - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - auto mouseEnterEvent = std::make_shared<GUI::MouseEnterEvent>(); - mouseEnterEvent->x = loc.x - frame.origin.x; - mouseEnterEvent->y = frame.size.height - loc.y - frame.origin.y; - native->pushBackEvent(mouseEnterEvent); - //[[NSCursor pointingHandCursor] set]; -} - -- (void) mouseExited:(NSEvent *)event -{ - [super mouseExited:event]; - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - auto mouseLeaveEvent = std::make_shared<GUI::MouseLeaveEvent>(); - mouseLeaveEvent->x = loc.x - frame.origin.x; - mouseLeaveEvent->y = frame.size.height - loc.y - frame.origin.y; - native->pushBackEvent(mouseLeaveEvent); - //[[NSCursor arrowCursor] set]; -} - -- (void) mouseMoved:(NSEvent*)event -{ - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - auto mouseMoveEvent = std::make_shared<GUI::MouseMoveEvent>(); - mouseMoveEvent->x = loc.x - frame.origin.x; - mouseMoveEvent->y = frame.size.height - loc.y - frame.origin.y; - native->pushBackEvent(mouseMoveEvent); -} - -- (void) mouseDown:(NSEvent*)event -{ - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - - auto buttonEvent = std::make_shared<GUI::ButtonEvent>(); - buttonEvent->x = loc.x - frame.origin.x; - buttonEvent->y = frame.size.height - loc.y - frame.origin.y; - switch((int)[event buttonNumber]) - { - case 0: - buttonEvent->button = GUI::MouseButton::left; - break; - case 1: - buttonEvent->button = GUI::MouseButton::right; - break; - case 2: - buttonEvent->button = GUI::MouseButton::middle; - break; - default: - return; - } - buttonEvent->direction = GUI::Direction::down; - buttonEvent->doubleClick = [event clickCount] == 2; - native->pushBackEvent(buttonEvent); - - [super mouseDown: event]; -} - -- (void) mouseUp:(NSEvent*)event -{ - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - - auto buttonEvent = std::make_shared<GUI::ButtonEvent>(); - buttonEvent->x = loc.x - frame.origin.x; - buttonEvent->y = frame.size.height - loc.y - frame.origin.y; - switch((int)[event buttonNumber]) - { - case 0: - buttonEvent->button = GUI::MouseButton::left; - break; - case 1: - buttonEvent->button = GUI::MouseButton::right; - break; - case 2: - buttonEvent->button = GUI::MouseButton::middle; - break; - default: - return; - } - buttonEvent->direction = GUI::Direction::up; - buttonEvent->doubleClick = false; - native->pushBackEvent(buttonEvent); - - [super mouseUp: event]; -} - -- (void) rightMouseDown:(NSEvent*)event -{ - [self mouseDown: event]; - [super rightMouseDown: event]; -} - -- (void) rightMouseUp:(NSEvent*)event -{ - [self mouseUp: event]; - [super rightMouseUp: event]; -} - -- (void) otherMouseDown:(NSEvent*)event -{ - [self mouseDown: event]; - [super otherMouseDown: event]; -} - -- (void) otherMouseUp:(NSEvent*)event -{ - [self mouseUp: event]; - [super otherMouseUp: event]; -} - -- (void) mouseDragged:(NSEvent*)event -{ - [self mouseMoved: event]; - [super mouseDragged: event]; -} - -- (void) rightMouseDragged:(NSEvent*)event -{ - [self mouseMoved: event]; - [super rightMouseDragged: event]; -} - -- (void) otherMouseDragged:(NSEvent*)event -{ - [self mouseMoved: event]; - [super otherMouseDragged: event]; -} - -- (void) scrollWheel:(NSEvent*)event -{ - auto frame = [self frame]; - NSPoint loc = [event locationInWindow]; - - auto scrollEvent = std::make_shared<GUI::ScrollEvent>(); - scrollEvent->x = loc.x - frame.origin.x; - scrollEvent->y = frame.size.height - loc.y - frame.origin.y; - scrollEvent->delta = [event deltaY] * -1.0f; - native->pushBackEvent(scrollEvent); - - [super scrollWheel: event]; -} - -- (void) keyDown:(NSEvent*)event -{ - const NSString* chars = [event characters]; - const char* str = [chars UTF8String]; - - auto keyEvent = std::make_shared<GUI::KeyEvent>(); - - switch([event keyCode]) - { - case 123: keyEvent->keycode = GUI::Key::left; break; - case 124: keyEvent->keycode = GUI::Key::right; break; - case 126: keyEvent->keycode = GUI::Key::up; break; - case 125: keyEvent->keycode = GUI::Key::down; break; - case 117: keyEvent->keycode = GUI::Key::deleteKey; break; - case 51: keyEvent->keycode = GUI::Key::backspace; break; - case 115: keyEvent->keycode = GUI::Key::home; break; - case 119: keyEvent->keycode = GUI::Key::end; break; - case 121: keyEvent->keycode = GUI::Key::pageDown; break; - case 116: keyEvent->keycode = GUI::Key::pageUp; break; - case 36: keyEvent->keycode = GUI::Key::enter; break; - default: keyEvent->keycode = GUI::Key::unknown; break; - } - - if(strlen(str) && keyEvent->keycode == GUI::Key::unknown) - { - keyEvent->keycode = GUI::Key::character; - } - - keyEvent->text = str; // TODO: UTF8 decode - keyEvent->direction = GUI::Direction::down; - - native->pushBackEvent(keyEvent); - [super keyDown: event]; -} - -- (void) keyUp:(NSEvent*)event -{ - const NSString* chars = [event characters]; - const char* str = [chars UTF8String]; - auto keyEvent = std::make_shared<GUI::KeyEvent>(); - - switch([event keyCode]) - { - case 123: keyEvent->keycode = GUI::Key::left; break; - case 124: keyEvent->keycode = GUI::Key::right; break; - case 126: keyEvent->keycode = GUI::Key::up; break; - case 125: keyEvent->keycode = GUI::Key::down; break; - case 117: keyEvent->keycode = GUI::Key::deleteKey; break; - case 51: keyEvent->keycode = GUI::Key::backspace; break; - case 115: keyEvent->keycode = GUI::Key::home; break; - case 119: keyEvent->keycode = GUI::Key::end; break; - case 121: keyEvent->keycode = GUI::Key::pageDown; break; - case 116: keyEvent->keycode = GUI::Key::pageUp; break; - case 36: keyEvent->keycode = GUI::Key::enter; break; - default: keyEvent->keycode = GUI::Key::unknown; break; - } - - if(strlen(str) && keyEvent->keycode == GUI::Key::unknown) - { - keyEvent->keycode = GUI::Key::character; - } - - keyEvent->text = str; // TODO: UTF8 decode - keyEvent->direction = GUI::Direction::up; - - native->pushBackEvent(keyEvent); - [super keyUp: event]; -} - -- (void) dealloc -{ - [super dealloc]; -} - -- (void)bindNative:(GUI::NativeWindowCocoa*)_native -{ - native = _native; -} - -- (void) unbindNative -{ - native = nullptr; -} -@end - - -namespace GUI -{ - -struct priv -{ - NSWindow* window; - DGView* view; - id listener; - id parent_view; - std::uint8_t* pixel_buffer{nullptr}; - std::size_t pixel_buffer_width{0}; - std::size_t pixel_buffer_height{0}; -}; - -NativeWindowCocoa::NativeWindowCocoa(void* native_window, Window& window) - : window(window) - , priv(new struct priv()) - , native_window(native_window) -{ - [NSAutoreleasePool new]; - [NSApplication sharedApplication]; - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - - priv->view = [DGView new]; - - [priv->view bindNative:this]; - - if(native_window) - { - if(sizeof(std::size_t) == sizeof(unsigned int)) // 32 bit machine - { - WindowRef ptr = (WindowRef)native_window; - priv->window = [[[NSWindow alloc] initWithWindowRef:ptr] retain]; - priv->parent_view = [priv->window contentView]; - } - else // 64 bit machine - { - priv->parent_view = (NSView*)native_window; - priv->window = [priv->parent_view window]; - } - - [priv->parent_view addSubview:priv->view]; - [priv->view display]; - [priv->parent_view setNeedsDisplay:YES]; - } - else - { - priv->window = - [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 10, 10) - styleMask:STYLE_MASK - backing:NSBackingStoreBuffered - defer:NO] - retain]; - [priv->window setLevel:NSStatusWindowLevel]; - } - - priv->listener = - [[[DGListener alloc] initWithWindow:priv->window - native:this] - retain]; - - if(native_window) - { - [[priv->window contentView] addSubview:priv->view]; - } - else - { - [priv->window setReleasedWhenClosed:NO]; - [priv->window setContentView:priv->view]; - } - - scale = [[NSScreen mainScreen] backingScaleFactor]; - - [priv->view setWantsLayer:YES]; - [priv->view setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft]; - [priv->view updateTrackingAreas]; - - if(!native_window) - { - hide(); - } -} - -NativeWindowCocoa::~NativeWindowCocoa() -{ - // Make the garbage collector able to collect the ObjC objects: - if(visible()) - { - hide(); - } - - [priv->listener unbindNative]; - [priv->listener release]; - - [priv->view unbindNative]; - [priv->view release]; - - if(native_window) - { - if(sizeof(std::size_t) == sizeof(unsigned int)) // 32 bit machine - { - [priv->window release]; - } - else - { - // in 64-bit the window was not created by us - } - } - else - { - [priv->window release]; - } -} - -void NativeWindowCocoa::setFixedSize(std::size_t width, std::size_t height) -{ - resize(width, height); - [priv->window setMinSize:NSMakeSize(width, height + 22)]; - [priv->window setMaxSize:NSMakeSize(width, height + 22)]; -} - -void NativeWindowCocoa::setAlwaysOnTop(bool always_on_top) -{ - if(always_on_top) - { - [priv->window setLevel: NSStatusWindowLevel]; - } - else - { - [priv->window setLevel: NSNormalWindowLevel]; - } -} - -void NativeWindowCocoa::resize(std::size_t width, std::size_t height) -{ - [priv->window setContentSize:NSMakeSize(width, height)]; -} - -std::pair<std::size_t, std::size_t> NativeWindowCocoa::getSize() const -{ - if(native_window) - { - auto frame = [priv->parent_view frame]; - return {frame.size.width, frame.size.height - frame.origin.y}; - } - else - { - NSSize size = [priv->view frame].size; - return {size.width, size.height}; - } -} - -void NativeWindowCocoa::move(int x, int y) -{ - NSRect screen = [[NSScreen mainScreen] frame]; - [priv->window setFrameTopLeftPoint:NSMakePoint(x, screen.size.height - y)]; -} - -std::pair<int, int> NativeWindowCocoa::getPosition() const -{ - NSRect screen = [[NSScreen mainScreen] frame]; - NSPoint pos = [[priv->window contentView] frame].origin; - return {pos.x, screen.size.height - pos.y}; -} - -void NativeWindowCocoa::show() -{ - if(!native_window) - { - [priv->window makeKeyAndOrderFront:priv->window]; - [NSApp activateIgnoringOtherApps:YES]; - } -} - -void NativeWindowCocoa::hide() -{ - if(!native_window) - { - [priv->window orderOut:priv->window]; - } -} - -bool NativeWindowCocoa::visible() const -{ - return [priv->window isVisible]; -} - -void NativeWindowCocoa::redraw(const Rect& dirty_rect) -{ - NSSize size; - if(native_window) - { - size = [priv->parent_view frame].size; - } - else - { - size = [priv->view frame].size; - } - - std::size_t width = size.width; - std::size_t height = size.height; - - if(priv->pixel_buffer == nullptr || - priv->pixel_buffer_width != width || - priv->pixel_buffer_height != height) - { - if(priv->pixel_buffer) delete[] priv->pixel_buffer; - priv->pixel_buffer = new std::uint8_t[width * height * 4]; - priv->pixel_buffer_width = width; - priv->pixel_buffer_height = height; - } - - CGColorSpaceRef rgb = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - CGContextRef gc = - CGBitmapContextCreate(priv->pixel_buffer, width, height, - 8, width * 4, rgb, - IMAGE_FLAGS); - CGColorSpaceRelease(rgb); - - size_t pitch = CGBitmapContextGetBytesPerRow(gc); - uint8_t *buffer = (uint8_t *)CGBitmapContextGetData(gc); - - struct Pixel - { - std::uint8_t red; - std::uint8_t green; - std::uint8_t blue; - std::uint8_t alpha; - }; - std::uint8_t* pixels = window.wpixbuf.buf; - for(std::size_t y = dirty_rect.y1; y < std::min(dirty_rect.y2, height); ++y) - { - Pixel *row = (Pixel *)(buffer + y * pitch); - for(std::size_t x = dirty_rect.x1; x < std::min(dirty_rect.x2, width); ++x) - { - row[x] = *(Pixel*)&pixels[(y * width + x) * 3]; - row[x].alpha = 0xff; - } - } - CGImageRef image = CGBitmapContextCreateImage(gc); - CGContextRelease(gc); - - auto nsImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; - - id layerContents = [nsImage layerContentsForContentsScale:scale]; - [[priv->view layer] setContents:layerContents]; - updateLayerOffset(); - [[priv->view layer] setContentsScale:scale]; -} - -void NativeWindowCocoa::setCaption(const std::string &caption) -{ - NSString* title = - [NSString stringWithCString:caption.data() - encoding:[NSString defaultCStringEncoding]]; - [priv->window setTitle:title]; -} - -void NativeWindowCocoa::grabMouse(bool grab) -{ -} - -void NativeWindowCocoa::updateLayerOffset() -{ - if(native_window) - { - //auto r1 = [priv->parent_view frame]; - auto r2 = [priv->view frame]; - - CATransform3D t = [[priv->view layer] transform]; - if(t.m42 != -r2.origin.y) - { - t.m42 = -r2.origin.y; // y - [[priv->view layer] setTransform:t]; - } - } -} - -EventQueue NativeWindowCocoa::getEvents() -{ - if(first) - { - resized(); - first = false; - } - - // If this is the root window, process the events - event processing will - // be handled by the hosting window if the window is embedded. - if(!native_window) - { - NSEvent* event = nil; - do - { - event = [NSApp nextEventMatchingMask:EVENT_MASK - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - [NSApp sendEvent:event]; - } - while(event != nil); - } - - EventQueue events; - std::swap(events, event_queue); - return events; -} - -void* NativeWindowCocoa::getNativeWindowHandle() const -{ - if(sizeof(std::size_t) == sizeof(unsigned int)) // 32 bit machine - { - return [priv->window windowRef]; - } - else // 64 bit machine - { - return [priv->window contentView]; - } -} - -Point NativeWindowCocoa::translateToScreen(const Point& point) -{ - NSRect e = [[NSScreen mainScreen] frame]; - NSRect frame; - if(native_window) - { - frame = [priv->parent_view frame]; - } - else - { - frame = [priv->view frame]; - } - - NSRect rect { { point.x + frame.origin.x, - frame.size.height - point.y + frame.origin.y}, - {0.0, 0.0} }; - rect = [priv->window convertRectToScreen:rect]; - - return { (int)rect.origin.x, (int)(e.size.height - rect.origin.y) }; -} - -Window& NativeWindowCocoa::getWindow() -{ - return window; -} - -PixelBuffer& NativeWindowCocoa::getWindowPixbuf() -{ - window.updateBuffer(); - return window.wpixbuf; -} - -void NativeWindowCocoa::resized() -{ - if(native_window) - { - NSRect frame = [priv->parent_view frame]; - [priv->view setFrame:frame]; - [priv->view updateTrackingAreas]; - updateLayerOffset(); - } - - auto resizeEvent = std::make_shared<GUI::ResizeEvent>(); - resizeEvent->width = 42; // size is not actually used - resizeEvent->height = 42; // size is not actually used - pushBackEvent(resizeEvent); -} - -void NativeWindowCocoa::pushBackEvent(std::shared_ptr<Event> event) -{ - event_queue.push_back(event); -} - -} // GUI:: |