[evince] libview: Add support for showing videos in EvView
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evince] libview: Add support for showing videos in EvView
- Date: Wed, 27 May 2015 13:10:21 +0000 (UTC)
commit 48da13c35dd864713b053ce84de1420735379184
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Wed May 27 13:00:47 2015 +0200
libview: Add support for showing videos in EvView
libview/ev-view.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 231 insertions(+), 1 deletions(-)
---
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 64f4027..d3f8469 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -46,6 +46,17 @@
#include "ev-view-type-builtins.h"
#include "ev-debug.h"
+#ifdef ENABLE_MULTIMEDIA
+#if defined (GDK_WINDOWING_X11)
+#include <gdk/gdkx.h>
+#elif defined (GDK_WINDOWING_WIN32)
+#include <gdk/gdkwin32.h>
+#endif
+
+#include "ev-media-player.h"
+#include "ev-media-controls.h"
+#endif
+
enum {
SIGNAL_SCROLL,
SIGNAL_HANDLE_LINK,
@@ -139,7 +150,10 @@ static char* tip_from_link (EvView
static EvFormField *ev_view_get_form_field_at_location (EvView *view,
gdouble x,
gdouble y);
-
+/*** Media ***/
+static EvMedia *ev_view_get_media_at_location (EvView *view,
+ gdouble x,
+ gdouble y);
/*** Annotations ***/
static EvAnnotation *ev_view_get_annotation_at_location (EvView *view,
gdouble x,
@@ -2080,6 +2094,7 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
EvLink *link;
EvFormField *field;
EvAnnotation *annot = NULL;
+ EvMedia *media;
if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
return;
@@ -2116,6 +2131,11 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
} else {
ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
}
+ } else if ((media = ev_view_get_media_at_location (view, x, y))) {
+ if (!g_object_get_data (G_OBJECT (media), "view-player"))
+ ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
+ else
+ ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
} else if ((annot = ev_view_get_annotation_at_location (view, x, y))) {
ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
} else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
@@ -2760,6 +2780,193 @@ ev_view_handle_form_field (EvView *view,
}
+/* Media */
+static EvMapping *
+get_media_mapping_at_location (EvView *view,
+ gdouble x,
+ gdouble y,
+ gint *page)
+{
+#ifdef ENABLE_MULTIMEDIA
+ gint x_new = 0, y_new = 0;
+ EvMappingList *media_mapping;
+
+ if (!EV_IS_DOCUMENT_MEDIA (view->document))
+ return NULL;
+
+ if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
+ return NULL;
+
+ media_mapping = ev_page_cache_get_media_mapping (view->page_cache, *page);
+
+ return media_mapping ? ev_mapping_list_get (media_mapping, x_new, y_new) : NULL;
+#else
+ return NULL;
+#endif
+}
+
+static EvMedia *
+ev_view_get_media_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvMapping *media_mapping;
+ gint page;
+
+ media_mapping = get_media_mapping_at_location (view, x, y, &page);
+
+ return media_mapping ? media_mapping->data : NULL;
+}
+
+#ifdef ENABLE_MULTIMEDIA
+static void
+media_player_state_changed (EvMediaPlayer *player,
+ guint state,
+ EvMedia *media)
+{
+ /* A media without controls can't be played again */
+ if (state == EV_MEDIA_PLAYER_STATE_PAUSE)
+ g_object_set_data (G_OBJECT (media), "view-player", NULL);
+}
+#endif
+
+static void
+ev_view_handle_media (EvView *view,
+ EvMedia *media)
+{
+#ifdef ENABLE_MULTIMEDIA
+ EvMediaPlayer *player;
+ EvMappingList *media_mapping;
+ GdkRectangle render_area;
+ guint page;
+ guint64 window_handle;
+
+ page = ev_media_get_page_index (media);
+ media_mapping = ev_page_cache_get_media_mapping (view->page_cache, page);
+
+ /* TODO: focus? */
+
+ player = g_object_get_data (G_OBJECT (media), "view-player");
+ if (player)
+ return;
+
+#if defined (GDK_WINDOWING_X11)
+ window_handle = (guint64)GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (view)));
+#elif defined (GDK_WINDOWING_WIN32)
+ window_handle = (guint64)GDK_WINDOW_HWND (gtk_widget_get_window (GTK_WIDGET (view)));
+#else
+ g_assert_not_reached ();
+#endif
+
+ ev_view_get_area_from_mapping (view, page, media_mapping, media, &render_area);
+ player = ev_media_player_new (media, window_handle, &render_area);
+ g_object_set_data_full (G_OBJECT (media), "view-player", player, g_object_unref);
+
+ if (ev_media_get_show_controls (media)) {
+ GtkWidget *controls;
+ EvMapping *mapping;
+ EvRectangle doc_rect;
+
+ mapping = ev_mapping_list_find (media_mapping, media);
+ doc_rect.x1 = mapping->area.x1;
+ doc_rect.x2 = mapping->area.x2;
+ doc_rect.y1 = mapping->area.y2;
+ doc_rect.y2 = doc_rect.y1 + 16;
+
+ controls = ev_media_controls_new (player);
+ ev_view_put (view, controls,
+ render_area.x,
+ render_area.y + render_area.height,
+ page, &doc_rect);
+ gtk_widget_show (controls);
+ } else {
+ /* A media without controls will be paused when reaching EOS */
+ g_signal_connect (player, "state-changed",
+ G_CALLBACK (media_player_state_changed),
+ media);
+ }
+#endif /* ENABLE_MULTIMEDIA */
+}
+
+static void
+ev_view_update_media_render_area (EvView *view)
+{
+#ifdef ENABLE_MULTIMEDIA
+ guint i;
+
+ for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
+ EvMappingList *media_mapping;
+ GList *l;
+
+ media_mapping = ev_page_cache_get_media_mapping (view->page_cache, i);
+ if (!media_mapping)
+ continue;
+
+ for (l = ev_mapping_list_get_list (media_mapping); l; l = g_list_next (l)) {
+ EvMapping *mapping = (EvMapping *)l->data;
+ EvMedia *media = (EvMedia *)mapping->data;
+ EvMediaPlayer *player;
+ GdkRectangle render_area;
+
+ player = g_object_get_data (G_OBJECT (media), "view-player");
+ if (!player)
+ continue;
+
+ _ev_view_transform_doc_rect_to_view_rect (view, i,
+ &mapping->area,
+ &render_area);
+ render_area.x -= view->scroll_x;
+ render_area.y -= view->scroll_y;
+ ev_media_player_set_render_area (player, &render_area);
+ }
+ }
+#endif
+}
+
+#ifdef ENABLE_MULTIMEDIA
+static void
+draw_media (EvView *view,
+ cairo_t *cr,
+ gint page,
+ GdkRectangle *clip)
+{
+ EvMappingList *media_mapping;
+ GList *l;
+
+ media_mapping = ev_page_cache_get_media_mapping (view->page_cache, page);
+
+ for (l = ev_mapping_list_get_list (media_mapping); l; l = g_list_next (l)) {
+ EvMapping *mapping = (EvMapping *)l->data;
+ EvMediaPlayer *player;
+ GdkRectangle media_rect;
+ GdkRectangle intersect;
+
+ player = g_object_get_data (G_OBJECT (mapping->data), "view-player");
+ if (!player)
+ continue;
+
+ _ev_view_transform_doc_rect_to_view_rect (view, page,
+ &mapping->area,
+ &media_rect);
+ media_rect.x -= view->scroll_x;
+ media_rect.y -= view->scroll_y;
+
+ /* Draw a black background to avoid showing the builtin poster */
+ if (gdk_rectangle_intersect (&media_rect, clip, &intersect)) {
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_rectangle (cr,
+ intersect.x, intersect.y,
+ intersect.width, intersect.height);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ ev_media_player_expose (player);
+ }
+ }
+}
+#endif
+
/* Annotations */
static EvViewWindowChild *
ev_view_get_window_child (EvView *view,
@@ -3987,6 +4194,8 @@ ev_view_size_allocate (GtkWidget *widget,
ev_view_window_child_move (view, child, view_rect.x + root_x, view_rect.y + root_y);
}
}
+
+ ev_view_update_media_render_area (view);
}
static gboolean
@@ -4454,6 +4663,10 @@ ev_view_draw (GtkWidget *widget,
draw_focus (view, cr, i, &clip_rect);
if (page_ready && view->synctex_result)
highlight_forward_search_results (view, cr, i);
+#ifdef ENABLE_MULTIMEDIA
+ if (page_ready && EV_IS_DOCUMENT_MEDIA (view->document))
+ draw_media (view, cr, i, &clip_rect);
+#endif
#ifdef EV_ENABLE_DEBUG
if (page_ready)
draw_debug_borders (view, cr, i, &clip_rect);
@@ -4849,6 +5062,7 @@ ev_view_button_press_event (GtkWidget *widget,
EvAnnotation *annot;
EvFormField *field;
EvMapping *link;
+ EvMedia *media;
gint page;
if (event->state & GDK_CONTROL_MASK)
@@ -4874,6 +5088,8 @@ ev_view_button_press_event (GtkWidget *widget,
ev_view_pend_cursor_blink (view);
}
}
+ } else if ((media = ev_view_get_media_at_location (view, event->x, event->y))) {
+ ev_view_handle_media (view, media);
} else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) {
ev_view_handle_annotation (view, annot, event->x, event->y, event->time);
} else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
@@ -7244,6 +7460,9 @@ static void
ev_view_init (EvView *view)
{
GtkStyleContext *context;
+#if defined (ENABLE_MULTIMEDIA) && defined (GDK_WINDOWING_X11)
+ GdkVisual *visual;
+#endif
gtk_widget_set_has_window (GTK_WIDGET (view), TRUE);
gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE);
@@ -7254,6 +7473,15 @@ ev_view_init (EvView *view)
gtk_style_context_add_class (context, "content-view");
gtk_style_context_add_class (context, "view");
+#if defined (ENABLE_MULTIMEDIA) && defined (GDK_WINDOWING_X11)
+ /* Use always the system visual, instead of the one inherited from the
+ * window, because gst xvimagesink doesn't work with RGBA visuals.
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=721148
+ */
+ visual = gdk_screen_get_system_visual (gdk_screen_get_default ());
+ gtk_widget_set_visual (GTK_WIDGET (view), visual);
+#endif
+
gtk_widget_set_events (GTK_WIDGET (view),
GDK_TOUCH_MASK |
GDK_EXPOSURE_MASK |
@@ -7411,6 +7639,8 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
if (view->document)
view_update_range_and_current_page (view);
+
+ ev_view_update_media_render_area (view);
}
GtkWidget*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]