osxvideosink: implement the navigation interface
authorAndoni Morales Alastruey <ylatuya@gmail.com>
Mon, 14 May 2012 12:27:58 +0000 (14:27 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 24 May 2012 12:35:21 +0000 (14:35 +0200)
sys/osxvideo/cocoawindow.h
sys/osxvideo/cocoawindow.m
sys/osxvideo/osxvideosink.m

index 7324cc7..7eec953 100644 (file)
@@ -29,6 +29,7 @@
 #import <Cocoa/Cocoa.h>
 #import <QuickTime/QuickTime.h>
 #import <glib.h>
+#import <gst/interfaces/navigation.h>
 
 struct _GstOSXImage;
 
@@ -44,6 +45,8 @@ struct _GstOSXImage;
     BOOL fullscreen;
     NSOpenGLContext* fullScreenContext; 
     NSOpenGLContext* actualContext;
+    NSTrackingArea *trackingArea;
+    GstNavigation *navigation;
 }
 - (void) drawQuad;
 - (void) drawRect: (NSRect) rect;
@@ -60,6 +63,7 @@ struct _GstOSXImage;
 - (void) haveSuperviewReal: (NSMutableArray *)closure;
 - (void) addToSuperview: (NSView *)superview;
 - (void) removeFromSuperview: (id)unused;
+- (void) setNavigation: (GstNavigation *) nav;
 
 @end
 
index ed24fad..b4f986a 100644 (file)
   [self setAcceptsMouseMovedEvents:YES];
 }
 
-- (void) sendEvent:(NSEvent *) event {
-  BOOL taken = NO;
-
-  GST_DEBUG ("event %p type:%d", event,(gint)[event type]);
-
-  if ([event type] == NSKeyDown) {
-  }
-  /*taken = [gstview keyDown:event]; */
-
-  if (!taken) {
-    [super sendEvent:event];
-  }
-}
-
-
 @end
 
 
 
   GST_LOG ("Width: %d Height: %d", width, height);
 
+  trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+      options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow)
+      owner:self
+      userInfo:nil];
+
+  [self addTrackingArea:trackingArea];
+
   [self initTextures];
   return self;
 }
 
   [super dealloc];
 }
+
+- (void)updateTrackingAreas {
+  [self removeTrackingArea:trackingArea];
+  [trackingArea release];
+  trackingArea = [[NSTrackingArea alloc] initWithRect: [self bounds]
+      options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow)
+      owner:self userInfo:nil];
+  [self addTrackingArea:trackingArea];
+}
+
+- (BOOL)acceptsFirstResponder {
+    return YES;
+}
+
+- (void) setNavigation:(GstNavigation *)nav
+{
+  navigation = nav;
+}
+
+- (void)sendMouseEvent:(NSEvent *)event: (const char *)event_name
+{
+  NSPoint location;
+  NSRect bounds;
+  gint button;
+  gint view_width, view_height;
+  gdouble x, y;
+
+  if (!navigation)
+    return;
+
+  switch ([event type]) {
+    case NSMouseMoved:
+      button = 0;
+      break;
+    case NSLeftMouseDown:
+    case NSLeftMouseUp:
+      button = 1;
+      break;
+    case NSRightMouseDown:
+    case NSRightMouseUp:
+      button = 2;
+      break;
+    default:
+      button = 3;
+      break;
+  }
+
+  location = [self convertPoint:[event locationInWindow] fromView:nil];
+
+  /* scale X and Y locations to the frame size */
+  bounds = [self bounds];
+  view_width = bounds.size.width;
+  view_height = bounds.size.height;
+
+  x = ((gdouble) location.x / view_width) * width;
+  y = ((gdouble) location.y / view_height) * height;
+
+  /* invert Y */
+  y = (1 - y / height) * height;
+
+  gst_navigation_send_mouse_event (navigation, event_name, button,
+      x, y);
+}
+
+- (void)sendKeyEvent:(NSEvent *)event: (const char *)event_name
+{
+  NSString *keyCharStr = [event charactersIgnoringModifiers];
+  gchar * key_str;
+
+  if (!navigation)
+    return;
+
+  if ( [keyCharStr length] == 0 )
+    return;
+
+  if ( [keyCharStr length] == 1 ) {
+    key_str = g_strdup_printf("%c", [keyCharStr characterAtIndex:0]);
+    gst_navigation_send_key_event(navigation, event_name, (const gchar *) key_str);
+    g_free(key_str);
+  }
+}
+
+- (void)keyDown:(NSEvent *) event;
+{
+  [self sendKeyEvent: event: "key-press"];
+}
+
+- (void)keyUp:(NSEvent *) event;
+{
+  [self sendKeyEvent: event: "key-release"];
+}
+
+- (void)mouseDown:(NSEvent *) event;
+{
+  [self sendMouseEvent:event: "mouse-button-press"];
+}
+
+- (void)mouseUp:(NSEvent *) event;
+{
+  [self sendMouseEvent:event: "mouse-button-release"];
+}
+
+- (void)mouseMoved:(NSEvent *)event;
+{
+  [self sendMouseEvent:event: "mouse-move"];
+}
+
+- (void)mouseEntered:(NSEvent *)event;
+{
+}
+
+- (void)mouseExited:(NSEvent *)event;
+{
+}
+
 @end
index 312316a..c4a8467 100644 (file)
@@ -148,6 +148,7 @@ gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width,
       GST_INFO_OBJECT (osxvideosink, "no superview");
     }
   }
+  [osxwindow->gstview setNavigation: GST_NAVIGATION(osxvideosink)];
 
   [pool release];
 
@@ -416,7 +417,7 @@ gst_osx_video_sink_class_init (GstOSXVideoSinkClass * klass)
 static gboolean
 gst_osx_video_sink_interface_supported (GstImplementsInterface * iface, GType type)
 {
-  g_assert (type == GST_TYPE_X_OVERLAY);
+  g_assert (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_NAVIGATION);
   return TRUE;
 }
 
@@ -427,6 +428,72 @@ gst_osx_video_sink_interface_init (GstImplementsInterfaceClass * klass)
 }
 
 static void
+gst_osx_video_sink_navigation_send_event (GstNavigation * navigation,
+    GstStructure * structure)
+{
+  GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (navigation);
+  GstPad *peer;
+  GstEvent *event;
+  GstVideoRectangle src, dst, result;
+  gdouble x, y, xscale = 1.0, yscale = 1.0;
+
+  peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (osxvideosink));
+
+  if (!peer || !osxvideosink->osxwindow)
+    return;
+
+  event = gst_event_new_navigation (structure);
+
+  /* FIXME: Use this when this sink is capable of keeping the display
+   * aspect ratio */
+  if (0) { //(osxvideosink->keep_aspect) {
+    /* We get the frame position using the calculated geometry from _setcaps
+       that respect pixel aspect ratios */
+    src.w = GST_VIDEO_SINK_WIDTH (osxvideosink);
+    src.h = GST_VIDEO_SINK_HEIGHT (osxvideosink);
+    //dst.w = osxvideosink->osxwindow->gstview->width;
+    //dst.w = osxvideosink->osxwindow->gstview->height;
+
+    gst_video_sink_center_rect (src, dst, &result, TRUE);
+    //result.x += osxvideosink->gstview->x;
+    //result.y += osxvideosink->gstview->y;
+  } else {
+    result.x = 0;
+    result.y = 0;
+    result.w = osxvideosink->osxwindow->width;
+    result.h = osxvideosink->osxwindow->height;
+  }
+
+  /* We calculate scaling using the original video frames geometry to include
+     pixel aspect ratio scaling. */
+  xscale = (gdouble) osxvideosink->osxwindow->width / result.w;
+  yscale = (gdouble) osxvideosink->osxwindow->height / result.h;
+
+  /* Converting pointer coordinates to the non scaled geometry */
+  if (gst_structure_get_double (structure, "pointer_x", &x)) {
+    x = MIN (x, result.x + result.w);
+    x = MAX (x - result.x, 0);
+    gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
+        (gdouble) x * xscale, NULL);
+  }
+  if (gst_structure_get_double (structure, "pointer_y", &y)) {
+    y = MIN (y, result.y + result.h);
+    y = MAX (y - result.y, 0);
+    gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
+        (gdouble) y * yscale, NULL);
+  }
+
+  gst_pad_send_event (peer, event);
+  gst_object_unref (peer);
+}
+
+static void
+gst_osx_video_sink_navigation_init (GstNavigationInterface * iface)
+{
+  iface->send_event = gst_osx_video_sink_navigation_send_event;
+}
+
+static void
 gst_osx_video_sink_set_window_handle (GstXOverlay * overlay, guintptr handle_id)
 {
   GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (overlay);
@@ -500,6 +567,11 @@ gst_osx_video_sink_get_type (void)
       NULL,
     };
 
+    static const GInterfaceInfo navigation_info = {
+      (GInterfaceInitFunc) gst_osx_video_sink_navigation_init,
+      NULL,
+      NULL,
+    };
     osxvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
         "GstOSXVideoSink", &osxvideosink_info, 0);