diff options
Diffstat (limited to 'src/cocoa_in_gtk2.mm')
-rw-r--r-- | src/cocoa_in_gtk2.mm | 587 |
1 files changed, 297 insertions, 290 deletions
diff --git a/src/cocoa_in_gtk2.mm b/src/cocoa_in_gtk2.mm index 9c6314d..2052bc0 100644 --- a/src/cocoa_in_gtk2.mm +++ b/src/cocoa_in_gtk2.mm @@ -20,349 +20,357 @@ #include "lv2/options/options.h" #include "lv2/urid/urid.h" -#include <gtk/gtk.h> #include <gdk/gdkquartz.h> +#include <gtk/gtk.h> #include <string.h> #ifndef MAC_OS_X_VERSION_10_12 -#define MAC_OS_X_VERSION_10_12 101200 +# define MAC_OS_X_VERSION_10_12 101200 #endif #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -#define NSEventTypeFlagsChanged NSFlagsChanged -#define NSEventTypeLeftMouseDown NSLeftMouseDown -#define NSEventTypeLeftMouseDragged NSLeftMouseDragged -#define NSEventTypeLeftMouseUp NSLeftMouseUp -#define NSEventTypeMouseEntered NSMouseEntered -#define NSEventTypeMouseExited NSMouseExited -#define NSEventTypeMouseMoved NSMouseMoved -#define NSEventTypeRightMouseDown NSRightMouseDown -#define NSEventTypeRightMouseUp NSRightMouseUp -#define NSEventTypeScrollWheel NSScrollWheel +# define NSEventTypeFlagsChanged NSFlagsChanged +# define NSEventTypeLeftMouseDown NSLeftMouseDown +# define NSEventTypeLeftMouseDragged NSLeftMouseDragged +# define NSEventTypeLeftMouseUp NSLeftMouseUp +# define NSEventTypeMouseEntered NSMouseEntered +# define NSEventTypeMouseExited NSMouseExited +# define NSEventTypeMouseMoved NSMouseMoved +# define NSEventTypeRightMouseDown NSRightMouseDown +# define NSEventTypeRightMouseUp NSRightMouseUp +# define NSEventTypeScrollWheel NSScrollWheel #endif extern "C" { #define SUIL_TYPE_COCOA_WRAPPER (suil_cocoa_wrapper_get_type()) -#define SUIL_COCOA_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_COCOA_WRAPPER, SuilCocoaWrapper)) +#define SUIL_COCOA_WRAPPER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_COCOA_WRAPPER, SuilCocoaWrapper)) typedef struct _SuilCocoaWrapper SuilCocoaWrapper; typedef struct _SuilCocoaWrapperClass SuilCocoaWrapperClass; struct _SuilCocoaWrapper { - GtkWidget widget; - SuilWrapper* wrapper; - SuilInstance* instance; - - GdkWindow* flt_win; - bool custom_size; - bool mapped; - int req_width; - int req_height; - int alo_width; - int alo_height; - - const LV2UI_Idle_Interface* idle_iface; - guint idle_id; - guint idle_ms; + GtkWidget widget; + SuilWrapper* wrapper; + SuilInstance* instance; + + GdkWindow* flt_win; + bool custom_size; + bool mapped; + int req_width; + int req_height; + int alo_width; + int alo_height; + + const LV2UI_Idle_Interface* idle_iface; + guint idle_id; + guint idle_ms; }; struct _SuilCocoaWrapperClass { - GtkWidgetClass parent_class; + GtkWidgetClass parent_class; }; -GType suil_cocoa_wrapper_get_type(void); // Accessor for SUIL_TYPE_COCOA_WRAPPER +GType +suil_cocoa_wrapper_get_type(void); // Accessor for SUIL_TYPE_COCOA_WRAPPER G_DEFINE_TYPE(SuilCocoaWrapper, suil_cocoa_wrapper, GTK_TYPE_WIDGET) static void suil_cocoa_wrapper_finalize(GObject* gobject) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(gobject); + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(gobject); - self->wrapper->impl = NULL; + self->wrapper->impl = NULL; - G_OBJECT_CLASS(suil_cocoa_wrapper_parent_class)->finalize(gobject); + G_OBJECT_CLASS(suil_cocoa_wrapper_parent_class)->finalize(gobject); } static void suil_cocoa_realize(GtkWidget* widget) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - g_return_if_fail(self != NULL); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - - GdkWindowAttr attrs; - attrs.x = widget->allocation.x; - attrs.y = widget->allocation.y; - attrs.width = widget->allocation.width; - attrs.height = widget->allocation.height; - attrs.wclass = GDK_INPUT_OUTPUT; - attrs.window_type = GDK_WINDOW_CHILD; - attrs.visual = gtk_widget_get_visual(widget); - attrs.colormap = gtk_widget_get_colormap(widget); - attrs.event_mask = gtk_widget_get_events(widget) | - GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK; - - widget->window = gdk_window_new( - widget->parent->window, - &attrs, - GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); - gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE); - gtk_widget_queue_resize(widget); + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + g_return_if_fail(self != NULL); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + + GdkWindowAttr attrs; + attrs.x = widget->allocation.x; + attrs.y = widget->allocation.y; + attrs.width = widget->allocation.width; + attrs.height = widget->allocation.height; + attrs.wclass = GDK_INPUT_OUTPUT; + attrs.window_type = GDK_WINDOW_CHILD; + attrs.visual = gtk_widget_get_visual(widget); + attrs.colormap = gtk_widget_get_colormap(widget); + attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; + + widget->window = + gdk_window_new(widget->parent->window, + &attrs, + GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); + gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE); + gtk_widget_queue_resize(widget); } static void suil_cocoa_size_request(GtkWidget* widget, GtkRequisition* requisition) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - if (self->custom_size) { - requisition->width = self->req_width; - requisition->height = self->req_height; - } else { - NSView* view = (NSView*)self->instance->ui_widget; - NSRect frame = [view frame]; - requisition->width = CGRectGetWidth(NSRectToCGRect(frame)); - requisition->height = CGRectGetHeight(NSRectToCGRect(frame)); - } + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + if (self->custom_size) { + requisition->width = self->req_width; + requisition->height = self->req_height; + } else { + NSView* view = (NSView*)self->instance->ui_widget; + NSRect frame = [view frame]; + requisition->width = CGRectGetWidth(NSRectToCGRect(frame)); + requisition->height = CGRectGetHeight(NSRectToCGRect(frame)); + } } static void suil_cocoa_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - self->alo_width = allocation->width; - self->alo_height = allocation->height; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + self->alo_width = allocation->width; + self->alo_height = allocation->height; - if (!self->mapped) { - return; - } + if (!self->mapped) { + return; + } - gint xx, yy; - gtk_widget_translate_coordinates( - gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy); + gint xx, yy; + gtk_widget_translate_coordinates( + gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy); - NSView* view = (NSView*)self->instance->ui_widget; - [view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)]; + NSView* view = (NSView*)self->instance->ui_widget; + [view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)]; } static void suil_cocoa_map(GtkWidget* widget) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - self->mapped = true; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + self->mapped = true; - if (self->alo_width == 0 || self->alo_height ==0) { - return; - } + if (self->alo_width == 0 || self->alo_height == 0) { + return; + } - gint xx, yy; - gtk_widget_translate_coordinates( - gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy); + gint xx, yy; + gtk_widget_translate_coordinates( + gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy); - NSView* view = (NSView*)self->instance->ui_widget; - [view setHidden:NO]; - [view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)]; + NSView* view = (NSView*)self->instance->ui_widget; + [view setHidden:NO]; + [view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)]; } static void suil_cocoa_unmap(GtkWidget* widget) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - NSView* view = (NSView*)self->instance->ui_widget; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + NSView* view = (NSView*)self->instance->ui_widget; - self->mapped = false; - [view setHidden:YES]; + self->mapped = false; + [view setHidden:YES]; } static gboolean suil_cocoa_key_press(GtkWidget* widget, GdkEventKey* event) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - if (!self->instance || !self->wrapper || !self->wrapper->impl) { - return FALSE; - } - NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event); - NSView* view = (NSView*)self->instance->ui_widget; - [view keyDown:nsevent]; - return TRUE; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + if (!self->instance || !self->wrapper || !self->wrapper->impl) { + return FALSE; + } + + NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event); + NSView* view = (NSView*)self->instance->ui_widget; + [view keyDown:nsevent]; + return TRUE; } static gboolean suil_cocoa_key_release(GtkWidget* widget, GdkEventKey* event) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - if (!self->instance || !self->wrapper || !self->wrapper->impl) { - return FALSE; - } - NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event); - NSView* view = (NSView*)self->instance->ui_widget; - [view keyUp:nsevent]; - return TRUE; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + if (!self->instance || !self->wrapper || !self->wrapper->impl) { + return FALSE; + } + + NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event); + NSView* view = (NSView*)self->instance->ui_widget; + [view keyUp:nsevent]; + return TRUE; } static gboolean suil_cocoa_expose(GtkWidget* widget, GdkEventExpose* event) { - SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); - NSView* view = (NSView*)self->instance->ui_widget; - [view drawRect:NSMakeRect(event->area.x, - event->area.y, - event->area.width, - event->area.height)]; - return TRUE; + SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget); + NSView* view = (NSView*)self->instance->ui_widget; + [view drawRect:NSMakeRect(event->area.x, + event->area.y, + event->area.width, + event->area.height)]; + return TRUE; } static void suil_cocoa_wrapper_class_init(SuilCocoaWrapperClass* klass) { - GObjectClass* const gobject_class = G_OBJECT_CLASS(klass); - GtkWidgetClass* const widget_class = (GtkWidgetClass*)(klass); - - gobject_class->finalize = suil_cocoa_wrapper_finalize; - - widget_class->realize = suil_cocoa_realize; - widget_class->expose_event = suil_cocoa_expose; - widget_class->size_request = suil_cocoa_size_request; - widget_class->size_allocate = suil_cocoa_size_allocate; - widget_class->map = suil_cocoa_map; - widget_class->unmap = suil_cocoa_unmap; - widget_class->key_press_event = suil_cocoa_key_press; - widget_class->key_release_event = suil_cocoa_key_release; + GObjectClass* const gobject_class = G_OBJECT_CLASS(klass); + GtkWidgetClass* const widget_class = (GtkWidgetClass*)(klass); + + gobject_class->finalize = suil_cocoa_wrapper_finalize; + + widget_class->realize = suil_cocoa_realize; + widget_class->expose_event = suil_cocoa_expose; + widget_class->size_request = suil_cocoa_size_request; + widget_class->size_allocate = suil_cocoa_size_allocate; + widget_class->map = suil_cocoa_map; + widget_class->unmap = suil_cocoa_unmap; + widget_class->key_press_event = suil_cocoa_key_press; + widget_class->key_release_event = suil_cocoa_key_release; } static void suil_cocoa_wrapper_init(SuilCocoaWrapper* self) { - self->wrapper = NULL; - self->instance = NULL; - self->flt_win = NULL; - self->custom_size = false; - self->mapped = false; - self->req_width = self->req_height = 0; - self->alo_width = self->alo_height = 0; - self->idle_iface = NULL; - self->idle_ms = 1000 / 30; // 30 Hz default + self->wrapper = NULL; + self->instance = NULL; + self->flt_win = NULL; + self->custom_size = false; + self->mapped = false; + self->req_width = 0; + self->req_height = 0; + self->alo_width = 0; + self->alo_height = 0; + self->idle_iface = NULL; + self->idle_ms = 1000 / 30; // 30 Hz default } static int wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) { - SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(handle); - wrap->req_width = width; - wrap->req_height = height; - wrap->custom_size = true; - gtk_widget_queue_resize(GTK_WIDGET(handle)); - return 0; + SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(handle); + + wrap->req_width = width; + wrap->req_height = height; + wrap->custom_size = true; + + gtk_widget_queue_resize(GTK_WIDGET(handle)); + + return 0; } static gboolean suil_cocoa_wrapper_idle(void* data) { - SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(data); - wrap->idle_iface->idle(wrap->instance->handle); - return TRUE; // Continue calling + SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(data); + wrap->idle_iface->idle(wrap->instance->handle); + return TRUE; // Continue calling } static GdkFilterReturn event_filter(GdkXEvent* xevent, GdkEvent* event, gpointer data) { - SuilCocoaWrapper* wrap = (SuilCocoaWrapper*)data; - if (!wrap->instance || !wrap->wrapper || !wrap->wrapper->impl) { - return GDK_FILTER_CONTINUE; - } - - NSEvent* nsevent = (NSEvent*)xevent; - NSView* view = (NSView*)wrap->instance->ui_widget; - if (view && nsevent) { - switch([nsevent type]) { - case NSEventTypeFlagsChanged: - [view flagsChanged:nsevent]; - return GDK_FILTER_REMOVE; - case NSEventTypeMouseEntered: - [view mouseEntered:nsevent]; - return GDK_FILTER_REMOVE; - case NSEventTypeMouseExited: - [view mouseExited:nsevent]; - return GDK_FILTER_REMOVE; - - /* Explicitly pass though mouse events. Needed for mouse-drags leaving - the window, and mouse-up after that. */ - case NSEventTypeMouseMoved: - [view mouseMoved:nsevent]; - break; - case NSEventTypeLeftMouseDragged: - [view mouseDragged:nsevent]; - break; - case NSEventTypeLeftMouseDown: - [view mouseDown:nsevent]; - break; - case NSEventTypeLeftMouseUp: - [view mouseUp:nsevent]; - break; - case NSEventTypeRightMouseDown: - [view rightMouseDown:nsevent]; - break; - case NSEventTypeRightMouseUp: - [view rightMouseUp:nsevent]; - break; - case NSEventTypeScrollWheel: - [view scrollWheel:nsevent]; - break; - default: - break; - } - } - return GDK_FILTER_CONTINUE; + SuilCocoaWrapper* wrap = (SuilCocoaWrapper*)data; + if (!wrap->instance || !wrap->wrapper || !wrap->wrapper->impl) { + return GDK_FILTER_CONTINUE; + } + + NSEvent* nsevent = (NSEvent*)xevent; + NSView* view = (NSView*)wrap->instance->ui_widget; + if (view && nsevent) { + switch ([nsevent type]) { + case NSEventTypeFlagsChanged: + [view flagsChanged:nsevent]; + return GDK_FILTER_REMOVE; + case NSEventTypeMouseEntered: + [view mouseEntered:nsevent]; + return GDK_FILTER_REMOVE; + case NSEventTypeMouseExited: + [view mouseExited:nsevent]; + return GDK_FILTER_REMOVE; + + /* Explicitly pass though mouse events. Needed for mouse-drags leaving + the window, and mouse-up after that. */ + case NSEventTypeMouseMoved: + [view mouseMoved:nsevent]; + break; + case NSEventTypeLeftMouseDragged: + [view mouseDragged:nsevent]; + break; + case NSEventTypeLeftMouseDown: + [view mouseDown:nsevent]; + break; + case NSEventTypeLeftMouseUp: + [view mouseUp:nsevent]; + break; + case NSEventTypeRightMouseDown: + [view rightMouseDown:nsevent]; + break; + case NSEventTypeRightMouseUp: + [view rightMouseUp:nsevent]; + break; + case NSEventTypeScrollWheel: + [view scrollWheel:nsevent]; + break; + default: + break; + } + } + return GDK_FILTER_CONTINUE; } static int wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) { - SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl); - - instance->host_widget = GTK_WIDGET(wrap); - wrap->wrapper = wrapper; - wrap->instance = instance; - - const LV2UI_Idle_Interface* idle_iface = NULL; - if (instance->descriptor->extension_data) { - idle_iface = (const LV2UI_Idle_Interface*) - instance->descriptor->extension_data(LV2_UI__idleInterface); - } - if (idle_iface) { - wrap->idle_iface = idle_iface; - wrap->idle_id = g_timeout_add( - wrap->idle_ms, suil_cocoa_wrapper_idle, wrap); - } - - return 0; + SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl); + + instance->host_widget = GTK_WIDGET(wrap); + wrap->wrapper = wrapper; + wrap->instance = instance; + + const LV2UI_Idle_Interface* idle_iface = NULL; + if (instance->descriptor->extension_data) { + idle_iface = + (const LV2UI_Idle_Interface*)instance->descriptor->extension_data( + LV2_UI__idleInterface); + } + + if (idle_iface) { + wrap->idle_iface = idle_iface; + wrap->idle_id = g_timeout_add(wrap->idle_ms, suil_cocoa_wrapper_idle, wrap); + } + + return 0; } static void wrapper_free(SuilWrapper* wrapper) { - if (wrapper->impl) { - SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl); - if (wrap->idle_id) { - g_source_remove(wrap->idle_id); - wrap->idle_id = 0; - } - - gdk_window_remove_filter(wrap->flt_win, event_filter, wrapper->impl); - gtk_object_destroy(GTK_OBJECT(wrap)); - } + if (wrapper->impl) { + SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl); + if (wrap->idle_id) { + g_source_remove(wrap->idle_id); + wrap->idle_id = 0; + } + + gdk_window_remove_filter(wrap->flt_win, event_filter, wrapper->impl); + gtk_object_destroy(GTK_OBJECT(wrap)); + } } - SUIL_LIB_EXPORT SuilWrapper* suil_wrapper_new(SuilHost* host, @@ -371,67 +379,66 @@ suil_wrapper_new(SuilHost* host, LV2_Feature*** features, unsigned n_features) { - GtkWidget* parent = NULL; - for (unsigned i = 0; i < n_features; ++i) { - if (!strcmp((*features)[i]->URI, LV2_UI__parent)) { - parent = (GtkWidget*)(*features)[i]->data; - } - } - - if (!GTK_CONTAINER(parent)) { - SUIL_ERRORF("No GtkContainer parent given for %s UI\n", - ui_type_uri); - return NULL; - } - - SuilWrapper* wrapper = (SuilWrapper*)calloc(1, sizeof(SuilWrapper)); - wrapper->wrap = wrapper_wrap; - wrapper->free = wrapper_free; - - SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER( - g_object_new(SUIL_TYPE_COCOA_WRAPPER, NULL)); - - wrapper->impl = wrap; - wrapper->resize.handle = wrap; - wrapper->resize.ui_resize = wrapper_resize; - - gtk_container_add(GTK_CONTAINER(parent), GTK_WIDGET(wrap)); - gtk_widget_set_can_focus(GTK_WIDGET(wrap), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(wrap), TRUE); - gtk_widget_realize(GTK_WIDGET(wrap)); - - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(wrap)); - wrap->flt_win = gtk_widget_get_window(parent); - gdk_window_add_filter(wrap->flt_win, event_filter, wrap); - - NSView* parent_view = gdk_quartz_window_get_nsview(window); - suil_add_feature(features, &n_features, LV2_UI__parent, parent_view); - suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize); - suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL); - - // Scan for URID map and options - LV2_URID_Map* map = NULL; - LV2_Options_Option* options = NULL; - for (LV2_Feature** f = *features; *f && (!map || !options); ++f) { - if (!strcmp((*f)->URI, LV2_OPTIONS__options)) { - options = (LV2_Options_Option*)(*f)->data; - } else if (!strcmp((*f)->URI, LV2_URID__map)) { - map = (LV2_URID_Map*)(*f)->data; - } - } - - if (map && options) { - // Set UI update rate if given - LV2_URID ui_updateRate = map->map(map->handle, LV2_UI__updateRate); - for (LV2_Options_Option* o = options; o->key; ++o) { - if (o->key == ui_updateRate) { - wrap->idle_ms = 1000.0f / *(const float*)o->value; - break; - } - } - } - - return wrapper; + GtkWidget* parent = NULL; + for (unsigned i = 0; i < n_features; ++i) { + if (!strcmp((*features)[i]->URI, LV2_UI__parent)) { + parent = (GtkWidget*)(*features)[i]->data; + } + } + + if (!GTK_CONTAINER(parent)) { + SUIL_ERRORF("No GtkContainer parent given for %s UI\n", ui_type_uri); + return NULL; + } + + SuilWrapper* wrapper = (SuilWrapper*)calloc(1, sizeof(SuilWrapper)); + wrapper->wrap = wrapper_wrap; + wrapper->free = wrapper_free; + + SuilCocoaWrapper* const wrap = + SUIL_COCOA_WRAPPER(g_object_new(SUIL_TYPE_COCOA_WRAPPER, NULL)); + + wrapper->impl = wrap; + wrapper->resize.handle = wrap; + wrapper->resize.ui_resize = wrapper_resize; + + gtk_container_add(GTK_CONTAINER(parent), GTK_WIDGET(wrap)); + gtk_widget_set_can_focus(GTK_WIDGET(wrap), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(wrap), TRUE); + gtk_widget_realize(GTK_WIDGET(wrap)); + + GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(wrap)); + wrap->flt_win = gtk_widget_get_window(parent); + gdk_window_add_filter(wrap->flt_win, event_filter, wrap); + + NSView* parent_view = gdk_quartz_window_get_nsview(window); + suil_add_feature(features, &n_features, LV2_UI__parent, parent_view); + suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize); + suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL); + + // Scan for URID map and options + LV2_URID_Map* map = NULL; + LV2_Options_Option* options = NULL; + for (LV2_Feature** f = *features; *f && (!map || !options); ++f) { + if (!strcmp((*f)->URI, LV2_OPTIONS__options)) { + options = (LV2_Options_Option*)(*f)->data; + } else if (!strcmp((*f)->URI, LV2_URID__map)) { + map = (LV2_URID_Map*)(*f)->data; + } + } + + if (map && options) { + // Set UI update rate if given + LV2_URID ui_updateRate = map->map(map->handle, LV2_UI__updateRate); + for (LV2_Options_Option* o = options; o->key; ++o) { + if (o->key == ui_updateRate) { + wrap->idle_ms = 1000.0f / *(const float*)o->value; + break; + } + } + } + + return wrapper; } -} // extern "C" +} // extern "C" |