summaryrefslogtreecommitdiff
path: root/libs/gtkmm2ext
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-03-20 04:21:08 +0100
committerRobin Gareus <robin@gareus.org>2017-03-20 04:35:05 +0100
commitb5e613d453921f87d59a911bd555e96e46abc5cc (patch)
tree366a800d3163757ac5d9d50da10afdd654f43022 /libs/gtkmm2ext
parentb726255007bfdafb29c547bafd71bbe32d11f58e (diff)
Move NSGlView into libgtkmm2ext
This allows to re-use the concept with CairoWidget
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/cairo_canvas.h38
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/nsglview.h15
-rw-r--r--libs/gtkmm2ext/nsglview.mm284
-rw-r--r--libs/gtkmm2ext/wscript2
4 files changed, 338 insertions, 1 deletions
diff --git a/libs/gtkmm2ext/gtkmm2ext/cairo_canvas.h b/libs/gtkmm2ext/gtkmm2ext/cairo_canvas.h
new file mode 100644
index 0000000000..7dd9d44b44
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/cairo_canvas.h
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) 2009 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtk2_ardour_cairo_canvas_h__
+#define __gtk2_ardour_cairo_canvas_h__
+
+#include <cairomm/context.h>
+#include "gtkmm2ext/visibility.h"
+
+namespace Gtkmm2ext {
+
+class LIBGTKMM2EXT_API CairoCanvas
+{
+public:
+ virtual ~CairoCanvas () {}
+
+ virtual void render (Cairo::RefPtr<Cairo::Context> const&, cairo_rectangle_t*) = 0;
+ virtual uint32_t background_color () = 0;
+};
+
+} /* namespace */
+#endif
diff --git a/libs/gtkmm2ext/gtkmm2ext/nsglview.h b/libs/gtkmm2ext/gtkmm2ext/nsglview.h
new file mode 100644
index 0000000000..8a175f3322
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/nsglview.h
@@ -0,0 +1,15 @@
+#ifndef __CANVAS_NSGLVIEW_H__
+#define __CANVAS_NSGLVIEW_H__
+
+#include <gdk/gdk.h>
+
+namespace Gtkmm2ext
+{
+ class CairoCanvas;
+
+ void* nsglview_create (CairoCanvas*);
+ void nsglview_overlay (void*, GdkWindow*);
+ void nsglview_resize (void*, int x, int y, int w, int h);
+ void nsglview_queue_draw (void*, int x, int y, int w, int h);
+}
+#endif
diff --git a/libs/gtkmm2ext/nsglview.mm b/libs/gtkmm2ext/nsglview.mm
new file mode 100644
index 0000000000..a9842935e7
--- /dev/null
+++ b/libs/gtkmm2ext/nsglview.mm
@@ -0,0 +1,284 @@
+/*
+ Copyright (C) 2011 Paul Davis
+ Copyright (C) 2012 David Robillard <http://drobilla.net>
+ Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/* include order matter due to apple defines */
+#include <gtkmm/window.h>
+
+#include "gtkmm2ext/cairo_canvas.h"
+#include "gtkmm2ext/nsglview.h"
+#include "gtkmm2ext/rgb_macros.h"
+
+#include <gdk/gdkquartz.h>
+
+#include <OpenGL/gl.h>
+#import <Cocoa/Cocoa.h>
+
+#ifndef ARDOUR_CANVAS_NSVIEW_TAG
+#define ARDOUR_CANVAS_NSVIEW_TAG 0xa2d0c2c4
+#endif
+
+__attribute__ ((visibility ("hidden")))
+@interface ArdourCanvasOpenGLView : NSOpenGLView
+{
+@private
+ unsigned int _texture_id;
+ int _width;
+ int _height;
+ Cairo::RefPtr<Cairo::ImageSurface> surf;
+ Gtkmm2ext::CairoCanvas *cairo_canvas;
+}
+
+@property (readwrite) NSInteger tag;
+
+- (id) initWithFrame:(NSRect)frame;
+- (void) dealloc;
+- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c;
+- (void) reshape;
+- (void) drawRect:(NSRect)rect;
+- (BOOL) canBecomeKeyWindow:(id)sender;
+- (BOOL) acceptsFirstResponder:(id)sender;
+
+@end
+
+@implementation ArdourCanvasOpenGLView
+
+@synthesize tag = _tag;
+
+- (id) initWithFrame:(NSRect)frame
+{
+ NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAColorSize, 32,
+ NSOpenGLPFADepthSize, 32,
+ NSOpenGLPFAMultisample,
+ NSOpenGLPFASampleBuffers, 1,
+ NSOpenGLPFASamples, 4,
+ 0
+ };
+
+ NSOpenGLPixelFormat* pixelFormat =
+ [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];
+
+ if (pixelFormat) {
+ self = [super initWithFrame:frame pixelFormat:pixelFormat];
+ [pixelFormat release];
+ } else {
+ self = [super initWithFrame:frame];
+ }
+
+ _texture_id = 0;
+ _width = 0;
+ _height = 0;
+
+ if (self) {
+ self.tag = ARDOUR_CANVAS_NSVIEW_TAG;
+ [[self openGLContext] makeCurrentContext];
+ glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
+ glDisable (GL_DEPTH_TEST);
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ [NSOpenGLContext clearCurrentContext];
+
+ [self reshape];
+ }
+
+ return self;
+}
+
+- (void) dealloc {
+ [[self openGLContext] makeCurrentContext];
+ glDeleteTextures (1, &_texture_id);
+ [NSOpenGLContext clearCurrentContext];
+
+ [super dealloc];
+}
+
+- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c
+{
+ cairo_canvas = c;
+}
+
+- (BOOL) canBecomeKeyWindow:(id)sender{
+ return NO;
+}
+
+- (BOOL) acceptsFirstResponder:(id)sender{
+ return NO;
+}
+
+- (void) reshape
+{
+ [[self openGLContext] update];
+
+ NSRect bounds = [self bounds];
+ int width = bounds.size.width;
+ int height = bounds.size.height;
+
+ if (_width == width && _height == height) {
+ return;
+ }
+
+ [[self openGLContext] makeCurrentContext];
+
+ glViewport (0, 0, width, height);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho (-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
+
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ glDeleteTextures (1, &_texture_id);
+ glGenTextures (1, &_texture_id);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture_id);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ [NSOpenGLContext clearCurrentContext];
+
+ _width = width;
+ _height = height;
+}
+
+- (void) drawRect:(NSRect)rect
+{
+ [[self openGLContext] makeCurrentContext];
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* call back into CairoCanvas */
+ cairo_rectangle_t cairo_rect;
+
+ cairo_rect.x = rect.origin.x;
+ cairo_rect.y = rect.origin.y;
+ cairo_rect.width = rect.size.width;
+ cairo_rect.height = rect.size.height;
+
+ if (!surf || surf->get_width () != _width || surf->get_height() != _height) {
+ surf = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _width, _height);
+
+ cairo_rect.x = 0;
+ cairo_rect.y = 0;
+ cairo_rect.width = _width;
+ cairo_rect.height = _height;
+ }
+
+ Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create (surf);
+
+ // TODO: check retina screen, scaling factor.
+ // cairo_surface_get_device_scale () or explicit scale
+
+ ctx->rectangle (cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height);
+ ctx->clip_preserve ();
+ {
+ /* draw background color */
+ uint32_t col = cairo_canvas->background_color ();
+ int r, g, b, a;
+ UINT_TO_RGBA (col, &r, &g, &b, &a);
+ ctx->set_source_rgba (r/255.0, g/255.0, b/255.0, a/255.0);
+ }
+ ctx->fill ();
+
+ cairo_canvas->render (ctx, &cairo_rect);
+
+ surf->flush ();
+ uint8_t* imgdata = surf->get_data ();
+
+ /* NOTE for big-endian (PPC), we'd need to flip byte-order
+ * RGBA <> RGBA for the texture.
+ * GtkCanvas does not use this nsview for PPC builds, yet
+ */
+
+ /* continue OpenGL */
+ glPushMatrix ();
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture_id);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ _width, _height, /*border*/ 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, imgdata);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f( 0.0f, (GLfloat) _height);
+ glVertex2f(-1.0f, -1.0f);
+
+ glTexCoord2f((GLfloat) _width, (GLfloat) _height);
+ glVertex2f( 1.0f, -1.0f);
+
+ glTexCoord2f((GLfloat) _width, 0.0f);
+ glVertex2f( 1.0f, 1.0f);
+
+ glTexCoord2f( 0.0f, 0.0f);
+ glVertex2f(-1.0f, 1.0f);
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glPopMatrix();
+
+ ///
+
+ glFlush();
+ glSwapAPPLE();
+ [NSOpenGLContext clearCurrentContext];
+}
+@end
+
+
+void*
+Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas)
+{
+ ArdourCanvasOpenGLView* gl_view = [ArdourCanvasOpenGLView new];
+ if (!gl_view) {
+ return 0;
+ }
+ [gl_view setCairoCanvas:canvas];
+ return gl_view;
+}
+
+void
+Gtkmm2ext::nsglview_overlay (void* glv, GdkWindow* window)
+{
+ ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
+ NSView* view = gdk_quartz_window_get_nsview (window);
+ [view addSubview:gl_view];
+}
+
+void
+Gtkmm2ext::nsglview_resize (void* glv, int x, int y, int w, int h)
+{
+ ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
+ [gl_view setFrame:NSMakeRect(x, y, w, h)];
+}
+
+void
+Gtkmm2ext::nsglview_queue_draw (void* glv, int x, int y, int w, int h)
+{
+ ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
+ [gl_view setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
+}
diff --git a/libs/gtkmm2ext/wscript b/libs/gtkmm2ext/wscript
index 4e1a031906..ef13e60071 100644
--- a/libs/gtkmm2ext/wscript
+++ b/libs/gtkmm2ext/wscript
@@ -118,7 +118,7 @@ def build(bld):
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"']
if sys.platform == 'darwin':
- obj.source += ['gtkapplication_quartz.mm']
+ obj.source += ['gtkapplication_quartz.mm', 'nsglview.mm']
else:
obj.source += ['gtkapplication_x11.c']