diff options
| -rwxr-xr-x | autogen.sh | 10 | ||||
| -rw-r--r-- | configure.ac | 6 | ||||
| -rw-r--r-- | plugingui/Makefile.am | 16 | ||||
| -rw-r--r-- | plugingui/guievent.h | 2 | ||||
| -rw-r--r-- | plugingui/nativewindow_cocoa.h | 39 | ||||
| -rw-r--r-- | plugingui/nativewindow_cocoa.mm | 897 | ||||
| -rw-r--r-- | plugingui/nativewindow_win32.cc | 2 | ||||
| -rw-r--r-- | plugingui/window.h | 3 | 
8 files changed, 719 insertions, 256 deletions
| @@ -11,5 +11,15 @@ then  		exit 1  fi +# Check for support of AC_PROG_OBJCXX macro. If missing emulate it. +mkdir -p actest +cat << EOF > actest/configure.ac +AC_INIT([actest], [1.0.0]) +AC_PROG_OBJCXX +EOF +[ -f acinclude.m4 ] && rm acinclude.m4 +autoreconf -W error actest 2>/dev/null || echo "AC_DEFUN([AC_PROG_OBJCXX],[echo ' - ObjC++ hack - not support by this platform, but not needed either.'])" > acinclude.m4 +rm -Rf actest +  # Now run autoreconf  ${AUTORECONF:-autoreconf} -fiv --warnings=no-unsupported diff --git a/configure.ac b/configure.ac index 43cef1c..ff226d0 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,7 @@ AM_INIT_AUTOMAKE  AC_PROG_CXX  AC_PROG_OBJC +AC_PROG_OBJCXX  AM_PROG_CC_C_O  AC_PROG_MKDIR_P @@ -39,6 +40,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],  ]  )  CXXFLAGS="$TMP_CXXFLAGS $CXXFLAGS" +OBJCXXFLAGS="$OBJCXXFLAGS $CXXFLAGS"  AC_LANG_POP([C++])  dnl =========================== @@ -144,7 +146,7 @@ AS_IF([test "x$enable_gui" = "xyes"], [enable_gui="auto"])  AS_IF([test "x$enable_gui" = "xauto"],        [AC_MSG_RESULT([Auto setting gui based on host: $host_os])  	     AS_CASE([$host_os], -		      [darwin*], [enable_gui="pugl-cocoa"], +		      [darwin*], [enable_gui="cocoa"],  		      [linux*|*bsd*], [enable_gui="x11"],  		      [msys|mingw*|windows*|winnt|cygwin], [enable_gui="win32"], @@ -168,7 +170,7 @@ AS_IF(    [test "x$enable_gui" = "xcocoa"],    [AC_MSG_RESULT([Setting gui backend to Cocoa])    GUI_CPPFLAGS="-DUI_COCOA" -  GUI_LIBS="-framework OpenGL -framework Cocoa" +  GUI_LIBS="-framework Cocoa"  	],    [test "x$enable_gui" = "xpugl-x11"], diff --git a/plugingui/Makefile.am b/plugingui/Makefile.am index c4c2fa0..778d909 100644 --- a/plugingui/Makefile.am +++ b/plugingui/Makefile.am @@ -48,9 +48,9 @@ libdggui_la_CPPFLAGS = \  	-DLODEPNG_NO_COMPILE_CPP  libdggui_la_CFLAGS = -if ENABLE_PUGL_COCOA +  libdggui_la_LIBTOOLFLAGS=--tag=CC -endif +  libdggui_la_LIBADD = \  	$(GUI_LIBS) $(PTHREAD_LIBS) @@ -125,11 +125,13 @@ nodist_libdggui_la_SOURCES += \  	nativewindow_win32.cc  endif -#if ENABLE_COCOA -#nodist_libdggui_la_SOURCES += \ -#	nativewindow_cocoa.m \ -#	nativewindow_cocoa.cc -#endif +if ENABLE_COCOA +nodist_libdggui_la_SOURCES += \ +	nativewindow_cocoa.mm + +libdggui_la_OBJCXXFLAGS = \ +	-fblocks +endif  if ENABLE_PUGL_X11  nodist_libdggui_la_SOURCES += \ diff --git a/plugingui/guievent.h b/plugingui/guievent.h index fe51826..fa42483 100644 --- a/plugingui/guievent.h +++ b/plugingui/guievent.h @@ -103,7 +103,7 @@ public:  	int x;  	int y; -	int delta; +	float delta;  };  class RepaintEvent diff --git a/plugingui/nativewindow_cocoa.h b/plugingui/nativewindow_cocoa.h index 100b3c7..3f0518a 100644 --- a/plugingui/nativewindow_cocoa.h +++ b/plugingui/nativewindow_cocoa.h @@ -26,6 +26,8 @@   */  #pragma once +#include <memory> +  #include "nativewindow.h"  namespace GUI @@ -40,21 +42,34 @@ public:  	~NativeWindowCocoa();  	// From NativeWindow: -	void setFixedSize(int width, int height) override; -	void resize(int width, int height) override; -	void move(int x, int y) override; -	void show() override; -	void hide() override; -	void setCaption(const std::string &caption) override; -	void handleBuffer() override; -	void redraw() override; -	void grabMouse(bool grab) override; -	bool hasEvent() override; -	std::shared_ptr<Event> getNextEvent() override; -	std::shared_ptr<Event> peekNextEvent() override; +	virtual void setFixedSize(std::size_t width, std::size_t height) override; +	virtual void resize(std::size_t width, std::size_t height) override; +	virtual std::pair<std::size_t, std::size_t> getSize() const override; +	virtual void move(int x, int y) override; +	virtual std::pair<int, int> getPosition() const override; +	virtual void show() override; +	virtual void hide() override; +	virtual bool visible() const override; +	virtual void setCaption(const std::string &caption) override; +	virtual void redraw(const Rect& dirty_rect) override; +	virtual void grabMouse(bool grab) override; +	virtual EventQueue getEvents() override; +	virtual void* getNativeWindowHandle() const override; + +	// Expose friend members of Window to ObjC++ implementation. +	class Window& getWindow(); +	class PixelBuffer& getWindowPixbuf(); +	void resized(); +	void pushBackEvent(std::shared_ptr<Event> event);  private: +	void updateLayerOffset(); +  	Window& window; +	std::unique_ptr<struct priv> priv; +	EventQueue event_queue; +	void* native_window{nullptr}; +	bool first{true};  };  } // GUI:: diff --git a/plugingui/nativewindow_cocoa.mm b/plugingui/nativewindow_cocoa.mm index 531c2a8..aaacd0e 100644 --- a/plugingui/nativewindow_cocoa.mm +++ b/plugingui/nativewindow_cocoa.mm @@ -24,337 +24,770 @@   *  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" -/* - -loop: -http://stackoverflow.com/questions/6732400/cocoa-integrate-nsapplication-into-an-existing-c-mainloop - -draw pixels: -http://stackoverflow.com/questions/10955913/how-can-i-display-an-array-of-pixels-on-a-nswindow -*/ +#include "guievent.h"  #include <stdio.h>  #include <unistd.h>  #import <Cocoa/Cocoa.h> -bool running = true; +#include "window.h" -@interface MyWindow : NSWindow +#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 -  //  MyView* my_view; +	NSWindow* window; +	GUI::NativeWindowCocoa* native;  } -- (id) initWithContentRect:(NSRect)contentRect -                 styleMask:(unsigned int)aStyle -                   backing:(NSBackingStoreType)bufferingType -                     defer:(BOOL)flag; -//- (void) setMyView:(MyView*)view; -- (BOOL) windowShouldClose:(id)sender; -- (void) mouseMoved:(NSEvent*)event; -- (void) drawRect:(NSRect)dirtyRect; +- (id) initWithWindow:(NSWindow*)ref +               native:(GUI::NativeWindowCocoa*)_native; +- (void) dealloc; +- (void) windowDidResize; +- (void) windowWillResize; +- (void) windowWillClose; +- (void) unbindNative;  @end -@implementation MyWindow +@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; +} -- (id)initWithContentRect:(NSRect)contentRect -                styleMask:(unsigned int)aStyle -                  backing:(NSBackingStoreType)bufferingType -                    defer:(BOOL)flag +- (void) dealloc  { -        NSWindow* result = [super initWithContentRect:contentRect -                                            styleMask:(NSClosableWindowMask | -                                                       NSTitledWindowMask | -                                                       NSResizableWindowMask) -                                              backing:NSBackingStoreBuffered defer:NO]; +	[[NSNotificationCenter defaultCenter] removeObserver:self]; +	[super dealloc]; +} + +- (void)windowDidResize +{ +	if(!native) +	{ +		return; +	} + +	native->resized(); +} + +- (void)windowWillResize +{ +	if(!native) +	{ +		return; +	} + +	native->resized(); +} -        [result setAcceptsMouseMovedEvents:YES]; -        [result setLevel: CGShieldingWindowLevel() + 1]; +- (void) windowWillClose +{ +	if(!native) +	{ +		return; +	} -        return result; +	auto closeEvent = std::make_shared<GUI::CloseEvent>(); +	native->pushBackEvent(closeEvent);  } -//- (void)setMyView:(MyView*)view +- (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  //{ -//  //my_view = view; -//      //[self setContentSize:NSMakeSize(view->width, view->height) ]; +//	[super init]; +//	[self updateTrackingAreas]; +//	return self;  //} -- (BOOL)windowShouldClose:(id)sender +- (void) updateTrackingAreas  { -  printf("closing!\n"); -  //if (puglview->closeFunc) -  //            puglview->closeFunc(puglview); -  running = false; -  return YES; +	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];  } -#define WIDTH 100 -#define HEIGHT 100 -#define SIZE (WIDTH*HEIGHT) -#define BYTES_PER_PIXEL 2 -#define BITS_PER_COMPONENT 5 -#define BITS_PER_PIXEL 16 +- (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)drawRect:(NSRect)dirtyRect +- (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  { -  /* -        if (puglview->motionFunc) { -                NSPoint loc = [event locationInWindow]; -                puglview->mods = getModifiers(puglview, event); -                puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); -        } -  */ -  NSPoint loc = [event locationInWindow]; -  printf("mouseMove: %f %f\n", loc.x, loc.y); +	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);  } -@end +- (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]; +} -@interface MyView : NSView +- (void) otherMouseDown:(NSEvent*)event  { -        int colorBits; -        int depthBits; -@public -  //PuglView* puglview; +	[self mouseDown: event]; +	[super otherMouseDown: event]; +} -  NSTrackingArea* trackingArea; +- (void) otherMouseUp:(NSEvent*)event +{ +	[self mouseUp: event]; +	[super otherMouseUp: event];  } -- (id) initWithFrame:(NSRect)frame -           colorBits:(int)numColorBits -           depthBits:(int)numDepthBits; -- (void) reshape; -- (void) drawRect:(NSRect)rect; +- (void) mouseDragged:(NSEvent*)event +{ +	[self mouseMoved: event]; +	[super mouseDragged: event]; +} -@end -@implementation MyView - -- (id) initWithFrame:(NSRect)frame -           colorBits:(int)numColorBits -           depthBits:(int)numDepthBits -{ -  colorBits = numColorBits; -  depthBits = numDepthBits; - -  //NSOpenGLPixelFormatAttribute pixelAttribs[16] = { -  //  NSOpenGLPFADoubleBuffer, -  //  NSOpenGLPFAAccelerated, -  //  NSOpenGLPFAColorSize, -  //  colorBits, -  //  NSOpenGLPFADepthSize, -  //  depthBits, -  //  0 -  //}; -  // -  //NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] -  //            initWithAttributes:pixelAttribs]; -  // -  //if (pixelFormat) { -  //  self = [super initWithFrame:frame pixelFormat:pixelFormat]; -  //  [pixelFormat release]; -  //  if (self) { -  //    [[self openGLContext] makeCurrentContext]; -  //    [self reshape]; -  //  } -  //} else { -  //  self = nil; -  //} - -  return self; -} -- (void) reshape -{ -  //[[self openGLContext] update]; -  // -  //NSRect bounds = [self bounds]; -  //int    width  = bounds.size.width; -  //int    height = bounds.size.height; -  // -  //if (puglview) { -  //  /* NOTE: Apparently reshape gets called when the GC gets around to -  //     deleting the view (?), so we must have reset puglview to NULL when -  //     this comes around. -  //  */ -  //  if (puglview->reshapeFunc) { -  //    puglview->reshapeFunc(puglview, width, height); -  //  } else { -  //    puglDefaultReshape(puglview, width, height); -  //  } -  // -  //  puglview->width  = width; -  //  puglview->height = height; -  //} -} -- (void) drawRect:(NSRect)rect -{ -  printf("drawRect\n"); - -  // Get current context -  CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - -  // Colorspace RGB -  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - -  // Pixel Matrix allocation -  unsigned short *pixels = calloc(SIZE, sizeof(unsigned short)); - -  // Random pixels will give you a non-organized RAINBOW -  for (int i = 0; i < WIDTH; i++) { -    for (int j = 0; j < HEIGHT; j++) { -      pixels[i+ j*HEIGHT] = arc4random() % USHRT_MAX; -    } -  } - -  // Provider -  CGDataProviderRef provider = CGDataProviderCreateWithData(nil, pixels, SIZE, nil); - -  // CGImage -  CGImageRef image = CGImageCreate(WIDTH, -            HEIGHT, -            BITS_PER_COMPONENT, -            BITS_PER_PIXEL, -            BYTES_PER_PIXEL*WIDTH, -            colorSpace, -            kCGImageAlphaNoneSkipFirst, -            // xRRRRRGGGGGBBBBB - 16-bits, first bit is ignored! -            provider, -            nil, //No decode -            NO,  //No interpolation -            kCGRenderingIntentDefault); // Default rendering - -  // Draw -  CGContextDrawImage(context, CGRectMake(0, 0, WIDTH, HEIGHT), image); - -  // Once everything is written on screen we can release everything -  CGImageRelease(image); -  CGColorSpaceRelease(colorSpace); -  CGDataProviderRelease(provider); +- (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 -#include "window.h"  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) -	: buffer(nullptr) -	, window(window) -{ -  [NSAutoreleasePool new]; -  [NSApplication sharedApplication]; -  [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; -  /* -  id menubar = [[NSMenu new] autorelease]; -  id appMenuItem = [[NSMenuItem new] autorelease]; -  [menubar addItem:appMenuItem]; -  [NSApp setMainMenu:menubar]; -  id appMenu = [[NSMenu new] autorelease]; -  id appName = [[NSProcessInfo processInfo] processName]; -  id quitTitle = [@"Quit " stringByAppendingString:appName]; -  id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle -    action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; -  [appMenu addItem:quitMenuItem]; -  [appMenuItem setSubmenu:appMenu]; -  */ -  id window = [[[MyWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) -          styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO] -  autorelease]; -  [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; -  //  [window setTitle:appName]; -  [window makeKeyAndOrderFront:nil]; - -  id my_view       = [MyView new]; -  [window setContentView:my_view]; -  [NSApp activateIgnoringOtherApps:YES]; -  [window makeFirstResponder:my_view]; - -  //  [NSApp run]; +	: 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]; +	} + +	[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::setFixedSize(int width, int height) +void NativeWindowCocoa::resize(std::size_t width, std::size_t height)  { +	[priv->window setContentSize:NSMakeSize(width, height)];  } -void NativeWindowCocoa::resize(int width, int 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)  { +	[priv->window setFrameTopLeftPoint:NSMakePoint(x, y)]; +} + +std::pair<int, int> NativeWindowCocoa::getPosition() const +{ +	NSPoint pos = [[priv->window contentView] frame].origin; +	return {pos.x, 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]; +	}  } -void NativeWindowCocoa::handleBuffer() +bool NativeWindowCocoa::visible() const  { +	return [priv->window isVisible];  } -void NativeWindowCocoa::redraw() +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); + +	[[priv->view layer] setContents:(__bridge id)image]; + +	updateLayerOffset();  }  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)  {  } -bool NativeWindowCocoa::hasEvent() +void NativeWindowCocoa::updateLayerOffset()  { -	return false; +	if(native_window) +	{ +		auto r1 = [priv->parent_view frame]; +		auto r2 = [priv->view frame]; + +		CATransform3D t = [[priv->view layer] transform]; +		if(t.m42 != -r1.origin.y) +		{ +			t.m42 = -r1.origin.y; // y +			[[priv->view layer] setTransform:t]; +		} +	}  } -std::shared_ptr<Event> NativeWindowCocoa::getNextEvent() +EventQueue NativeWindowCocoa::getEvents()  { -  //[window setNeedsDisplay: YES]; - -  while(running) { -    NSEvent * event; - -    do -      { -        event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefa\ -ultRunLoopMode dequeue:YES]; - +	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; +} -        //Convert the cocoa events to something useful here and add them to your own event queue +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]; +	} +} -        [NSApp sendEvent: event]; -      } -    while(event != nil); +Window& NativeWindowCocoa::getWindow() +{ +	return window; +} -    //printf("loop\n"); -    usleep(10000); -  } +PixelBuffer& NativeWindowCocoa::getWindowPixbuf() +{ +	window.updateBuffer(); +	return window.wpixbuf; +} -	return nullptr; +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);  } -std::shared_ptr<Event> NativeWindowCocoa::peekNextEvent() +void NativeWindowCocoa::pushBackEvent(std::shared_ptr<Event> event)  { -	return nullptr; +	event_queue.push_back(event); +	redraw({});  }  } // GUI:: diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc index 0dc30de..12d430f 100644 --- a/plugingui/nativewindow_win32.cc +++ b/plugingui/nativewindow_win32.cc @@ -129,7 +129,7 @@ LRESULT CALLBACK NativeWindowWin32::dialogProc(HWND hwnd, UINT msg,  			scrollEvent->x = p.x;  			scrollEvent->y = p.y; -			scrollEvent->delta = -1 * (short)HIWORD(wp) / 60; +			scrollEvent->delta = -1 * (short)HIWORD(wp) / 60.0f;  			native->event_queue.push_back(scrollEvent);  		}  		break; diff --git a/plugingui/window.h b/plugingui/window.h index 218beec..e5bc496 100644 --- a/plugingui/window.h +++ b/plugingui/window.h @@ -90,10 +90,11 @@ protected:  	// For the Painter  	friend class Widget; -	// For the NativeWindow +	// For the NativeWindow implementations:  	friend class NativeWindowX11;  	friend class NativeWindowWin32;  	friend class NativeWindowPugl; +	friend class NativeWindowCocoa;  	PixelBuffer wpixbuf;  	size_t refcount{0}; | 
